core: make manager event loop rate limit configurable
Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Yu Watanabe
parent
1006535bb9
commit
e1c63fd4c0
@@ -475,6 +475,10 @@ node /org/freedesktop/systemd1 {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly u DefaultStartLimitBurst = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t EventLoopRateLimitIntervalUSec = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly u EventLoopRateLimitBurst = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b DefaultIOAccounting = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b DefaultIPAccounting = ...;
|
||||
@@ -725,6 +729,10 @@ node /org/freedesktop/systemd1 {
|
||||
|
||||
<!--property DefaultStartLimitBurst is not documented!-->
|
||||
|
||||
<!--property EventLoopRateLimitIntervalUSec is not documented!-->
|
||||
|
||||
<!--property EventLoopRateLimitBurst is not documented!-->
|
||||
|
||||
<!--property DefaultIOAccounting is not documented!-->
|
||||
|
||||
<!--property DefaultIPAccounting is not documented!-->
|
||||
@@ -1183,6 +1191,10 @@ node /org/freedesktop/systemd1 {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DefaultStartLimitBurst"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="EventLoopRateLimitIntervalUSec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="EventLoopRateLimitBurst"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DefaultIOAccounting"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DefaultIPAccounting"/>
|
||||
@@ -12691,8 +12703,10 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
||||
<varname>DefaultCPUPressureThresholdUSec</varname>,
|
||||
<varname>DefaultCPUPressureWatch</varname>,
|
||||
<varname>DefaultIOPressureThresholdUSec</varname>,
|
||||
<varname>DefaultIOPressureWatch</varname>, and
|
||||
<varname>ReloadCount</varname> were added in version 261.</para>
|
||||
<varname>DefaultIOPressureWatch</varname>,
|
||||
<varname>ReloadCount</varname>,
|
||||
<varname>EventLoopRateLimitIntervalUSec</varname>, and
|
||||
<varname>EventLoopRateLimitBurst</varname> were added in version 261.</para>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Unit Objects</title>
|
||||
|
||||
@@ -705,6 +705,22 @@
|
||||
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>EventLoopRateLimitIntervalSec=</varname></term>
|
||||
<term><varname>EventLoopRateLimitBurst=</varname></term>
|
||||
|
||||
<listitem><para>Configures the rate limiting applied to the manager's main event loop. If the event
|
||||
loop iterates more than <varname>EventLoopRateLimitBurst=</varname> times within
|
||||
<varname>EventLoopRateLimitIntervalSec=</varname>, event processing is briefly paused to prevent
|
||||
excessive CPU usage. <varname>EventLoopRateLimitIntervalSec=</varname> defaults to 1s.
|
||||
<varname>EventLoopRateLimitBurst=</varname> defaults to 50000. These settings can also be set on the
|
||||
kernel command line via
|
||||
<varname>systemd.event_loop_ratelimit_interval_sec=</varname> and
|
||||
<varname>systemd.event_loop_ratelimit_burst=</varname>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>MinimumUptimeSec=</varname></term>
|
||||
|
||||
|
||||
@@ -2959,6 +2959,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
||||
SD_BUS_PROPERTY("DefaultStartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Manager, defaults.start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
|
||||
SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, defaults.start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
|
||||
SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, defaults.start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("EventLoopRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, event_loop_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("EventLoopRateLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, event_loop_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultIOAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.io_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultIPAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.ip_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, defaults.memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
|
||||
@@ -165,6 +165,8 @@ static void *arg_random_seed;
|
||||
static size_t arg_random_seed_size;
|
||||
static usec_t arg_reload_limit_interval_sec;
|
||||
static unsigned arg_reload_limit_burst;
|
||||
static usec_t arg_event_loop_ratelimit_interval_sec;
|
||||
static unsigned arg_event_loop_ratelimit_burst;
|
||||
static usec_t arg_minimum_uptime_usec;
|
||||
|
||||
/* A copy of the original environment block */
|
||||
@@ -557,6 +559,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.event_loop_ratelimit_interval_sec")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = parse_sec(value, &arg_event_loop_ratelimit_interval_sec);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse systemd.event_loop_ratelimit_interval_sec= argument '%s', ignoring: %m", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.event_loop_ratelimit_burst")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = safe_atou(value, &arg_event_loop_ratelimit_burst);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse systemd.event_loop_ratelimit_burst= argument '%s', ignoring: %m", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.minimum_uptime_sec")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
@@ -865,6 +889,8 @@ static int parse_config_file(void) {
|
||||
{ "Manager", "DefaultOOMScoreAdjust", config_parse_oom_score_adjust, 0, NULL },
|
||||
{ "Manager", "ReloadLimitIntervalSec", config_parse_sec, 0, &arg_reload_limit_interval_sec },
|
||||
{ "Manager", "ReloadLimitBurst", config_parse_unsigned, 0, &arg_reload_limit_burst },
|
||||
{ "Manager", "EventLoopRateLimitIntervalSec", config_parse_sec, 0, &arg_event_loop_ratelimit_interval_sec },
|
||||
{ "Manager", "EventLoopRateLimitBurst", config_parse_unsigned, 0, &arg_event_loop_ratelimit_burst },
|
||||
{ "Manager", "DefaultMemoryZSwapWriteback", config_parse_bool, 0, &arg_defaults.memory_zswap_writeback },
|
||||
{ "Manager", "MinimumUptimeSec", config_parse_sec, 0, &arg_minimum_uptime_usec },
|
||||
#if ENABLE_SMACK
|
||||
@@ -951,6 +977,8 @@ static void set_manager_settings(Manager *m) {
|
||||
* counter on every daemon-reload. */
|
||||
m->reload_reexec_ratelimit.interval = arg_reload_limit_interval_sec;
|
||||
m->reload_reexec_ratelimit.burst = arg_reload_limit_burst;
|
||||
m->event_loop_ratelimit.interval = arg_event_loop_ratelimit_interval_sec;
|
||||
m->event_loop_ratelimit.burst = arg_event_loop_ratelimit_burst;
|
||||
|
||||
manager_set_watchdog(m, WATCHDOG_RUNTIME, arg_runtime_watchdog);
|
||||
manager_set_watchdog(m, WATCHDOG_REBOOT, arg_reboot_watchdog);
|
||||
@@ -2902,6 +2930,9 @@ static void reset_arguments(void) {
|
||||
arg_reload_limit_interval_sec = 0;
|
||||
arg_reload_limit_burst = 0;
|
||||
|
||||
arg_event_loop_ratelimit_interval_sec = 1 * USEC_PER_SEC;
|
||||
arg_event_loop_ratelimit_burst = 50000;
|
||||
|
||||
arg_minimum_uptime_usec = USEC_INFINITY;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +163,7 @@ int manager_serialize(
|
||||
|
||||
(void) serialize_ratelimit(f, "dump-ratelimit", &m->dump_ratelimit);
|
||||
(void) serialize_ratelimit(f, "reload-reexec-ratelimit", &m->reload_reexec_ratelimit);
|
||||
(void) serialize_ratelimit(f, "event-loop-ratelimit", &m->event_loop_ratelimit);
|
||||
|
||||
(void) serialize_id128(f, "bus-id", m->bus_id);
|
||||
bus_track_serialize(m->subscribed, f, "subscribed");
|
||||
@@ -747,6 +748,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
deserialize_ratelimit(&m->dump_ratelimit, "dump-ratelimit", val);
|
||||
else if ((val = startswith(l, "reload-reexec-ratelimit=")))
|
||||
deserialize_ratelimit(&m->reload_reexec_ratelimit, "reload-reexec-ratelimit", val);
|
||||
else if ((val = startswith(l, "event-loop-ratelimit=")))
|
||||
deserialize_ratelimit(&m->event_loop_ratelimit, "event-loop-ratelimit", val);
|
||||
else if ((val = startswith(l, "soft-reboots-count="))) {
|
||||
unsigned n;
|
||||
|
||||
|
||||
+1
-2
@@ -3310,7 +3310,6 @@ static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t use
|
||||
}
|
||||
|
||||
int manager_loop(Manager *m) {
|
||||
RateLimit rl = { .interval = 1*USEC_PER_SEC, .burst = 50000 };
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@@ -3325,7 +3324,7 @@ int manager_loop(Manager *m) {
|
||||
|
||||
while (m->objective == MANAGER_OK) {
|
||||
|
||||
if (!ratelimit_below(&rl)) {
|
||||
if (!ratelimit_below(&m->event_loop_ratelimit)) {
|
||||
/* Yay, something is going seriously wrong, pause a little */
|
||||
log_warning("Looping too fast. Throttling execution a little.");
|
||||
sleep(1);
|
||||
|
||||
@@ -495,6 +495,9 @@ typedef struct Manager {
|
||||
/* Dump*() are slow, so always rate limit them to 10 per 10 minutes */
|
||||
RateLimit dump_ratelimit;
|
||||
|
||||
/* Rate limit for the manager event loop */
|
||||
RateLimit event_loop_ratelimit;
|
||||
|
||||
sd_event_source *pressure_event_source[_PRESSURE_RESOURCE_MAX];
|
||||
|
||||
/* For NFTSet= */
|
||||
|
||||
@@ -88,4 +88,6 @@
|
||||
#DefaultRestrictSUIDSGID=
|
||||
#ReloadLimitIntervalSec=
|
||||
#ReloadLimitBurst=
|
||||
#EventLoopRateLimitIntervalSec=1s
|
||||
#EventLoopRateLimitBurst=50000
|
||||
#DefaultMemoryZSwapWriteback=yes
|
||||
|
||||
@@ -61,4 +61,6 @@
|
||||
#DefaultSmackProcessLabel=
|
||||
#DefaultRestrictSUIDSGID=
|
||||
#ReloadLimitIntervalSec=
|
||||
#ReloadLimitBurst
|
||||
#ReloadLimitBurst=
|
||||
#EventLoopRateLimitIntervalSec=1s
|
||||
#EventLoopRateLimitBurst=50000
|
||||
|
||||
Reference in New Issue
Block a user