Skip to content

Commit e4d2f99

Browse files
committed
erts: Make module and export table limits tunable
Add the +zmml and +zmel emulator flags to set the maximum number of entries in the module_code and export_list loader index tables, raising the previously hardcoded MODULE_LIMIT (64K) and EXPORT_LIMIT (512K) caps. Expose the current limits and counts via erlang:system_info/1 with the new module_limit, module_count, export_limit and export_count keys, and document the flags and system_info keys. As with atom_limit, the reported limit is the effective one enforced by the underlying index table (the requested value rounded up to a whole number of pages).
1 parent 0652aaa commit e4d2f99

11 files changed

Lines changed: 279 additions & 13 deletions

File tree

erts/doc/references/erl_cmd.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,24 @@ behavior of earlier flags.
14551455
14561456
Since: OTP 27.0
14571457
1458+
- **`+zmml limit`{: #+zmml }** - Sets the maximum number of modules that can
1459+
be loaded into the runtime system. Valid range of this limit is
1460+
`[1, 2147483647]` (on 32-bit systems the maximum is `134217727`). Defaults
1461+
to 65536. The limit is rounded up to a whole number of index-table pages,
1462+
so the effective value can be slightly larger than requested.
1463+
1464+
The current (effective) value can be read by Erlang code by calling
1465+
[`erlang:system_info(module_limit)`](`m:erlang#system_info_module_limit`).
1466+
1467+
- **`+zmel limit`{: #+zmel }** - Sets the maximum number of exported functions
1468+
that can be loaded into the runtime system. Valid range of this limit is
1469+
`[1, 2147483647]` (on 32-bit systems the maximum is `134217727`). Defaults
1470+
to 524288. The limit is rounded up to a whole number of index-table pages,
1471+
so the effective value can be slightly larger than requested.
1472+
1473+
The current (effective) value can be read by Erlang code by calling
1474+
[`erlang:system_info(export_limit)`](`m:erlang#system_info_export_limit`).
1475+
14581476
## Environment Variables
14591477
14601478
- **`ERL_CRASH_DUMP`** - If the emulator needs to write a crash dump, the value

erts/doc/src/erlang_system_info.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ order to make it easier to navigate.
5151
[`atom_limit`](`m:erlang#system_info_atom_limit`),
5252
[`ets_count`](`m:erlang#system_info_ets_count`),
5353
[`ets_limit`](`m:erlang#system_info_ets_limit`),
54+
[`export_count`](`m:erlang#system_info_export_count`),
55+
[`export_limit`](`m:erlang#system_info_export_limit`),
56+
[`module_count`](`m:erlang#system_info_module_count`),
57+
[`module_limit`](`m:erlang#system_info_module_limit`),
5458
[`port_count`](`m:erlang#system_info_port_count`),
5559
[`port_limit`](`m:erlang#system_info_port_limit`),
5660
[`process_count`](`m:erlang#system_info_process_count`),
@@ -374,6 +378,29 @@ Returns information about the current system (emulator) limits as specified by `
374378

375379
Since: OTP R16B03
376380

381+
- `export_count`{: #system_info_export_count } - Returns the number of exported
382+
functions currently loaded at the local node. The value is given as an
383+
integer.
384+
385+
Since: OTP 30.0
386+
387+
- `export_limit`{: #system_info_export_limit } - Returns the maximum number of
388+
exported functions allowed. This limit can be changed at startup by passing
389+
command-line flag [`+zmel`](erl_cmd.md#+zmel) to `erl(1)`.
390+
391+
Since: OTP 30.0
392+
393+
- `module_count`{: #system_info_module_count } - Returns the number of modules
394+
currently loaded at the local node. The value is given as an integer.
395+
396+
Since: OTP 30.0
397+
398+
- `module_limit`{: #system_info_module_limit } - Returns the maximum number of
399+
modules allowed. This limit can be changed at startup by passing command-line
400+
flag [`+zmml`](erl_cmd.md#+zmml) to `erl(1)`.
401+
402+
Since: OTP 30.0
403+
377404
- `port_count`{: #system_info_port_count } - Returns the number of ports
378405
currently existing at the local node. The value is given as an integer. This
379406
is the same value as returned by `length(erlang:ports())`, but more

erts/emulator/beam/erl_bif_info.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3521,6 +3521,18 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
35213521
else if (ERTS_IS_ATOM_STR("atom_count",BIF_ARG_1)) {
35223522
BIF_RET(make_small(atom_table_size()));
35233523
}
3524+
else if (ERTS_IS_ATOM_STR("module_limit",BIF_ARG_1)) {
3525+
BIF_RET(erts_make_integer(erts_module_table_limit(), BIF_P));
3526+
}
3527+
else if (ERTS_IS_ATOM_STR("module_count",BIF_ARG_1)) {
3528+
BIF_RET(erts_make_integer(module_code_size(erts_active_code_ix()), BIF_P));
3529+
}
3530+
else if (ERTS_IS_ATOM_STR("export_limit",BIF_ARG_1)) {
3531+
BIF_RET(erts_make_integer(erts_export_table_limit(), BIF_P));
3532+
}
3533+
else if (ERTS_IS_ATOM_STR("export_count",BIF_ARG_1)) {
3534+
BIF_RET(erts_make_integer(export_list_size(erts_active_code_ix()), BIF_P));
3535+
}
35243536
else if (ERTS_IS_ATOM_STR("tolerant_timeofday",BIF_ARG_1)) {
35253537
if (erts_has_time_correction()
35263538
&& erts_time_offset_state() == ERTS_TIME_OFFSET_FINAL) {

erts/emulator/beam/erl_init.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ static void erl_init(int ncpu,
9595
int time_correction,
9696
ErtsTimeWarpMode time_warp_mode,
9797
int node_tab_delete_delay,
98-
ErtsDbSpinCount db_spin_count);
98+
ErtsDbSpinCount db_spin_count,
99+
int module_tab_sz,
100+
int export_tab_sz);
99101

100102
static erts_atomic_t exiting;
101103

@@ -255,7 +257,9 @@ erl_init(int ncpu,
255257
int time_correction,
256258
ErtsTimeWarpMode time_warp_mode,
257259
int node_tab_delete_delay,
258-
ErtsDbSpinCount db_spin_count)
260+
ErtsDbSpinCount db_spin_count,
261+
int module_tab_sz,
262+
int export_tab_sz)
259263
{
260264
init_global_literals();
261265
erts_monitor_link_init();
@@ -283,9 +287,9 @@ erl_init(int ncpu,
283287
erts_code_ix_init();
284288
erts_init_fun_table();
285289
init_atom_table();
286-
init_export_table();
290+
init_export_table(export_tab_sz);
287291
erts_record_init_table();
288-
init_module_table();
292+
init_module_table(module_tab_sz);
289293
init_register_table();
290294
init_message();
291295
#ifdef BEAMASM
@@ -1310,6 +1314,8 @@ erl_start(int argc, char **argv)
13101314
ErtsTimeWarpMode time_warp_mode;
13111315
int node_tab_delete_delay = ERTS_NODE_TAB_DELAY_GC_DEFAULT;
13121316
ErtsDbSpinCount db_spin_count = ERTS_DB_SPNCNT_NORMAL;
1317+
int module_tab_sz = 0;
1318+
int export_tab_sz = 0;
13131319

13141320
/* Must be set up as early as possible for crash dump encryption to work
13151321
* properly. */
@@ -2446,6 +2452,32 @@ erl_start(int argc, char **argv)
24462452
erts_halt_flush_timeout = (ErtsMonotonicTime) val;
24472453
}
24482454
}
2455+
else if (has_prefix("mml", sub_param)) {
2456+
long val;
2457+
char *endptr;
2458+
arg = get_arg(sub_param+3, argv[i+1], &i);
2459+
errno = 0;
2460+
val = strtol(arg, &endptr, 10);
2461+
if (errno != 0 || *arg == '\0' || *endptr != '\0'
2462+
|| val < 1 || MAX_SMALL < val || INT_MAX < val) {
2463+
erts_fprintf(stderr, "Invalid module table limit %s\n", arg);
2464+
erts_usage();
2465+
}
2466+
module_tab_sz = (int) val;
2467+
}
2468+
else if (has_prefix("mel", sub_param)) {
2469+
long val;
2470+
char *endptr;
2471+
arg = get_arg(sub_param+3, argv[i+1], &i);
2472+
errno = 0;
2473+
val = strtol(arg, &endptr, 10);
2474+
if (errno != 0 || *arg == '\0' || *endptr != '\0'
2475+
|| val < 1 || MAX_SMALL < val || INT_MAX < val) {
2476+
erts_fprintf(stderr, "Invalid export table limit %s\n", arg);
2477+
erts_usage();
2478+
}
2479+
export_tab_sz = (int) val;
2480+
}
24492481
else {
24502482
erts_fprintf(stderr, "bad -z option %s\n", argv[i]);
24512483
erts_usage();
@@ -2529,7 +2561,9 @@ erl_start(int argc, char **argv)
25292561
time_correction,
25302562
time_warp_mode,
25312563
node_tab_delete_delay,
2532-
db_spin_count);
2564+
db_spin_count,
2565+
module_tab_sz,
2566+
export_tab_sz);
25332567

25342568
load_preloaded();
25352569
erts_end_staging_code_ix();

erts/emulator/beam/export.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#define EXPORT_INITIAL_SIZE 4000
3636
#define EXPORT_LIMIT (512*1024)
3737

38+
static int export_limit = EXPORT_LIMIT;
39+
3840
#ifdef DEBUG
3941
# define IF_DEBUG(x) x
4042
#else
@@ -115,7 +117,7 @@ static void export_stage(Export *export,
115117
#define ERTS_CODE_STAGED_OBJECT_ALLOC_TYPE ERTS_ALC_T_EXPORT
116118
#define ERTS_CODE_STAGED_TABLE_ALLOC_TYPE ERTS_ALC_T_EXPORT_TABLE
117119
#define ERTS_CODE_STAGED_TABLE_INITIAL_SIZE EXPORT_INITIAL_SIZE
118-
#define ERTS_CODE_STAGED_TABLE_LIMIT EXPORT_LIMIT
120+
#define ERTS_CODE_STAGED_TABLE_LIMIT export_limit
119121

120122
#define ERTS_CODE_STAGED_WANT_GET
121123
#define ERTS_CODE_STAGED_WANT_PUT
@@ -128,11 +130,19 @@ static void export_stage(Export *export,
128130
#include "erl_code_staged.h"
129131

130132
void
131-
init_export_table(void)
133+
init_export_table(int limit)
132134
{
135+
if (limit > 0) {
136+
export_limit = limit;
137+
}
133138
export_staged_init();
134139
}
135140

141+
int erts_export_table_limit(void)
142+
{
143+
return export_tables[erts_active_code_ix()].limit;
144+
}
145+
136146
void
137147
export_info(fmtfn_t to, void *to_arg)
138148
{

erts/emulator/beam/export.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ typedef struct export_
122122
#define DBG_CHECK_EXPORT(EP, CX)
123123
#endif
124124

125-
void init_export_table(void);
125+
void init_export_table(int limit);
126126
void export_info(fmtfn_t, void *);
127+
int erts_export_table_limit(void);
127128

128129
ERTS_GLB_INLINE void erts_activate_export_trampoline(Export *ep, int code_ix);
129130
ERTS_GLB_INLINE int erts_is_export_trampoline_active(const Export * const ep, int code_ix);

erts/emulator/beam/module.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#define MODULE_SIZE 50
4444
#define MODULE_LIMIT (64*1024)
4545

46+
static int module_limit = MODULE_LIMIT;
47+
4648
static IndexTable module_tables[ERTS_NUM_CODE_IX];
4749

4850
erts_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX];
@@ -103,11 +105,15 @@ static void module_free(Module* mod)
103105
erts_atomic_add_nob(&tot_module_bytes, -sizeof(Module));
104106
}
105107

106-
void init_module_table(void)
108+
void init_module_table(int limit)
107109
{
108110
HashFunctions f;
109111
int i;
110112

113+
if (limit > 0) {
114+
module_limit = limit;
115+
}
116+
111117
f.hash = (H_FUN) module_hash;
112118
f.cmp = (HCMP_FUN) module_cmp;
113119
f.alloc = (HALLOC_FUN) module_alloc;
@@ -117,8 +123,8 @@ void init_module_table(void)
117123
f.meta_print = (HMPRINT_FUN) erts_print;
118124

119125
for (i = 0; i < ERTS_NUM_CODE_IX; i++) {
120-
erts_index_init(ERTS_ALC_T_MODULE_TABLE, &module_tables[i], "module_code",
121-
MODULE_SIZE, MODULE_LIMIT, f);
126+
erts_index_init(ERTS_ALC_T_MODULE_TABLE, &module_tables[i], "module_code",
127+
MODULE_SIZE, module_limit, f);
122128
}
123129

124130
for (i=0; i<ERTS_NUM_CODE_IX; i++) {
@@ -256,6 +262,11 @@ int module_code_size(ErtsCodeIndex code_ix)
256262
return module_tables[code_ix].entries;
257263
}
258264

265+
int erts_module_table_limit(void)
266+
{
267+
return module_tables[erts_active_code_ix()].limit;
268+
}
269+
259270
int module_table_sz(void)
260271
{
261272
return erts_atomic_read_nob(&tot_module_bytes);

erts/emulator/beam/module.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,15 @@ void erts_unseal_module(struct erl_module_instance *modi);
7575
* setting up a code barrier. */
7676
void erts_seal_module(struct erl_module_instance *modi);
7777

78-
void init_module_table(void);
78+
void init_module_table(int limit);
7979
void module_start_staging(void);
8080
void module_end_staging(int commit);
8181
void module_info(fmtfn_t, void *);
8282

8383
Module *module_code(int, ErtsCodeIndex);
8484
int module_code_size(ErtsCodeIndex);
8585
int module_table_sz(void);
86+
int erts_module_table_limit(void);
8687

8788
ERTS_GLB_INLINE void erts_rwlock_old_code(ErtsCodeIndex);
8889
ERTS_GLB_INLINE void erts_rwunlock_old_code(ErtsCodeIndex);

0 commit comments

Comments
 (0)