mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-06 12:58:22 +03:00
core: add new RandomSec= setting for time units
This allows configuration of a random time on top of the elapse events, in order to spread time events in a network evenly across a range.
This commit is contained in:
parent
45090bf2ff
commit
744c769375
@ -190,13 +190,12 @@
|
||||
<varname>OnUnitInactiveSec=</varname> and ending the time
|
||||
configured with <varname>AccuracySec=</varname> later. Within
|
||||
this time window, the expiry time will be placed at a
|
||||
host-specific, randomized but stable position that is
|
||||
host-specific, randomized, but stable position that is
|
||||
synchronized between all local timer units. This is done in
|
||||
order to distribute the wake-up time in networked
|
||||
installations, as well as optimizing power consumption to
|
||||
suppress unnecessary CPU wake-ups. To get best accuracy, set
|
||||
this option to 1us. Note that the timer is still subject to
|
||||
the timer slack configured via
|
||||
order to optimize power consumption to suppress unnecessary
|
||||
CPU wake-ups. To get best accuracy, set this option to
|
||||
1us. Note that the timer is still subject to the timer slack
|
||||
configured via
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>'s
|
||||
<varname>TimerSlackNSec=</varname> setting. See
|
||||
<citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
@ -204,6 +203,38 @@
|
||||
this value as high as possible and as low as
|
||||
necessary.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RandomSec=</varname></term>
|
||||
|
||||
<listitem><para>Delay the timer by a randomly selected, evenly
|
||||
distributed amount of time between 0 and the specified time
|
||||
value. Defaults to 0, indicating that no randomized delay
|
||||
shall be applied. Each timer unit will determine this delay
|
||||
randomly each time it is started, and the delay will simply be
|
||||
added on top of the next determined elapsing time. This is
|
||||
useful to stretch dispatching of similarly configured timer
|
||||
events over a certain amount time, to avoid that they all fire
|
||||
at the same time, possibly resulting in resource
|
||||
congestion. Note the relation to
|
||||
<varname>AccuracySec=</varname> above: the latter allows the
|
||||
service manager to coalesce timer events within a specified
|
||||
time range in order to minimize wakeups, the former does the
|
||||
opposite: it stretches timer events over a time range, to make
|
||||
it unlikely that they fire simultaneously. If
|
||||
<varname>RandomSec=</varname> and
|
||||
<varname>AccuracySec=</varname> are used in conjunction, first
|
||||
the a randomized time is added, and the result is then
|
||||
possibly shifted further to coalesce it with other timer
|
||||
events possibly happening on the system. As mentioned above
|
||||
<varname>AccuracySec=</varname> defaults to 1min and
|
||||
<varname>RandomSec=</varname> to 0, thus encouraging
|
||||
coalescing of timer events. In order to optimally stretch
|
||||
timer events over a certain range of time, make sure to set
|
||||
<varname>RandomSec=</varname> to a higher value, and
|
||||
<varname>AccuracySec=1us</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Unit=</varname></term>
|
||||
|
||||
|
@ -180,6 +180,7 @@ const sd_bus_vtable bus_timer_vtable[] = {
|
||||
BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RandomUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@ -283,6 +284,22 @@ static int bus_timer_set_transient_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "RandomUSec")) {
|
||||
usec_t u = 0;
|
||||
|
||||
r = sd_bus_message_read(message, "t", &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
char time[FORMAT_TIMESPAN_MAX];
|
||||
|
||||
t->random_usec = u;
|
||||
unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomSec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "WakeSystem")) {
|
||||
int b;
|
||||
|
||||
|
@ -347,6 +347,7 @@ Timer.Persistent, config_parse_bool, 0,
|
||||
Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
|
||||
Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
|
||||
Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
|
||||
Timer.RandomSec, config_parse_sec, 0, offsetof(Timer, random_usec)
|
||||
Timer.Unit, config_parse_trigger_unit, 0, 0
|
||||
m4_dnl
|
||||
Path.PathExists, config_parse_path_spec, 0, 0
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "dbus-timer.h"
|
||||
#include "fs-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "random-util.h"
|
||||
#include "special.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
@ -330,6 +331,28 @@ static usec_t monotonic_to_boottime(usec_t t) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_random(Timer *t, usec_t *v) {
|
||||
char s[FORMAT_TIMESPAN_MAX];
|
||||
usec_t add;
|
||||
|
||||
assert(t);
|
||||
assert(*v);
|
||||
|
||||
if (t->random_usec == 0)
|
||||
return;
|
||||
if (*v == USEC_INFINITY)
|
||||
return;
|
||||
|
||||
add = random_u64() % t->random_usec;
|
||||
|
||||
if (*v + add < *v) /* overflow */
|
||||
*v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
|
||||
else
|
||||
*v += add;
|
||||
|
||||
log_unit_info(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
|
||||
}
|
||||
|
||||
static void timer_enter_waiting(Timer *t, bool initial) {
|
||||
bool found_monotonic = false, found_realtime = false;
|
||||
usec_t ts_realtime, ts_monotonic;
|
||||
@ -452,6 +475,8 @@ static void timer_enter_waiting(Timer *t, bool initial) {
|
||||
char buf[FORMAT_TIMESPAN_MAX];
|
||||
usec_t left;
|
||||
|
||||
add_random(t, &t->next_elapse_monotonic_or_boottime);
|
||||
|
||||
left = t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0;
|
||||
log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
|
||||
|
||||
@ -486,6 +511,9 @@ static void timer_enter_waiting(Timer *t, bool initial) {
|
||||
|
||||
if (found_realtime) {
|
||||
char buf[FORMAT_TIMESTAMP_MAX];
|
||||
|
||||
add_random(t, &t->next_elapse_realtime);
|
||||
|
||||
log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
|
||||
|
||||
if (t->realtime_event_source) {
|
||||
|
@ -58,6 +58,7 @@ struct Timer {
|
||||
Unit meta;
|
||||
|
||||
usec_t accuracy_usec;
|
||||
usec_t random_usec;
|
||||
|
||||
LIST_HEAD(TimerValue, values);
|
||||
usec_t next_elapse_realtime;
|
||||
|
@ -1442,6 +1442,23 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 0;
|
||||
|
||||
} else if (streq(field, "RandomSec")) {
|
||||
usec_t t;
|
||||
|
||||
r = parse_sec(eq, &t);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse RandomSec= parameter: %s", eq);
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomUSec");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", t);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
|
||||
|
Loading…
x
Reference in New Issue
Block a user