Skip to content

Commit f336314

Browse files
authored
Make heap size hint available as an env variable (JuliaLang#55631)
This makes `JULIA_HEAP_SIZE_HINT` the environment variable version of the `--heap-size-hint` command-line flag. Seems like there was interest in JuliaLang#45369 (comment). The same syntax is used as for the command-line version with, for example, `2G` => 2 GB and `200M` => 200 MB. @oscardssmith want to take a look?
1 parent 8593792 commit f336314

File tree

5 files changed

+84
-48
lines changed

5 files changed

+84
-48
lines changed

doc/src/manual/environment-variables.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,23 @@ If set to anything besides `0`, then Julia's thread policy is consistent with
400400
running on a dedicated machine: the master thread is on proc 0, and threads are
401401
affinitized. Otherwise, Julia lets the operating system handle thread policy.
402402

403+
## Garbage Collection
404+
405+
### [`JULIA_HEAP_SIZE_HINT`](@id JULIA_HEAP_SIZE_HINT)
406+
407+
Environment variable equivalent to the `--heap-size-hint=<size>[<unit>]` command line option.
408+
409+
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:
410+
411+
- B (bytes)
412+
- K (kibibytes)
413+
- M (mebibytes)
414+
- G (gibibytes)
415+
- T (tebibytes)
416+
- % (percentage of physical memory)
417+
418+
For example, `JULIA_HEAP_SIZE_HINT=1G` would provide a 1 GB heap size hint to the garbage collector.
419+
403420
## REPL formatting
404421

405422
Environment variables that determine how REPL output should be formatted at the

src/gc-stock.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3618,6 +3618,13 @@ void jl_gc_init(void)
36183618
uint64_t mem_reserve = 250*1024*1024; // LLVM + other libraries need some amount of memory
36193619
uint64_t min_heap_size_hint = mem_reserve + 1*1024*1024;
36203620
uint64_t hint = jl_options.heap_size_hint;
3621+
3622+
// check if heap size specified on command line
3623+
if (jl_options.heap_size_hint == 0) {
3624+
char *cp = getenv(HEAP_SIZE_HINT);
3625+
if (cp)
3626+
hint = parse_heap_size_hint(cp, "JULIA_HEAP_SIZE_HINT=\"<size>[<unit>]\"");
3627+
}
36213628
#ifdef _P64
36223629
total_mem = uv_get_total_memory();
36233630
if (hint == 0) {

src/jloptions.c

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,54 @@ JL_DLLEXPORT const char *jl_get_default_sysimg_path(void)
3434
return &system_image_path[1];
3535
}
3636

37+
/* This function is also used by gc-stock.c to parse the
38+
* JULIA_HEAP_SIZE_HINT environment variable. */
39+
uint64_t parse_heap_size_hint(const char *optarg, const char *option_name)
40+
{
41+
long double value = 0.0;
42+
char unit[4] = {0};
43+
int nparsed = sscanf(optarg, "%Lf%3s", &value, unit);
44+
if (nparsed == 0 || strlen(unit) > 2 || (strlen(unit) == 2 && ascii_tolower(unit[1]) != 'b')) {
45+
jl_errorf("julia: invalid argument to %s (%s)", option_name, optarg);
46+
}
47+
uint64_t multiplier = 1ull;
48+
switch (ascii_tolower(unit[0])) {
49+
case '\0':
50+
case 'b':
51+
break;
52+
case 'k':
53+
multiplier <<= 10;
54+
break;
55+
case 'm':
56+
multiplier <<= 20;
57+
break;
58+
case 'g':
59+
multiplier <<= 30;
60+
break;
61+
case 't':
62+
multiplier <<= 40;
63+
break;
64+
case '%':
65+
if (value > 100)
66+
jl_errorf("julia: invalid percentage specified in %s", option_name);
67+
uint64_t mem = uv_get_total_memory();
68+
uint64_t cmem = uv_get_constrained_memory();
69+
if (cmem > 0 && cmem < mem)
70+
mem = cmem;
71+
multiplier = mem/100;
72+
break;
73+
default:
74+
jl_errorf("julia: invalid argument to %s (%s)", option_name, optarg);
75+
break;
76+
}
77+
long double sz = value * multiplier;
78+
if (isnan(sz) || sz < 0) {
79+
jl_errorf("julia: invalid argument to %s (%s)", option_name, optarg);
80+
}
81+
const long double limit = ldexpl(1.0, 64); // UINT64_MAX + 1
82+
return sz < limit ? (uint64_t)sz : UINT64_MAX;
83+
}
84+
3785
static int jl_options_initialized = 0;
3886

3987
JL_DLLEXPORT void jl_init_options(void)
@@ -231,10 +279,11 @@ static const char opts[] =
231279
" current environment and fallbacks to the latest\n"
232280
" compatible BugReporting.jl if not. For more\n"
233281
" information, see --bug-report=help.\n\n"
234-
" --heap-size-hint=<size> Forces garbage collection if memory usage is higher\n"
282+
" --heap-size-hint=<size>[<unit>] Forces garbage collection if memory usage is higher\n"
235283
" than the given value. The value may be specified as a\n"
236-
" number of bytes, optionally in units of KB, MB, GB,\n"
237-
" or TB, or as a percentage of physical memory with %.\n\n"
284+
" number of bytes, optionally in units of: B, K (kibibytes),\n"
285+
" M (mebibytes), G (gibibytes), T (tebibytes), or % (percentage\n"
286+
" of physical memory).\n\n"
238287
;
239288

240289
static const char opts_hidden[] =
@@ -880,52 +929,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
880929
jl_options.strip_ir = 1;
881930
break;
882931
case opt_heap_size_hint:
883-
if (optarg != NULL) {
884-
long double value = 0.0;
885-
char unit[4] = {0};
886-
int nparsed = sscanf(optarg, "%Lf%3s", &value, unit);
887-
if (nparsed == 0 || strlen(unit) > 2 || (strlen(unit) == 2 && ascii_tolower(unit[1]) != 'b')) {
888-
jl_errorf("julia: invalid argument to --heap-size-hint (%s)", optarg);
889-
}
890-
uint64_t multiplier = 1ull;
891-
switch (ascii_tolower(unit[0])) {
892-
case '\0':
893-
case 'b':
894-
break;
895-
case 'k':
896-
multiplier <<= 10;
897-
break;
898-
case 'm':
899-
multiplier <<= 20;
900-
break;
901-
case 'g':
902-
multiplier <<= 30;
903-
break;
904-
case 't':
905-
multiplier <<= 40;
906-
break;
907-
case '%':
908-
if (value > 100)
909-
jl_errorf("julia: invalid percentage specified in --heap-size-hint");
910-
uint64_t mem = uv_get_total_memory();
911-
uint64_t cmem = uv_get_constrained_memory();
912-
if (cmem > 0 && cmem < mem)
913-
mem = cmem;
914-
multiplier = mem/100;
915-
break;
916-
default:
917-
jl_errorf("julia: invalid argument to --heap-size-hint (%s)", optarg);
918-
break;
919-
}
920-
long double sz = value * multiplier;
921-
if (isnan(sz) || sz < 0) {
922-
jl_errorf("julia: invalid argument to --heap-size-hint (%s)", optarg);
923-
}
924-
const long double limit = ldexpl(1.0, 64); // UINT64_MAX + 1
925-
jl_options.heap_size_hint = sz < limit ? (uint64_t)sz : UINT64_MAX;
926-
}
932+
if (optarg != NULL)
933+
jl_options.heap_size_hint = parse_heap_size_hint(optarg, "--heap-size-hint=<size>[<unit>]");
927934
if (jl_options.heap_size_hint == 0)
928-
jl_errorf("julia: invalid memory size specified in --heap-size-hint");
935+
jl_errorf("julia: invalid memory size specified in --heap-size-hint=<size>[<unit>]");
929936

930937
break;
931938
case opt_gc_threads:

src/julia.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2536,6 +2536,8 @@ JL_DLLEXPORT ssize_t jl_sizeof_jl_options(void);
25362536
JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp);
25372537
JL_DLLEXPORT char *jl_format_filename(const char *output_pattern);
25382538

2539+
uint64_t parse_heap_size_hint(const char *optarg, const char *option_name);
2540+
25392541
// Set julia-level ARGS array according to the arguments provided in
25402542
// argc/argv
25412543
JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv);

src/options.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@
137137
// GC threads
138138
#define NUM_GC_THREADS_NAME "JULIA_NUM_GC_THREADS"
139139

140+
// heap size hint
141+
#define HEAP_SIZE_HINT "JULIA_HEAP_SIZE_HINT"
142+
140143
// affinitization behavior
141144
#define MACHINE_EXCLUSIVE_NAME "JULIA_EXCLUSIVE"
142145
#define DEFAULT_MACHINE_EXCLUSIVE 0

0 commit comments

Comments
 (0)