diff --git a/repos/os/src/test/timer/main.cc b/repos/os/src/test/timer/main.cc index cc2d0badda..d830253cad 100644 --- a/repos/os/src/test/timer/main.cc +++ b/repos/os/src/test/timer/main.cc @@ -68,16 +68,29 @@ struct Lazy_test struct Stress_test { + enum { DURATION_SEC = 10 }; + enum { MAX_SLV_PERIOD_US = 33000 }; + + struct Starvation : Exception { }; + struct Violation_of_timer_rate_limit : Exception { }; + struct Slave { + enum { DURATION_US = DURATION_SEC * 1000 * 1000 }; + enum { MIN_TIMER_PERIOD_US = 1000 }; + enum { MAX_CNT_BASE = DURATION_US / MIN_TIMER_PERIOD_US }; + enum { MAX_CNT_TOLERANCE = MAX_CNT_BASE / 10 }; + enum { MAX_CNT = MAX_CNT_BASE + MAX_CNT_TOLERANCE }; + enum { MIN_CNT = DURATION_US / MAX_SLV_PERIOD_US / 2 }; + Signal_handler timer_handler; Timer::Connection timer; - unsigned us; + unsigned long us; unsigned count { 0 }; - Slave(Env &env, unsigned ms) + Slave(Env &env, unsigned us) : timer_handler(env.ep(), *this, &Slave::handle_timer), - timer(env), us(ms * 1000) { timer.sigh(timer_handler); } + timer(env), us(us) { timer.sigh(timer_handler); } virtual ~Slave() { } @@ -87,9 +100,26 @@ struct Stress_test timer.trigger_once(us); } - void dump() { - log("timer (period ", us / 1000, " ms) triggered ", count, - " times -> slept ", (us / 1000) * count, " ms"); } + void dump() + { + log("timer (period ", us, " us) triggered ", count, + " times (min ", (unsigned)MIN_CNT, + " max ", (unsigned)MAX_CNT, ") -> slept ", + ((unsigned long)us * count) / 1000, " ms"); + + /* detect starvation of timeouts */ + if (count < MIN_CNT) { + error("triggered less than ", (unsigned)MIN_CNT, + " times"); + throw Starvation(); + } + /* detect violation of timer rate limitation */ + if (count > MAX_CNT) { + error("triggered more than ", (unsigned)MAX_CNT, + " times"); + throw Violation_of_timer_rate_limit(); + } + } void start() { timer.trigger_once(us); } void stop() { timer.sigh(Signal_context_capability()); } @@ -105,11 +135,10 @@ struct Stress_test void handle() { - enum { MAX_COUNT = 10 }; - if (count < MAX_COUNT) { + if (count < DURATION_SEC) { count++; - log("wait ", count, "/", (unsigned)MAX_COUNT); - timer.trigger_once(1000 * 1000); + log("wait ", count, "/", (unsigned)DURATION_SEC); + timer.trigger_once(1000UL * 1000); } else { slaves.for_each([&] (Slave &timer) { timer.stop(); }); slaves.for_each([&] (Slave &timer) { timer.dump(); }); @@ -120,8 +149,12 @@ struct Stress_test Stress_test(Env &env, Signal_context_capability done) : env(env), done(done) { timer.sigh(handler); - for (unsigned ms = 1; ms < 28; ms++) { - new (heap) Registered(slaves, env, ms); } + + for (unsigned long us_1 = 1; us_1 < MAX_SLV_PERIOD_US; us_1 *= 2) { + new (heap) Registered(slaves, env, us_1 - us_1 / 3); + new (heap) Registered(slaves, env, us_1); + } + slaves.for_each([&] (Slave &slv) { slv.start(); }); timer.trigger_once(1000 * 1000); }