diff options
author | Jere Leppänen <jere.leppanen@nokia.com> | 2023-03-14 11:24:38 +0200 |
---|---|---|
committer | Matias Elo <matias.elo@nokia.com> | 2024-02-01 16:35:10 +0200 |
commit | 5cc40ab1c038831d9d9fafa97a6b6222d8141432 (patch) | |
tree | 6a03c093151eeba489f77590adad8f55c6373468 | |
parent | 22c7067de77ff0ad39c01cd2525547eb3a9e6772 (diff) |
linux-gen: sched: improve timer behavior when power saving sleep is enabled
When using inline timers and power saving sleep, limit sleep duration
according to the next timeout.
Signed-off-by: Jere Leppänen <jere.leppanen@nokia.com>
Reviewed-by: Petri Savolainen <petri.savolainen@nokia.com>
-rw-r--r-- | config/odp-linux-generic.conf | 7 | ||||
-rw-r--r-- | platform/linux-generic/odp_schedule_basic.c | 24 |
2 files changed, 22 insertions, 9 deletions
diff --git a/config/odp-linux-generic.conf b/config/odp-linux-generic.conf index 63ac31fe2..2d27752b2 100644 --- a/config/odp-linux-generic.conf +++ b/config/odp-linux-generic.conf @@ -240,8 +240,9 @@ sched_basic: { # When waiting for events during a schedule call, save power by # sleeping in the poll loop. First, run schedule loop normally for # poll_time_nsec nanoseconds. If there are no events to schedule in that - # time, continue polling, but sleep for sleep_time_nsec nanoseconds on - # each round. + # time, continue polling, but sleep on each round. Sleep time is + # sleep_time_nsec nanoseconds, or the time to the next timer expiration, + # whichever is smaller. Timer pools are scanned just before sleep. # # During sleep, the thread is not polling for packet input or timers. # Each thread measures time and sleeps independently of other threads. @@ -257,7 +258,7 @@ sched_basic: { # Time in nsec to sleep # - # Actual sleep time may vary. + # Must be less than one second. Actual sleep time may vary. sleep_time_nsec = 0 } } diff --git a/platform/linux-generic/odp_schedule_basic.c b/platform/linux-generic/odp_schedule_basic.c index 7bd8cbfed..3b0a4dce9 100644 --- a/platform/linux-generic/odp_schedule_basic.c +++ b/platform/linux-generic/odp_schedule_basic.c @@ -44,6 +44,7 @@ #include <string.h> #include <time.h> +#include <inttypes.h> /* No synchronization context */ #define NO_SYNC_CONTEXT ODP_SCHED_SYNC_PARALLEL @@ -297,7 +298,7 @@ typedef struct { struct { uint32_t poll_time; - struct timespec sleep_time; + uint64_t sleep_time; } powersave; /* Scheduler interface config options (not used in fast path) */ @@ -545,8 +546,8 @@ static int read_config_file(sched_global_t *sched) } val = _ODP_MAX(0, val); - sched->powersave.sleep_time.tv_sec = val / 1000000000; - sched->powersave.sleep_time.tv_nsec = val % 1000000000; + val = _ODP_MIN((int)ODP_TIME_SEC_IN_NS - 1, val); + sched->powersave.sleep_time = val; _ODP_PRINT(" %s: %i\n", str, val); _ODP_PRINT(" dynamic load balance: %s\n", sched->load_balance ? "ON" : "OFF"); @@ -1672,7 +1673,7 @@ static inline int schedule_loop_sleep(odp_queue_t *out_queue, uint64_t wait, timer_run(2); break; } - timer_run(1); + uint64_t next = timer_run(sleep ? TIMER_SCAN_FORCE : 1); if (first) { start = odp_time_local(); @@ -1683,8 +1684,19 @@ static inline int schedule_loop_sleep(odp_queue_t *out_queue, uint64_t wait, continue; } - if (sleep) - nanosleep(&sched->powersave.sleep_time, NULL); + if (sleep && next) { + uint64_t sleep_nsec = _ODP_MIN(sched->powersave.sleep_time, next); + + if (wait != ODP_SCHED_WAIT) { + uint64_t nsec_to_end = odp_time_diff_ns(end, current); + + sleep_nsec = _ODP_MIN(sleep_nsec, nsec_to_end); + } + + struct timespec ts = { 0, sleep_nsec }; + + nanosleep(&ts, NULL); + } if (wait != ODP_SCHED_WAIT || !sleep) { current = odp_time_local(); |