From 722a888ef73913539fb7555fc956ebda1e293eb4 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Fri, 21 Sep 2018 11:54:57 -0700 Subject: [PATCH] timer: Clean up hairy tickless APIs The tickless driver had a bunch of "hairy" APIs which forced the timer drivers to do needless low-level accounting for the benefit of the kernel, all of which then proceeded to implement them via cut and paste. Specifically the "program_time" calls forced the driver to expose to the kernel exactly when the next interrupt was due and how much time had elapsed, in a parallel API to the existing "what time is it" and "announce a tick" interrupts that carry the same information. Remove these from the kernel, replacing them with synthesized logic written in terms of the simpler APIs. In some cases there will be a performance impact due to the use of the 64 bit uptime call, but that will go away soon. Signed-off-by: Andy Ross --- drivers/timer/legacy_api.h | 12 +++++++----- include/drivers/system_timer.h | 6 ------ kernel/idle.c | 4 +++- kernel/include/timeout_q.h | 30 +++++++++++++++--------------- kernel/sched.c | 14 ++++---------- kernel/sys_clock.c | 8 +++++--- 6 files changed, 34 insertions(+), 40 deletions(-) diff --git a/drivers/timer/legacy_api.h b/drivers/timer/legacy_api.h index 44184b89c19..de1990c76bc 100644 --- a/drivers/timer/legacy_api.h +++ b/drivers/timer/legacy_api.h @@ -8,16 +8,18 @@ * included only once in a single compilation. */ - -#ifdef CONFIG_TICKLESS_KERNEL -void _set_time(u32_t time); -#endif - #ifdef CONFIG_TICKLESS_IDLE void _timer_idle_enter(s32_t ticks); void z_clock_idle_exit(void); #endif +#ifdef CONFIG_TICKLESS_KERNEL +void _set_time(u32_t time); +extern u32_t _get_program_time(void); +extern u32_t _get_remaining_program_time(void); +extern u32_t _get_elapsed_program_time(void); +#endif + extern void z_clock_set_timeout(s32_t ticks, bool idle) { #ifdef CONFIG_TICKLESS_KERNEL diff --git a/include/drivers/system_timer.h b/include/drivers/system_timer.h index 4ff877f648a..04da471413d 100644 --- a/include/drivers/system_timer.h +++ b/include/drivers/system_timer.h @@ -109,12 +109,6 @@ extern void z_clock_announce(s32_t ticks); */ extern u64_t z_clock_uptime(void); -#ifdef CONFIG_TICKLESS_KERNEL -extern u32_t _get_program_time(void); -extern u32_t _get_remaining_program_time(void); -extern u32_t _get_elapsed_program_time(void); -#endif - #ifdef __cplusplus } #endif diff --git a/kernel/idle.c b/kernel/idle.c index 1ad08028e65..48415499956 100644 --- a/kernel/idle.c +++ b/kernel/idle.c @@ -13,6 +13,8 @@ #include #include +extern u64_t z_last_tick_announced; + #if defined(CONFIG_TICKLESS_IDLE) /* * Idle time must be this value or higher for timer to go into tickless idle @@ -72,7 +74,7 @@ static void sys_power_save_idle(s32_t ticks) { #ifdef CONFIG_TICKLESS_KERNEL if (ticks != K_FOREVER) { - ticks -= _get_elapsed_program_time(); + ticks -= (int)(z_clock_uptime() - z_last_tick_announced); if (!ticks) { /* * Timer has expired or about to expire diff --git a/kernel/include/timeout_q.h b/kernel/include/timeout_q.h index e2330ab745a..23e264aff06 100644 --- a/kernel/include/timeout_q.h +++ b/kernel/include/timeout_q.h @@ -21,6 +21,8 @@ extern "C" { #endif +extern u64_t z_last_tick_announced; + /* initialize the timeouts part of k_thread when enabled in the kernel */ static inline void _init_timeout(struct _timeout *t, _timeout_func_t func) @@ -172,6 +174,16 @@ static inline void _dump_timeout_q(void) #endif } +/* find the closest deadline in the timeout queue */ + +static inline s32_t _get_next_timeout_expiry(void) +{ + struct _timeout *t = (struct _timeout *) + sys_dlist_peek_head(&_timeout_q); + + return t ? t->delta_ticks_from_prev : K_FOREVER; +} + /* * Add timeout to timeout queue. Record waiting thread and wait queue if any. * @@ -229,11 +241,9 @@ static inline void _add_timeout(struct k_thread *thread, * This is like adding this timout back in history. */ u32_t adjusted_timeout; - u32_t program_time = _get_program_time(); - if (program_time > 0) { - *delta += _get_elapsed_program_time(); - } + *delta += (int)(z_clock_uptime() - z_last_tick_announced); + adjusted_timeout = *delta; #endif SYS_DLIST_FOR_EACH_CONTAINER(&_timeout_q, in_q, node) { @@ -255,7 +265,7 @@ inserted: _dump_timeout_q(); #ifdef CONFIG_TICKLESS_KERNEL - if (!program_time || (adjusted_timeout < program_time)) { + if (adjusted_timeout < _get_next_timeout_expiry()) { z_clock_set_timeout(adjusted_timeout, false); } #endif @@ -276,16 +286,6 @@ static inline void _add_thread_timeout(struct k_thread *thread, _add_timeout(thread, &thread->base.timeout, wait_q, timeout_in_ticks); } -/* find the closest deadline in the timeout queue */ - -static inline s32_t _get_next_timeout_expiry(void) -{ - struct _timeout *t = (struct _timeout *) - sys_dlist_peek_head(&_timeout_q); - - return t ? t->delta_ticks_from_prev : K_FOREVER; -} - #ifdef __cplusplus } #endif diff --git a/kernel/sched.c b/kernel/sched.c index dc7b9d28027..043f72b19b6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -648,17 +648,11 @@ void _update_time_slice_before_swap(void) return; } - u32_t remaining = _get_remaining_program_time(); - - if (!remaining || (_time_slice_duration < remaining)) { - z_clock_set_timeout(_time_slice_duration, false); - } else { - /* Account previous elapsed time and reprogram - * timer with remaining time - */ - z_clock_set_timeout(remaining, false); - } + int elapsed = (int)(z_clock_uptime() - z_last_tick_announced); + int next_timeout = _get_next_timeout_expiry() - elapsed; + int t = min(_time_slice_duration, next_timeout); + z_clock_set_timeout(t, false); #endif /* Restart time slice count at new thread switch */ _time_slice_elapsed = 0; diff --git a/kernel/sys_clock.c b/kernel/sys_clock.c index 2245f5d65c9..d7c7f108ac6 100644 --- a/kernel/sys_clock.c +++ b/kernel/sys_clock.c @@ -36,6 +36,8 @@ int z_clock_hw_cycles_per_sec; */ static volatile u64_t tick_count; +u64_t z_last_tick_announced; + #ifdef CONFIG_TICKLESS_KERNEL /* * If this flag is set, system clock will run continuously even if @@ -291,6 +293,8 @@ static void handle_time_slicing(s32_t ticks) */ void z_clock_announce(s32_t ticks) { + z_last_tick_announced += ticks; + #ifdef CONFIG_SMP /* sys_clock timekeeping happens only on the main CPU */ if (_arch_curr_cpu()->id) { @@ -319,9 +323,7 @@ void z_clock_announce(s32_t ticks) next_to = !next_to || (next_ts && next_to) > next_ts ? next_ts : next_to; - u32_t remaining = _get_remaining_program_time(); - - if ((!remaining && next_to) || (next_to < remaining)) { + if (next_to) { /* Clears current program if next_to = 0 and remaining > 0 */ int dt = next_to ? next_to : (_sys_clock_always_on ? INT_MAX : K_FOREVER); z_clock_set_timeout(dt, false);