sched/deadline: Document dl_server

Place the notes that resulted from going through the dl_server code in a
comment.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
This commit is contained in:
Peter Zijlstra 2025-11-03 11:25:52 +01:00
parent f5a538c07d
commit 2614069c59
1 changed files with 194 additions and 0 deletions

View File

@ -1595,6 +1595,200 @@ void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)
update_curr_dl_se(dl_se->rq, dl_se, delta_exec);
}
/*
* dl_server && dl_defer:
*
* 6
* +--------------------+
* v |
* +-------------+ 4 +-----------+ 5 +------------------+
* +-> | A:init | <--- | D:running | -----> | E:replenish-wait |
* | +-------------+ +-----------+ +------------------+
* | | | 1 ^ ^ |
* | | 1 +----------+ | 3 |
* | v | |
* | +--------------------------------+ 2 |
* | | | ----+ |
* | 8 | B:zero_laxity-wait | | |
* | | | <---+ |
* | +--------------------------------+ |
* | | ^ ^ 2 |
* | | 7 | 2 +--------------------+
* | v |
* | +-------------+ |
* +-- | C:idle-wait | -+
* +-------------+
* ^ 7 |
* +---------+
*
*
* [A] - init
* dl_server_active = 0
* dl_throttled = 0
* dl_defer_armed = 0
* dl_defer_running = 0/1
* dl_defer_idle = 0
*
* [B] - zero_laxity-wait
* dl_server_active = 1
* dl_throttled = 1
* dl_defer_armed = 1
* dl_defer_running = 0
* dl_defer_idle = 0
*
* [C] - idle-wait
* dl_server_active = 1
* dl_throttled = 1
* dl_defer_armed = 1
* dl_defer_running = 0
* dl_defer_idle = 1
*
* [D] - running
* dl_server_active = 1
* dl_throttled = 0
* dl_defer_armed = 0
* dl_defer_running = 1
* dl_defer_idle = 0
*
* [E] - replenish-wait
* dl_server_active = 1
* dl_throttled = 1
* dl_defer_armed = 0
* dl_defer_running = 1
* dl_defer_idle = 0
*
*
* [1] A->B, A->D
* dl_server_start()
* dl_server_active = 1;
* enqueue_dl_entity()
* update_dl_entity(WAKEUP)
* if (!dl_defer_running)
* dl_defer_armed = 1;
* dl_throttled = 1;
* if (dl_throttled && start_dl_timer())
* return; // [B]
* __enqueue_dl_entity();
* // [D]
*
* // deplete server runtime from client-class
* [2] B->B, C->B, E->B
* dl_server_update()
* update_curr_dl_se() // idle = false
* if (dl_defer_idle)
* dl_defer_idle = 0;
* if (dl_defer && dl_throttled && dl_runtime_exceeded())
* dl_defer_running = 0;
* hrtimer_try_to_cancel(); // stop timer
* replenish_dl_new_period()
* // fwd period
* dl_throttled = 1;
* dl_defer_armed = 1;
* start_dl_timer(); // restart timer
* // [B]
*
* // timer actually fires means we have runtime
* [3] B->D
* dl_server_timer()
* if (dl_defer_armed)
* dl_defer_running = 1;
* enqueue_dl_entity(REPLENISH)
* replenish_dl_entity()
* // fwd period
* if (dl_throttled)
* dl_throttled = 0;
* if (dl_defer_armed)
* dl_defer_armed = 0;
* __enqueue_dl_entity();
* // [D]
*
* // schedule server
* [4] D->A
* pick_task_dl()
* p = server_pick_task();
* if (!p)
* dl_server_stop()
* dequeue_dl_entity();
* hrtimer_try_to_cancel();
* dl_defer_armed = 0;
* dl_throttled = 0;
* dl_server_active = 0;
* // [A]
* return p;
*
* // server running
* [5] D->E
* update_curr_dl_se()
* if (dl_runtime_exceeded())
* dl_throttled = 1;
* dequeue_dl_entity();
* start_dl_timer();
* // [E]
*
* // server replenished
* [6] E->D
* dl_server_timer()
* enqueue_dl_entity(REPLENISH)
* replenish_dl_entity()
* fwd-period
* if (dl_throttled)
* dl_throttled = 0;
* __enqueue_dl_entity();
* // [D]
*
* // deplete server runtime from idle
* [7] B->C, C->C
* dl_server_update_idle()
* update_curr_dl_se() // idle = true
* if (dl_defer && dl_throttled && dl_runtime_exceeded())
* if (dl_defer_idle)
* return;
* dl_defer_running = 0;
* hrtimer_try_to_cancel();
* replenish_dl_new_period()
* // fwd period
* dl_throttled = 1;
* dl_defer_armed = 1;
* dl_defer_idle = 1;
* start_dl_timer(); // restart timer
* // [C]
*
* // stop idle server
* [8] C->A
* dl_server_timer()
* if (dl_defer_idle)
* dl_server_stop();
* // [A]
*
*
* digraph dl_server {
* "A:init" -> "B:zero_laxity-wait" [label="1:dl_server_start"]
* "A:init" -> "D:running" [label="1:dl_server_start"]
* "B:zero_laxity-wait" -> "B:zero_laxity-wait" [label="2:dl_server_update"]
* "B:zero_laxity-wait" -> "C:idle-wait" [label="7:dl_server_update_idle"]
* "B:zero_laxity-wait" -> "D:running" [label="3:dl_server_timer"]
* "C:idle-wait" -> "A:init" [label="8:dl_server_timer"]
* "C:idle-wait" -> "B:zero_laxity-wait" [label="2:dl_server_update"]
* "C:idle-wait" -> "C:idle-wait" [label="7:dl_server_update_idle"]
* "D:running" -> "A:init" [label="4:pick_task_dl"]
* "D:running" -> "E:replenish-wait" [label="5:update_curr_dl_se"]
* "E:replenish-wait" -> "B:zero_laxity-wait" [label="2:dl_server_update"]
* "E:replenish-wait" -> "D:running" [label="6:dl_server_timer"]
* }
*
*
* Notes:
*
* - When there are fair tasks running the most likely loop is [2]->[2].
* the dl_server never actually runs, the timer never fires.
*
* - When there is actual fair starvation; the timer fires and starts the
* dl_server. This will then throttle and replenish like a normal DL
* task. Notably it will not 'defer' again.
*
* - When idle it will push the actication forward once, and then wait
* for the timer to hit or a non-idle update to restart things.
*/
void dl_server_start(struct sched_dl_entity *dl_se)
{
struct rq *rq = dl_se->rq;