Skip to content

Commit fab87b2

Browse files
committed
erts: Honor CPU quotas when deciding number of online schedulers
Using more cores than we have quota for is likely to hurt performance as any busy-waiting we might do (waiting for new jobs to arrive in a queue, waiting for a lock, etc) will burn the quota without doing useful work, leaving us with fewer resources to work with. This is especially bad when the +sbwt option has been used to increase the wait time. This commit checks our current CPU quota (if possible) and tries to limit the number of online schedulers accordingly on startup. The schedulers can be brought online later on, or overridden with the `+S` option.
1 parent c46f6b3 commit fab87b2

9 files changed

Lines changed: 434 additions & 101 deletions

File tree

erts/doc/src/erl.xml

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -944,14 +944,19 @@
944944
<c><![CDATA[+S Schedulers:SchedulerOnline]]></c></tag>
945945
<item>
946946
<p>Sets the number of scheduler threads to create and scheduler threads
947-
to set online. The maximum for both
948-
values is 1024. If the Erlang runtime system is able to determine the
949-
number of logical processors configured and logical processors
950-
available, <c>Schedulers</c> defaults to logical processors
951-
configured, and <c>SchedulersOnline</c> defaults to logical processors
952-
available; otherwise the default values are 1. <c>Schedulers</c> can
953-
be omitted if <c>:SchedulerOnline</c> is not and conversely. The
954-
number of schedulers online can be changed at runtime through
947+
to set online. The maximum for both values is 1024. If the Erlang
948+
runtime system is able to determine the number of logical processors
949+
configured and logical processors available, <c>Schedulers</c>
950+
defaults to logical processors configured, and
951+
<c>SchedulersOnline</c> defaults to logical processors available;
952+
otherwise the default values are 1. If the emulator detects that it
953+
is subject to a <seealso marker="erlang#system_info_cpu_quota">CPU
954+
quota</seealso>, the default value for <c>SchedulersOnline</c> will
955+
be limited accordingly.</p>
956+
<p>
957+
<c>Schedulers</c> can be omitted if <c>:SchedulerOnline</c> is not
958+
and conversely. The number of schedulers online can be changed at
959+
runtime through
955960
<seealso marker="erlang#system_flag_schedulers_online">
956961
<c>erlang:system_flag(schedulers_online,
957962
SchedulersOnline)</c></seealso>.</p>

erts/doc/src/erlang.xml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8153,6 +8153,15 @@ Metadata = #{ pid => pid(),
81538153
<seealso marker="#system_info_logical_processors">logical processors
81548154
configured</seealso>.</p>
81558155
</item>
8156+
<tag><marker id="system_info_cpu_quota"/>
8157+
<c>cpu_quota</c></tag>
8158+
<item>
8159+
<p>Returns the detected CPU quota the emulator is limited by. The
8160+
return value is an integer saying how many processors' worth of
8161+
runtime we get (between 1 and the number of logical processors),
8162+
or the atom <c>unknown</c> if the emulator cannot detect a
8163+
quota.</p>
8164+
</item>
81568165
<tag><marker id="system_info_update_cpu_info"/>
81578166
<c>update_cpu_info</c></tag>
81588167
<item>
@@ -8162,8 +8171,9 @@ Metadata = #{ pid => pid(),
81628171
CPU topology</seealso> and the number of logical processors
81638172
<seealso marker="#system_info_logical_processors">configured</seealso>,
81648173
<seealso marker="#system_info_logical_processors_online">online</seealso>,
8165-
and <seealso marker="#system_info_logical_processors_available">
8166-
available</seealso>.</p>
8174+
<seealso marker="#system_info_logical_processors_available">available</seealso>,
8175+
and <seealso marker="#system_info_cpu_quota">cpu
8176+
quota</seealso>.</p>
81678177
<p>If the CPU information has changed since the last time
81688178
it was read, the atom <c>changed</c> is returned, otherwise
81698179
the atom <c>unchanged</c>. If the CPU information has changed,

erts/emulator/beam/erl_bif_info.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2825,7 +2825,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
28252825
/* Arguments that are unusual follow ... */
28262826
else if (ERTS_IS_ATOM_STR("logical_processors", BIF_ARG_1)) {
28272827
int no;
2828-
erts_get_logical_processors(&no, NULL, NULL);
2828+
erts_get_logical_processors(&no, NULL, NULL, NULL);
28292829
if (no > 0)
28302830
BIF_RET(make_small((Uint) no));
28312831
else {
@@ -2835,7 +2835,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
28352835
}
28362836
else if (ERTS_IS_ATOM_STR("logical_processors_online", BIF_ARG_1)) {
28372837
int no;
2838-
erts_get_logical_processors(NULL, &no, NULL);
2838+
erts_get_logical_processors(NULL, &no, NULL, NULL);
28392839
if (no > 0)
28402840
BIF_RET(make_small((Uint) no));
28412841
else {
@@ -2845,7 +2845,17 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
28452845
}
28462846
else if (ERTS_IS_ATOM_STR("logical_processors_available", BIF_ARG_1)) {
28472847
int no;
2848-
erts_get_logical_processors(NULL, NULL, &no);
2848+
erts_get_logical_processors(NULL, NULL, &no, NULL);
2849+
if (no > 0)
2850+
BIF_RET(make_small((Uint) no));
2851+
else {
2852+
DECL_AM(unknown);
2853+
BIF_RET(AM_unknown);
2854+
}
2855+
}
2856+
else if (ERTS_IS_ATOM_STR("cpu_quota", BIF_ARG_1)) {
2857+
int no;
2858+
erts_get_logical_processors(NULL, NULL, NULL, &no);
28492859
if (no > 0)
28502860
BIF_RET(make_small((Uint) no));
28512861
else {

erts/emulator/beam/erl_cpu_topology.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,21 +1632,23 @@ erts_get_cpu_topology_term(Process *c_p, Eterm which)
16321632
}
16331633

16341634
static void
1635-
get_logical_processors(int *conf, int *onln, int *avail)
1635+
get_logical_processors(int *conf, int *onln, int *avail, int *quota)
16361636
{
16371637
if (conf)
16381638
*conf = erts_get_cpu_configured(cpuinfo);
16391639
if (onln)
16401640
*onln = erts_get_cpu_online(cpuinfo);
16411641
if (avail)
16421642
*avail = erts_get_cpu_available(cpuinfo);
1643+
if (quota)
1644+
*quota = erts_get_cpu_quota(cpuinfo);
16431645
}
16441646

16451647
void
1646-
erts_get_logical_processors(int *conf, int *onln, int *avail)
1648+
erts_get_logical_processors(int *conf, int *onln, int *avail, int *quota)
16471649
{
16481650
erts_rwmtx_rlock(&cpuinfo_rwmtx);
1649-
get_logical_processors(conf, onln, avail);
1651+
get_logical_processors(conf, onln, avail, quota);
16501652
erts_rwmtx_runlock(&cpuinfo_rwmtx);
16511653
}
16521654

@@ -1655,14 +1657,15 @@ erts_pre_early_init_cpu_topology(int *max_dcg_p,
16551657
int *max_rg_p,
16561658
int *conf_p,
16571659
int *onln_p,
1658-
int *avail_p)
1660+
int *avail_p,
1661+
int *quota_p)
16591662
{
16601663
cpu_groups_maps = NULL;
16611664
no_cpu_groups_callbacks = 0;
16621665
*max_rg_p = ERTS_MAX_READER_GROUPS;
16631666
*max_dcg_p = ERTS_MAX_FLXCTR_GROUPS;
16641667
cpuinfo = erts_cpu_info_create();
1665-
get_logical_processors(conf_p, onln_p, avail_p);
1668+
get_logical_processors(conf_p, onln_p, avail_p, quota_p);
16661669
}
16671670

16681671
void

erts/emulator/beam/erl_cpu_topology.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ erts_pre_early_init_cpu_topology(int *max_dcg_p,
3232
int *max_rg_p,
3333
int *conf_p,
3434
int *onln_p,
35-
int *avail_p);
35+
int *avail_p,
36+
int *quota_p);
3637
void
3738
erts_early_init_cpu_topology(int no_schedulers,
3839
int *max_main_threads_p,
@@ -81,7 +82,7 @@ Eterm erts_set_cpu_topology(Process *c_p, Eterm term);
8182
Eterm erts_get_cpu_topology_term(Process *c_p, Eterm which);
8283

8384
int erts_update_cpu_info(void);
84-
void erts_get_logical_processors(int *conf, int *onln, int *avail);
85+
void erts_get_logical_processors(int *conf, int *onln, int *avail, int *quota);
8586

8687
int erts_sched_bind_atthrcreate_prepare(void);
8788
int erts_sched_bind_atthrcreate_child(int unbind);

erts/emulator/beam/erl_init.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ early_init(int *argc, char **argv) /*
774774
int ncpu;
775775
int ncpuonln;
776776
int ncpuavail;
777+
int ncpuquota;
777778
int schdlrs;
778779
int schdlrs_onln;
779780
int schdlrs_percentage = 100;
@@ -811,7 +812,8 @@ early_init(int *argc, char **argv) /*
811812
&max_reader_groups,
812813
&ncpu,
813814
&ncpuonln,
814-
&ncpuavail);
815+
&ncpuavail,
816+
&ncpuquota);
815817

816818
ignore_break = 0;
817819
replace_intr = 0;
@@ -838,9 +840,18 @@ early_init(int *argc, char **argv) /*
838840
* can initialize the allocators.
839841
*/
840842
no_schedulers = (Uint) (ncpu > 0 ? ncpu : 1);
841-
no_schedulers_online = (ncpuavail > 0
842-
? ncpuavail
843-
: (ncpuonln > 0 ? ncpuonln : no_schedulers));
843+
844+
if (ncpuavail > 0) {
845+
if (ncpuquota > 0) {
846+
no_schedulers_online = MIN(ncpuquota, ncpuavail);
847+
} else {
848+
no_schedulers_online = ncpuavail;
849+
}
850+
} else if (ncpuonln > 0) {
851+
no_schedulers_online = ncpuonln;
852+
} else {
853+
no_schedulers_online = no_schedulers;
854+
}
844855

845856
schdlrs = no_schedulers;
846857
schdlrs_onln = no_schedulers_online;

0 commit comments

Comments
 (0)