Skip to content

Commit ae4fdac

Browse files
authored
Merge pull request #22 from topolarity/ct/no-eval-pref
Add Preference to disable runtime invalidation
2 parents fc95ee7 + bddfae2 commit ae4fdac

File tree

7 files changed

+104
-22
lines changed

7 files changed

+104
-22
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
fail-fast: false
1111
matrix:
1212
version:
13-
- '1.5'
13+
- '1.10'
1414
- '1'
1515
- 'nightly'
1616
os:

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ version = "0.1.17"
77
BitTwiddlingConvenienceFunctions = "62783981-4cbd-42fc-bca8-16325de8dc4b"
88
IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
99
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
10+
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
1011
Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
1112

1213
[compat]
1314
BitTwiddlingConvenienceFunctions = "0.1"
1415
IfElse = "0.1"
1516
Static = "0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1"
16-
julia = "1.5"
17+
julia = "1.10"
1718

1819
[extras]
1920
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

docs/src/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ Documentation for [HostCPUFeatures](https://github.com/JuliaSIMD/HostCPUFeatures
1212
```@autodocs
1313
Modules = [HostCPUFeatures]
1414
```
15+
16+
## Supported Preferences
17+
18+
- `cpu_target`: if provided, use this string as your CPU target for feature detection instead of `JULIA_CPU_TARGET`
19+
- `freeze_cpu_target`: if `true`, "freeze" the features detected based on your precompile-time CPU target and do not perform runtime feature detection
20+
- `allow_runtime_invalidation`: if `false`, warn when performing runtime feature detection (instead of invalidating) when CPU features don't match precompile-time

src/HostCPUFeatures.jl

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,32 @@ end
77
using Libdl, Static
88
using Static: Zero, One, lt, gt
99
using IfElse: ifelse
10+
using Preferences
1011

1112
using BitTwiddlingConvenienceFunctions: prevpow2, nextpow2, intlog2
1213

1314
export has_feature, fma_fast, pick_vector_width, pick_vector_width_shift, register_count,
1415
register_size, simd_integer_register_size
1516

17+
_cpu_target = if @has_preference("cpu_target")
18+
@load_preference("cpu_target")
19+
else
20+
Base.unsafe_string(Base.JLOptions().cpu_target)
21+
end
22+
23+
const build_cpu_target = if occursin("native", _cpu_target)
24+
"native" # 'native' takes priority if provided
25+
else
26+
split(_cpu_target, ";")[1]
27+
end
28+
29+
# If true, this will opt-in to "freeze" an under-approximation of the CPU features at precompile-
30+
# time based on the CPU target.
31+
#
32+
# This is only done by default if "native" was excluded from the CPU target (or via a preference).
33+
const freeze_cpu_target =
34+
@load_preference("freeze_cpu_target", false) || build_cpu_target != "native"
35+
1636
function get_cpu_name()::String
1737
if isdefined(Sys, :CPU_NAME)
1838
Sys.CPU_NAME
@@ -37,19 +57,43 @@ unwrap(::StaticSymbol{S}) where {S} = S
3757

3858
@noinline function redefine()
3959
@debug "Defining CPU name."
40-
define_cpu_name()
60+
redefine_cpu_name()
4161

4262
reset_features!()
4363
reset_extra_features!()
4464
end
4565
const BASELINE_CPU_NAME = get_cpu_name()
66+
const allow_eval = @load_preference("allow_runtime_invalidation", false)
67+
68+
function make_generic(target)
69+
target == "native" && return false
70+
if Sys.ARCH === :x86_64 || Sys.ARCH === :i686
71+
make_generic_x86(target)
72+
return true
73+
else
74+
return false
75+
end
76+
end
77+
78+
make_generic(build_cpu_target)
79+
4680
function __init__()
4781
ccall(:jl_generating_output, Cint, ()) == 1 && return
48-
if Sys.ARCH === :x86_64 || Sys.ARCH === :i686
49-
target = Base.unsafe_string(Base.JLOptions().cpu_target)
50-
occursin("native", target) || return make_generic(target)
82+
freeze_cpu_target && return # CPU info fixed at precompile-time
83+
84+
runtime_target = Base.unsafe_string(Base.JLOptions().cpu_target)
85+
if !occursin("native", runtime_target)
86+
# The CPU target included "native" at pre-compile time, but at runtime it did not!
87+
#
88+
# Fixing this discepancy will invalidate the whole world (so it should probably
89+
# throw an error), but we do it anyway for backwards-compatibility.
90+
if make_generic(runtime_target)
91+
return nothing
92+
end
93+
end
94+
if BASELINE_CPU_NAME != Sys.CPU_NAME::String
95+
redefine()
5196
end
52-
BASELINE_CPU_NAME == Sys.CPU_NAME::String || redefine()
5397
return nothing
5498
end
5599

src/cpu_info.jl

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,22 @@ function set_features!()
3939
end
4040
Libc.free(features_cstring)
4141
end
42-
set_features!()
43-
4442

43+
if build_cpu_target == "native"
44+
set_features!()
45+
end
4546

4647
function reset_features!()
4748
features, features_cstring = feature_string()
4849
for ext features
4950
feature, has = process_feature(ext)
5051
if _has_feature(feature) has
51-
@debug "Defining $(has ? "presence" : "absense") of feature $feature."
52-
set_feature(feature, has)
52+
if allow_eval
53+
@debug "Defining $(has ? "presence" : "absense") of feature $feature."
54+
set_feature(feature, has)
55+
else
56+
@warn "Runtime invalidation was disabled, but the CPU info is out-of-date.\nWill continue with incorrect CPU feature flag: $ext."
57+
end
5358
end
5459
end
5560
Libc.free(features_cstring)
@@ -58,8 +63,16 @@ end
5863
register_size(::Type{T}) where {T} = register_size()
5964
register_size(::Type{T}) where {T<:Union{Signed,Unsigned}} = simd_integer_register_size()
6065

61-
function define_cpu_name()
66+
function redefine_cpu_name()
6267
cpu = QuoteNode(Symbol(get_cpu_name()))
63-
@eval cpu_name() = Val{$cpu}()
68+
if allow_eval
69+
@eval cpu_name() = Val{$cpu}()
70+
else
71+
@warn "Runtime invalidation was disabled, but the CPU info is out-of-date.\nWill continue with incorrect CPU name (from build time)."
72+
end
73+
end
74+
75+
let _cpu = QuoteNode(Symbol(build_cpu_target == "native" ?
76+
get_cpu_name() : build_cpu_target))
77+
@eval cpu_name() = Val{$_cpu}()
6478
end
65-
define_cpu_name()

src/cpu_info_aarch64.jl

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function _set_sve_vector_width!(bytes = _dynamic_register_size())
2828
end
2929

3030

31-
if _has_aarch64_sve()# && !(Bool(has_feature(Val(:aarch64_sve))))
31+
if build_cpu_target == "native" && _has_aarch64_sve()# && !(Bool(has_feature(Val(:aarch64_sve))))
3232
has_feature(::Val{:aarch64_sve_cpuid}) = True()
3333
_set_sve_vector_width!()
3434
else
@@ -39,10 +39,20 @@ end
3939

4040
function reset_extra_features!()
4141
drs = _dynamic_register_size()
42-
register_size() drs && _set_sve_vector_width!(drs)
42+
if register_size() drs
43+
if allow_eval
44+
_set_sve_vector_width!(drs)
45+
else
46+
@warn "Runtime invalidation was disabled, but the CPU info is out-of-date.\nWill continue with incorrect CPU register size."
47+
end
48+
end
4349
hassve = _has_aarch64_sve()
4450
if hassve has_feature(Val(:aarch64_sve_cpuid))
45-
@eval has_feature(::Val{:aarch64_sve_cpuid}) = $(Expr(:call, hassve ? :True : :False))
51+
if allow_eval
52+
@eval has_feature(::Val{:aarch64_sve_cpuid}) = $(Expr(:call, hassve ? :True : :False))
53+
else
54+
@warn "Runtime invalidation was disabled, but the CPU info is out-of-date.\nWill continue with incorrect CPU feature flag: :aarch64_sve_cpuid."
55+
end
4656
end
4757
end
4858

src/cpu_info_x86.jl

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,26 @@ fast_int64_to_double() = has_feature(Val(:x86_64_avx512dq))
3232

3333
fast_half() = False()
3434

35-
@noinline function setfeaturefalse(s)
35+
@inline function setfeaturefalse(s)
3636
if has_feature(Val(s)) === True()
37-
@eval has_feature(::Val{$(QuoteNode(s))}) = False()
37+
if allow_eval
38+
@eval has_feature(::Val{$(QuoteNode(s))}) = False()
39+
else
40+
@warn "Runtime invalidation was disabled, but the CPU info is out-of-date.\nWill continue with incorrect CPU feature flag: $s."
41+
end
3842
end
3943
end
40-
@noinline function setfeaturetrue(s)
44+
@inline function setfeaturetrue(s)
4145
if has_feature(Val(s)) === False()
42-
@eval has_feature(::Val{$(QuoteNode(s))}) = True()
46+
if allow_eval
47+
@eval has_feature(::Val{$(QuoteNode(s))}) = True()
48+
else
49+
@warn "Runtime invalidation was disabled, but the CPU info is out-of-date.\nWill continue with incorrect CPU feature flag: $s."
50+
end
4351
end
4452
end
4553

46-
function make_generic(target)
54+
function make_generic_x86(target)
4755
if occursin("tigerlake", target) || occursin("znver4", target) || occursin("sapphirerapids", target)
4856
# most feature-complete architectures we use
4957
setfeaturetrue(:x86_64_avx512ifma)

0 commit comments

Comments
 (0)