@@ -1595,6 +1595,200 @@ void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)
15951595 update_curr_dl_se (dl_se -> rq , dl_se , delta_exec );
15961596}
15971597
1598+ /*
1599+ * dl_server && dl_defer:
1600+ *
1601+ * 6
1602+ * +--------------------+
1603+ * v |
1604+ * +-------------+ 4 +-----------+ 5 +------------------+
1605+ * +-> | A:init | <--- | D:running | -----> | E:replenish-wait |
1606+ * | +-------------+ +-----------+ +------------------+
1607+ * | | | 1 ^ ^ |
1608+ * | | 1 +----------+ | 3 |
1609+ * | v | |
1610+ * | +--------------------------------+ 2 |
1611+ * | | | ----+ |
1612+ * | 8 | B:zero_laxity-wait | | |
1613+ * | | | <---+ |
1614+ * | +--------------------------------+ |
1615+ * | | ^ ^ 2 |
1616+ * | | 7 | 2 +--------------------+
1617+ * | v |
1618+ * | +-------------+ |
1619+ * +-- | C:idle-wait | -+
1620+ * +-------------+
1621+ * ^ 7 |
1622+ * +---------+
1623+ *
1624+ *
1625+ * [A] - init
1626+ * dl_server_active = 0
1627+ * dl_throttled = 0
1628+ * dl_defer_armed = 0
1629+ * dl_defer_running = 0/1
1630+ * dl_defer_idle = 0
1631+ *
1632+ * [B] - zero_laxity-wait
1633+ * dl_server_active = 1
1634+ * dl_throttled = 1
1635+ * dl_defer_armed = 1
1636+ * dl_defer_running = 0
1637+ * dl_defer_idle = 0
1638+ *
1639+ * [C] - idle-wait
1640+ * dl_server_active = 1
1641+ * dl_throttled = 1
1642+ * dl_defer_armed = 1
1643+ * dl_defer_running = 0
1644+ * dl_defer_idle = 1
1645+ *
1646+ * [D] - running
1647+ * dl_server_active = 1
1648+ * dl_throttled = 0
1649+ * dl_defer_armed = 0
1650+ * dl_defer_running = 1
1651+ * dl_defer_idle = 0
1652+ *
1653+ * [E] - replenish-wait
1654+ * dl_server_active = 1
1655+ * dl_throttled = 1
1656+ * dl_defer_armed = 0
1657+ * dl_defer_running = 1
1658+ * dl_defer_idle = 0
1659+ *
1660+ *
1661+ * [1] A->B, A->D
1662+ * dl_server_start()
1663+ * dl_server_active = 1;
1664+ * enqueue_dl_entity()
1665+ * update_dl_entity(WAKEUP)
1666+ * if (!dl_defer_running)
1667+ * dl_defer_armed = 1;
1668+ * dl_throttled = 1;
1669+ * if (dl_throttled && start_dl_timer())
1670+ * return; // [B]
1671+ * __enqueue_dl_entity();
1672+ * // [D]
1673+ *
1674+ * // deplete server runtime from client-class
1675+ * [2] B->B, C->B, E->B
1676+ * dl_server_update()
1677+ * update_curr_dl_se() // idle = false
1678+ * if (dl_defer_idle)
1679+ * dl_defer_idle = 0;
1680+ * if (dl_defer && dl_throttled && dl_runtime_exceeded())
1681+ * dl_defer_running = 0;
1682+ * hrtimer_try_to_cancel(); // stop timer
1683+ * replenish_dl_new_period()
1684+ * // fwd period
1685+ * dl_throttled = 1;
1686+ * dl_defer_armed = 1;
1687+ * start_dl_timer(); // restart timer
1688+ * // [B]
1689+ *
1690+ * // timer actually fires means we have runtime
1691+ * [3] B->D
1692+ * dl_server_timer()
1693+ * if (dl_defer_armed)
1694+ * dl_defer_running = 1;
1695+ * enqueue_dl_entity(REPLENISH)
1696+ * replenish_dl_entity()
1697+ * // fwd period
1698+ * if (dl_throttled)
1699+ * dl_throttled = 0;
1700+ * if (dl_defer_armed)
1701+ * dl_defer_armed = 0;
1702+ * __enqueue_dl_entity();
1703+ * // [D]
1704+ *
1705+ * // schedule server
1706+ * [4] D->A
1707+ * pick_task_dl()
1708+ * p = server_pick_task();
1709+ * if (!p)
1710+ * dl_server_stop()
1711+ * dequeue_dl_entity();
1712+ * hrtimer_try_to_cancel();
1713+ * dl_defer_armed = 0;
1714+ * dl_throttled = 0;
1715+ * dl_server_active = 0;
1716+ * // [A]
1717+ * return p;
1718+ *
1719+ * // server running
1720+ * [5] D->E
1721+ * update_curr_dl_se()
1722+ * if (dl_runtime_exceeded())
1723+ * dl_throttled = 1;
1724+ * dequeue_dl_entity();
1725+ * start_dl_timer();
1726+ * // [E]
1727+ *
1728+ * // server replenished
1729+ * [6] E->D
1730+ * dl_server_timer()
1731+ * enqueue_dl_entity(REPLENISH)
1732+ * replenish_dl_entity()
1733+ * fwd-period
1734+ * if (dl_throttled)
1735+ * dl_throttled = 0;
1736+ * __enqueue_dl_entity();
1737+ * // [D]
1738+ *
1739+ * // deplete server runtime from idle
1740+ * [7] B->C, C->C
1741+ * dl_server_update_idle()
1742+ * update_curr_dl_se() // idle = true
1743+ * if (dl_defer && dl_throttled && dl_runtime_exceeded())
1744+ * if (dl_defer_idle)
1745+ * return;
1746+ * dl_defer_running = 0;
1747+ * hrtimer_try_to_cancel();
1748+ * replenish_dl_new_period()
1749+ * // fwd period
1750+ * dl_throttled = 1;
1751+ * dl_defer_armed = 1;
1752+ * dl_defer_idle = 1;
1753+ * start_dl_timer(); // restart timer
1754+ * // [C]
1755+ *
1756+ * // stop idle server
1757+ * [8] C->A
1758+ * dl_server_timer()
1759+ * if (dl_defer_idle)
1760+ * dl_server_stop();
1761+ * // [A]
1762+ *
1763+ *
1764+ * digraph dl_server {
1765+ * "A:init" -> "B:zero_laxity-wait" [label="1:dl_server_start"]
1766+ * "A:init" -> "D:running" [label="1:dl_server_start"]
1767+ * "B:zero_laxity-wait" -> "B:zero_laxity-wait" [label="2:dl_server_update"]
1768+ * "B:zero_laxity-wait" -> "C:idle-wait" [label="7:dl_server_update_idle"]
1769+ * "B:zero_laxity-wait" -> "D:running" [label="3:dl_server_timer"]
1770+ * "C:idle-wait" -> "A:init" [label="8:dl_server_timer"]
1771+ * "C:idle-wait" -> "B:zero_laxity-wait" [label="2:dl_server_update"]
1772+ * "C:idle-wait" -> "C:idle-wait" [label="7:dl_server_update_idle"]
1773+ * "D:running" -> "A:init" [label="4:pick_task_dl"]
1774+ * "D:running" -> "E:replenish-wait" [label="5:update_curr_dl_se"]
1775+ * "E:replenish-wait" -> "B:zero_laxity-wait" [label="2:dl_server_update"]
1776+ * "E:replenish-wait" -> "D:running" [label="6:dl_server_timer"]
1777+ * }
1778+ *
1779+ *
1780+ * Notes:
1781+ *
1782+ * - When there are fair tasks running the most likely loop is [2]->[2].
1783+ * the dl_server never actually runs, the timer never fires.
1784+ *
1785+ * - When there is actual fair starvation; the timer fires and starts the
1786+ * dl_server. This will then throttle and replenish like a normal DL
1787+ * task. Notably it will not 'defer' again.
1788+ *
1789+ * - When idle it will push the actication forward once, and then wait
1790+ * for the timer to hit or a non-idle update to restart things.
1791+ */
15981792void dl_server_start (struct sched_dl_entity * dl_se )
15991793{
16001794 struct rq * rq = dl_se -> rq ;
0 commit comments