diff --git a/doc/src/manual/environment-variables.md b/doc/src/manual/environment-variables.md index 5aa0701c9aafe..b3bfa5204e603 100644 --- a/doc/src/manual/environment-variables.md +++ b/doc/src/manual/environment-variables.md @@ -400,6 +400,23 @@ If set to anything besides `0`, then Julia's thread policy is consistent with running on a dedicated machine: the master thread is on proc 0, and threads are affinitized. Otherwise, Julia lets the operating system handle thread policy. +## Garbage Collection + +### [`JULIA_HEAP_SIZE_HINT`](@id JULIA_HEAP_SIZE_HINT) + +Environment variable equivalent to the `--heap-size-hint=[]` command line option. + +Forces garbage collection if memory usage is higher than the given value. The value may be specified as a number of bytes, optionally in units of: + + - B (bytes) + - K (kibibytes) + - M (mebibytes) + - G (gibibytes) + - T (tebibytes) + - % (percentage of physical memory) + +For example, `JULIA_HEAP_SIZE_HINT=1G` would provide a 1 GB heap size hint to the garbage collector. + ## REPL formatting Environment variables that determine how REPL output should be formatted at the diff --git a/src/gc-stock.c b/src/gc-stock.c index 86dbea3b9a17a..1a8d85e249c29 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -3618,6 +3618,13 @@ void jl_gc_init(void) uint64_t mem_reserve = 250*1024*1024; // LLVM + other libraries need some amount of memory uint64_t min_heap_size_hint = mem_reserve + 1*1024*1024; uint64_t hint = jl_options.heap_size_hint; + + // check if heap size specified on command line + if (jl_options.heap_size_hint == 0) { + char *cp = getenv(HEAP_SIZE_HINT); + if (cp) + hint = parse_heap_size_hint(cp, "JULIA_HEAP_SIZE_HINT=\"[]\""); + } #ifdef _P64 total_mem = uv_get_total_memory(); if (hint == 0) { diff --git a/src/jloptions.c b/src/jloptions.c index 35f0a76e3f6e7..907f47d9030e4 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -34,6 +34,54 @@ JL_DLLEXPORT const char *jl_get_default_sysimg_path(void) return &system_image_path[1]; } +/* This function is also used by gc-stock.c to parse the + * JULIA_HEAP_SIZE_HINT environment variable. */ +uint64_t parse_heap_size_hint(const char *optarg, const char *option_name) +{ + long double value = 0.0; + char unit[4] = {0}; + int nparsed = sscanf(optarg, "%Lf%3s", &value, unit); + if (nparsed == 0 || strlen(unit) > 2 || (strlen(unit) == 2 && ascii_tolower(unit[1]) != 'b')) { + jl_errorf("julia: invalid argument to %s (%s)", option_name, optarg); + } + uint64_t multiplier = 1ull; + switch (ascii_tolower(unit[0])) { + case '\0': + case 'b': + break; + case 'k': + multiplier <<= 10; + break; + case 'm': + multiplier <<= 20; + break; + case 'g': + multiplier <<= 30; + break; + case 't': + multiplier <<= 40; + break; + case '%': + if (value > 100) + jl_errorf("julia: invalid percentage specified in %s", option_name); + uint64_t mem = uv_get_total_memory(); + uint64_t cmem = uv_get_constrained_memory(); + if (cmem > 0 && cmem < mem) + mem = cmem; + multiplier = mem/100; + break; + default: + jl_errorf("julia: invalid argument to %s (%s)", option_name, optarg); + break; + } + long double sz = value * multiplier; + if (isnan(sz) || sz < 0) { + jl_errorf("julia: invalid argument to %s (%s)", option_name, optarg); + } + const long double limit = ldexpl(1.0, 64); // UINT64_MAX + 1 + return sz < limit ? (uint64_t)sz : UINT64_MAX; +} + static int jl_options_initialized = 0; JL_DLLEXPORT void jl_init_options(void) @@ -231,10 +279,11 @@ static const char opts[] = " current environment and fallbacks to the latest\n" " compatible BugReporting.jl if not. For more\n" " information, see --bug-report=help.\n\n" - " --heap-size-hint= Forces garbage collection if memory usage is higher\n" + " --heap-size-hint=[] Forces garbage collection if memory usage is higher\n" " than the given value. The value may be specified as a\n" - " number of bytes, optionally in units of KB, MB, GB,\n" - " or TB, or as a percentage of physical memory with %.\n\n" + " number of bytes, optionally in units of: B, K (kibibytes),\n" + " M (mebibytes), G (gibibytes), T (tebibytes), or % (percentage\n" + " of physical memory).\n\n" ; static const char opts_hidden[] = @@ -880,52 +929,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) jl_options.strip_ir = 1; break; case opt_heap_size_hint: - if (optarg != NULL) { - long double value = 0.0; - char unit[4] = {0}; - int nparsed = sscanf(optarg, "%Lf%3s", &value, unit); - if (nparsed == 0 || strlen(unit) > 2 || (strlen(unit) == 2 && ascii_tolower(unit[1]) != 'b')) { - jl_errorf("julia: invalid argument to --heap-size-hint (%s)", optarg); - } - uint64_t multiplier = 1ull; - switch (ascii_tolower(unit[0])) { - case '\0': - case 'b': - break; - case 'k': - multiplier <<= 10; - break; - case 'm': - multiplier <<= 20; - break; - case 'g': - multiplier <<= 30; - break; - case 't': - multiplier <<= 40; - break; - case '%': - if (value > 100) - jl_errorf("julia: invalid percentage specified in --heap-size-hint"); - uint64_t mem = uv_get_total_memory(); - uint64_t cmem = uv_get_constrained_memory(); - if (cmem > 0 && cmem < mem) - mem = cmem; - multiplier = mem/100; - break; - default: - jl_errorf("julia: invalid argument to --heap-size-hint (%s)", optarg); - break; - } - long double sz = value * multiplier; - if (isnan(sz) || sz < 0) { - jl_errorf("julia: invalid argument to --heap-size-hint (%s)", optarg); - } - const long double limit = ldexpl(1.0, 64); // UINT64_MAX + 1 - jl_options.heap_size_hint = sz < limit ? (uint64_t)sz : UINT64_MAX; - } + if (optarg != NULL) + jl_options.heap_size_hint = parse_heap_size_hint(optarg, "--heap-size-hint=[]"); if (jl_options.heap_size_hint == 0) - jl_errorf("julia: invalid memory size specified in --heap-size-hint"); + jl_errorf("julia: invalid memory size specified in --heap-size-hint=[]"); break; case opt_gc_threads: diff --git a/src/julia.h b/src/julia.h index 301650540a15c..81e6cf42da567 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2536,6 +2536,8 @@ JL_DLLEXPORT ssize_t jl_sizeof_jl_options(void); JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp); JL_DLLEXPORT char *jl_format_filename(const char *output_pattern); +uint64_t parse_heap_size_hint(const char *optarg, const char *option_name); + // Set julia-level ARGS array according to the arguments provided in // argc/argv JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv); diff --git a/src/options.h b/src/options.h index 800be866183b0..0715069faab32 100644 --- a/src/options.h +++ b/src/options.h @@ -137,6 +137,9 @@ // GC threads #define NUM_GC_THREADS_NAME "JULIA_NUM_GC_THREADS" +// heap size hint +#define HEAP_SIZE_HINT "JULIA_HEAP_SIZE_HINT" + // affinitization behavior #define MACHINE_EXCLUSIVE_NAME "JULIA_EXCLUSIVE" #define DEFAULT_MACHINE_EXCLUSIVE 0