Skip to content

Commit 3b29187

Browse files
Add 'sysimage' keyword for JULIA_CPU_TARGET to match (or extend) the sysimage target (#58970)
1 parent e4755de commit 3b29187

File tree

10 files changed

+105
-8
lines changed

10 files changed

+105
-8
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Command-line option changes
2626
---------------------------
2727

2828
* The option `--sysimage-native-code=no` has been deprecated.
29+
* The `JULIA_CPU_TARGET` environment variable now supports a `sysimage` keyword to match (or extend) the CPU target used to build the current system image ([#58970]).
2930

3031
Multi-threading changes
3132
-----------------------
@@ -47,6 +48,7 @@ New library functions
4748
* `ispositive(::Real)` and `isnegative(::Real)` are provided for performance and convenience ([#53677]).
4849
* Exporting function `fieldindex` to get the index of a struct's field ([#58119]).
4950
* `Base.donotdelete` is now public. It prevents deadcode elemination of its arguments ([#55774]).
51+
* `Sys.sysimage_target()` returns the CPU target string used to build the current system image ([#58970]).
5052

5153
New library features
5254
--------------------

base/sysinfo.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export BINDIR,
1616
JIT,
1717
cpu_info,
1818
cpu_summary,
19+
sysimage_target,
1920
uptime,
2021
loadavg,
2122
free_memory,
@@ -312,6 +313,23 @@ function cpu_info()
312313
return cpus
313314
end
314315

316+
"""
317+
Sys.sysimage_target()
318+
319+
Return the CPU target string that was used to build the current system image.
320+
321+
This function returns the original CPU target specification that was passed to Julia
322+
when the system image was compiled. This can be useful for reproducing the same
323+
system image or for understanding what CPU features were enabled during compilation.
324+
325+
If the system image was built with the default settings this will return `"native"`.
326+
327+
See also [`JULIA_CPU_TARGET`](@ref).
328+
"""
329+
function sysimage_target()
330+
return ccall(:jl_get_sysimage_cpu_target, Ref{String}, ())
331+
end
332+
315333
"""
316334
Sys.uptime()
317335

doc/src/base/base.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ Base.Sys.total_memory
397397
Base.Sys.free_physical_memory
398398
Base.Sys.total_physical_memory
399399
Base.Sys.uptime
400+
Base.Sys.sysimage_target
400401
Base.Sys.isjsvm
401402
Base.Sys.loadavg
402403
Base.Sys.isexecutable

doc/src/manual/environment-variables.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -479,9 +479,15 @@ stored in memory.
479479

480480
Valid values for [`JULIA_CPU_TARGET`](@ref JULIA_CPU_TARGET) can be obtained by executing `julia -C help`.
481481

482+
To get the CPU target string that was used to build the current system image,
483+
use [`Sys.sysimage_target()`](@ref). This can be useful for reproducing
484+
the same system image or understanding what CPU features were enabled during compilation.
485+
482486
Setting [`JULIA_CPU_TARGET`](@ref JULIA_CPU_TARGET) is important for heterogeneous compute systems where processors of
483487
distinct types or features may be present. This is commonly encountered in high performance
484-
computing (HPC) clusters since the component nodes may be using distinct processors.
488+
computing (HPC) clusters since the component nodes may be using distinct processors. In this case,
489+
you may want to use the `sysimage` CPU target to maintain the same configuration as the sysimage.
490+
See below for more details.
485491

486492
The CPU target string is a list of strings separated by `;` each string starts with a CPU
487493
or architecture name and followed by an optional list of features separated by `,`.
@@ -490,25 +496,33 @@ which is at least the architecture the C/C++ runtime is compiled with. Each stri
490496
is interpreted by LLVM.
491497

492498
A few special features are supported:
493-
1. `clone_all`
499+
500+
1. `sysimage`
501+
502+
A special keyword that can be used as a CPU target name, which will be replaced
503+
with the CPU target string that was used to build the current system image. This allows
504+
you to specify CPU targets that build upon or extend the current sysimage's target, which
505+
is particularly helpful for creating package images that are as flexible as the sysimage.
506+
507+
2. `clone_all`
494508

495509
This forces the target to have all functions in sysimg cloned.
496510
When used in negative form (i.e. `-clone_all`), this disables full clone that's
497511
enabled by default for certain targets.
498512

499-
2. `base([0-9]*)`
513+
3. `base([0-9]*)`
500514

501515
This specifies the (0-based) base target index. The base target is the target
502516
that the current target is based on, i.e. the functions that are not being cloned
503517
will use the version in the base target. This option causes the base target to be
504518
fully cloned (as if `clone_all` is specified for it) if it is not the default target (0).
505519
The index can only be smaller than the current index.
506520

507-
3. `opt_size`
521+
4. `opt_size`
508522

509523
Optimize for size with minimum performance impact. Clang/GCC's `-Os`.
510524

511-
4. `min_size`
525+
5. `min_size`
512526

513527
Optimize only for size. Clang's `-Oz`.
514528

pkgimage.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ print-depot-path:
2626
@$(call PRINT_JULIA, $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e '@show Base.DEPOT_PATH')
2727

2828
$(BUILDDIR)/stdlib/%.image: $(JULIAHOME)/stdlib/Project.toml $(JULIAHOME)/stdlib/Manifest.toml $(INDEPENDENT_STDLIBS_SRCS) $(DEPOTDIR)/compiled
29-
@$(call PRINT_JULIA, JULIA_CPU_TARGET="$(JULIA_CPU_TARGET)" $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e \
29+
@$(call PRINT_JULIA, JULIA_CPU_TARGET="sysimage" $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e \
3030
'Base.Precompilation.precompilepkgs(configs=[``=>Base.CacheFlags(debug_level=2, opt_level=3), ``=>Base.CacheFlags(check_bounds=1, debug_level=2, opt_level=3)])')
3131
touch $@
3232

src/aotcompile.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2344,15 +2344,24 @@ void jl_dump_native_impl(void *native_code,
23442344
"jl_small_typeof");
23452345
jl_small_typeof_copy->setVisibility(GlobalValue::HiddenVisibility);
23462346
jl_small_typeof_copy->setDSOLocal(true);
2347-
AT = ArrayType::get(T_psize, 5);
2347+
2348+
// Create CPU target string constant
2349+
auto cpu_target_str = jl_options.cpu_target ? jl_options.cpu_target : "native";
2350+
auto cpu_target_data = ConstantDataArray::getString(Context, cpu_target_str, true);
2351+
auto cpu_target_global = new GlobalVariable(metadataM, cpu_target_data->getType(), true,
2352+
GlobalVariable::InternalLinkage,
2353+
cpu_target_data, "jl_cpu_target_string");
2354+
2355+
AT = ArrayType::get(T_psize, 6);
23482356
auto pointers = new GlobalVariable(metadataM, AT, false,
23492357
GlobalVariable::ExternalLinkage,
23502358
ConstantArray::get(AT, {
23512359
ConstantExpr::getBitCast(header, T_psize),
23522360
ConstantExpr::getBitCast(shards, T_psize),
23532361
ConstantExpr::getBitCast(ptls, T_psize),
23542362
ConstantExpr::getBitCast(jl_small_typeof_copy, T_psize),
2355-
ConstantExpr::getBitCast(target_ids, T_psize)
2363+
ConstantExpr::getBitCast(target_ids, T_psize),
2364+
ConstantExpr::getBitCast(cpu_target_global, T_psize)
23562365
}),
23572366
"jl_image_pointers");
23582367
addComdat(pointers, TheTriple);

src/jl_exported_funcs.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
XX(jl_check_binding_currently_writable) \
191191
XX(jl_get_cpu_name) \
192192
XX(jl_get_cpu_features) \
193+
XX(jl_get_sysimage_cpu_target) \
193194
XX(jl_cpu_has_fma) \
194195
XX(jl_get_current_task) \
195196
XX(jl_get_default_sysimg_path) \

src/processor.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,20 @@ parse_cmdline(const char *option, F &&feature_cb)
506506
if (!option)
507507
abort();
508508

509+
// Preprocess the option string to expand "sysimage" keyword
510+
std::string processed_option;
511+
if (strncmp(option, "sysimage", 8) == 0 && (option[8] == '\0' || option[8] == ';')) {
512+
// Replace "sysimage" with the actual sysimage CPU target
513+
jl_value_t *target_str = jl_get_sysimage_cpu_target();
514+
if (target_str != nullptr) {
515+
processed_option = std::string(jl_string_data(target_str), jl_string_len(target_str));
516+
if (option[8] == ';') {
517+
processed_option += option + 8; // append the rest after "sysimage"
518+
}
519+
option = processed_option.c_str();
520+
}
521+
}
522+
509523
llvm::SmallVector<TargetData<n>, 0> res;
510524
TargetData<n> arg{};
511525
auto reset_arg = [&] {
@@ -633,6 +647,12 @@ static inline jl_image_t parse_sysimg(jl_image_buf_t image, F &&callback, void *
633647

634648
const jl_image_pointers_t *pointers = (const jl_image_pointers_t *)image.pointers;
635649
const void *ids = pointers->target_data;
650+
651+
// Set the sysimage CPU target from the stored string
652+
if (pointers->cpu_target_string) {
653+
jl_set_sysimage_cpu_target(pointers->cpu_target_string);
654+
}
655+
636656
jl_value_t* rejection_reason = nullptr;
637657
JL_GC_PUSH1(&rejection_reason);
638658
uint32_t target_idx = callback(ctx, ids, &rejection_reason);
@@ -1002,6 +1022,9 @@ static std::string jl_get_cpu_features_llvm(void)
10021022

10031023
#endif
10041024

1025+
// Global variable to store the CPU target string used for the sysimage
1026+
static std::string sysimage_cpu_target;
1027+
10051028
JL_DLLEXPORT jl_value_t *jl_get_cpu_name(void)
10061029
{
10071030
return jl_cstr_to_string(host_cpu_name().c_str());
@@ -1038,3 +1061,17 @@ extern "C" JL_DLLEXPORT void jl_reflect_feature_names(const FeatureName **fnames
10381061
*fnames = feature_names;
10391062
*nf = nfeature_names;
10401063
}
1064+
1065+
extern "C" JL_DLLEXPORT jl_value_t *jl_get_sysimage_cpu_target(void) {
1066+
if (sysimage_cpu_target.empty()) {
1067+
return jl_cstr_to_string("native");
1068+
}
1069+
return jl_cstr_to_string(sysimage_cpu_target.c_str());
1070+
}
1071+
1072+
// Function to set the sysimage CPU target (called during initialization)
1073+
void jl_set_sysimage_cpu_target(const char *cpu_target) {
1074+
if (cpu_target) {
1075+
sysimage_cpu_target = cpu_target;
1076+
}
1077+
}

src/processor.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ typedef struct {
195195
// This contains the number of targets
196196
// in addition to the name and feature set of each target.
197197
const void *target_data;
198+
// Original CPU target string used to build this sysimage
199+
const char *cpu_target_string;
198200
} jl_image_pointers_t;
199201

200202
/**
@@ -210,10 +212,15 @@ typedef struct {
210212
jl_image_t jl_init_processor_sysimg(jl_image_buf_t image, const char *cpu_target);
211213
jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image);
212214

215+
// Internal function to set the sysimage CPU target during initialization
216+
void jl_set_sysimage_cpu_target(const char *cpu_target);
217+
213218
// Return the name of the host CPU as a julia string.
214219
JL_DLLEXPORT jl_value_t *jl_get_cpu_name(void);
215220
// Return the features of the host CPU as a julia string.
216221
JL_DLLEXPORT jl_value_t *jl_get_cpu_features(void);
222+
// Return the CPU target string used to build the current sysimage
223+
JL_DLLEXPORT jl_value_t *jl_get_sysimage_cpu_target(void);
217224
// Dump the name and feature set of the host CPU
218225
JL_DLLEXPORT jl_value_t *jl_cpu_has_fma(int bits);
219226
// Check if the CPU has native FMA instructions;

test/cmdlineargs.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,14 @@ end
10281028
@test v[2] == ""
10291029
@test contains(v[3], "More than one command line CPU targets specified")
10301030
end
1031+
1032+
# Testing this more precisely would be very platform and build system dependent and brittle.
1033+
withenv("JULIA_CPU_TARGET" => "sysimage") do
1034+
v = readchomp(`$julia_path -E "Sys.sysimage_target()"`)
1035+
# Local builds will likely be "native" but CI shouldn't be.
1036+
invalid_results = Base.get_bool_env("CI", false) ? ("", "native", "sysimage") : ("", "sysimage",)
1037+
@test !in(v, invalid_results)
1038+
end
10311039
end
10321040

10331041
# Find the path of libjulia (or libjulia-debug, as the case may be)

0 commit comments

Comments
 (0)