pm: policy: separate default policy and events

The default policy currently directly references the private
variable next_event from policy_events.c to then convert the cycle
of said event (if exists) to a kernel tick in the future, something
policy_events.c already implements and exposes through
pm_policy_next_event_ticks().

Additionally, the implementation of pm_policy_next_state() in
policy_default.c already gets the nearest kernel tick, wherein
the next event has already been accounted for in, see
implementation of pm_system_suspend().

This commit removes the redundant and layer violating computation
if the tick of the next event from policy_default.c and updates
the test test_pm_policy_events to not use default policy to
determine if pm_policy_next_event_ticks() is correct.

Signed-off-by: Bjarki Arge Andreasen <bjarki.andreasen@nordicsemi.no>
This commit is contained in:
Bjarki Arge Andreasen 2024-10-29 15:59:09 +01:00 committed by Anas Nashif
commit 14117b453d
2 changed files with 23 additions and 77 deletions

View file

@ -9,7 +9,6 @@
#include <zephyr/sys_clock.h> #include <zephyr/sys_clock.h>
#include <zephyr/pm/device.h> #include <zephyr/pm/device.h>
extern struct pm_policy_event *next_event;
extern int32_t max_latency_cyc; extern int32_t max_latency_cyc;
const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks) const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
@ -30,27 +29,6 @@ const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
num_cpu_states = pm_state_cpu_get_all(cpu, &cpu_states); num_cpu_states = pm_state_cpu_get_all(cpu, &cpu_states);
if ((next_event) && (next_event->value_cyc >= 0)) {
uint32_t cyc_curr = k_cycle_get_32();
int64_t cyc_evt = next_event->value_cyc - cyc_curr;
/* event happening after cycle counter max value, pad */
if (next_event->value_cyc <= cyc_curr) {
cyc_evt += UINT32_MAX;
}
if (cyc_evt > 0) {
/* if there's no system wakeup event always wins,
* otherwise, who comes earlier wins
*/
if (cyc < 0) {
cyc = cyc_evt;
} else {
cyc = MIN(cyc, cyc_evt);
}
}
}
for (int16_t i = (int16_t)num_cpu_states - 1; i >= 0; i--) { for (int16_t i = (int16_t)num_cpu_states - 1; i >= 0; i--) {
const struct pm_state_info *state = &cpu_states[i]; const struct pm_state_info *state = &cpu_states[i];
uint32_t min_residency_cyc, exit_latency_cyc; uint32_t min_residency_cyc, exit_latency_cyc;

View file

@ -304,68 +304,36 @@ ZTEST(policy_api, test_pm_policy_next_state_custom)
} }
#endif /* CONFIG_PM_POLICY_CUSTOM */ #endif /* CONFIG_PM_POLICY_CUSTOM */
#ifdef CONFIG_PM_POLICY_DEFAULT
/* note: we can't easily mock k_cycle_get_32(), so test is not ideal */
ZTEST(policy_api, test_pm_policy_events) ZTEST(policy_api, test_pm_policy_events)
{ {
struct pm_policy_event evt1, evt2; struct pm_policy_event evt1;
const struct pm_state_info *next; struct pm_policy_event evt2;
uint32_t now; uint32_t now_cycle;
uint32_t evt1_1_cycle;
uint32_t evt1_2_cycle;
uint32_t evt2_cycle;
now = k_cyc_to_ticks_ceil32(k_cycle_get_32()); now_cycle = k_cycle_get_32();
evt1_1_cycle = now_cycle + k_ticks_to_cyc_floor32(100);
evt1_2_cycle = now_cycle + k_ticks_to_cyc_floor32(200);
evt2_cycle = now_cycle + k_ticks_to_cyc_floor32(2000);
/* events: zassert_equal(pm_policy_next_event_ticks(), -1);
* - 10ms from now (time < runtime idle latency) pm_policy_event_register(&evt1, evt1_1_cycle);
* - 200ms from now (time > runtime idle, < suspend to ram latencies) pm_policy_event_register(&evt2, evt2_cycle);
* zassert_within(pm_policy_next_event_ticks(), 100, 50);
* system wakeup:
* - 2s from now (time > suspend to ram latency)
*
* first event wins, so we must stay active
*/
pm_policy_event_register(&evt1, k_ms_to_cyc_floor32(10) + k_cycle_get_32());
pm_policy_event_register(&evt2, k_ms_to_cyc_floor32(200) + k_cycle_get_32());
next = pm_policy_next_state(0U, now + k_sec_to_ticks_floor32(2));
zassert_is_null(next);
/* remove first event so second event now wins, meaning we can now enter
* runtime idle
*/
pm_policy_event_unregister(&evt1); pm_policy_event_unregister(&evt1);
next = pm_policy_next_state(0U, now + k_sec_to_ticks_floor32(2)); zassert_within(pm_policy_next_event_ticks(), 2000, 50);
zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
/* remove second event, now we can enter deepest state */
pm_policy_event_unregister(&evt2); pm_policy_event_unregister(&evt2);
next = pm_policy_next_state(0U, now + k_sec_to_ticks_floor32(2)); zassert_equal(pm_policy_next_event_ticks(), -1);
zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM); pm_policy_event_register(&evt2, evt2_cycle);
zassert_within(pm_policy_next_event_ticks(), 2000, 50);
/* events: pm_policy_event_register(&evt1, evt1_1_cycle);
* - 2s from now (time > suspend to ram latency) zassert_within(pm_policy_next_event_ticks(), 100, 50);
* pm_policy_event_update(&evt1, evt1_2_cycle);
* system wakeup: zassert_within(pm_policy_next_event_ticks(), 200, 50);
* - 200ms from now (time > runtime idle, < suspend to ram latencies)
*
* system wakeup wins, so we can go up to runtime idle.
*/
pm_policy_event_register(&evt1, k_sec_to_cyc_floor32(2) + k_cycle_get_32());
next = pm_policy_next_state(0U, now + k_ms_to_ticks_floor32(200));
zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
/* modify event to occur in 10ms, so it now wins system wakeup and
* requires to stay awake
*/
pm_policy_event_update(&evt1, k_ms_to_cyc_floor32(10) + k_cycle_get_32());
next = pm_policy_next_state(0U, now + k_ms_to_ticks_floor32(200));
zassert_is_null(next);
pm_policy_event_unregister(&evt1); pm_policy_event_unregister(&evt1);
pm_policy_event_unregister(&evt2);
} }
#else
ZTEST(policy_api, test_pm_policy_events)
{
ztest_test_skip();
}
#endif /* CONFIG_PM_POLICY_CUSTOM */
ZTEST_SUITE(policy_api, NULL, NULL, NULL, NULL, NULL); ZTEST_SUITE(policy_api, NULL, NULL, NULL, NULL, NULL);