1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
//! Which waiting job to admit next, when several are waiting.
//!
//! Admission was strict FIFO, for a reason this module has to answer
//! rather than ignore. From the batcher's own notes:
//!
//! > A skip-ahead policy ("admit the next job that fits") raises
//! > utilization and can starve a large request indefinitely behind a
//! > stream of small ones -- a queue that reorders by size
//! > systematically punishes exactly the requests that already wait
//! > longest. FIFO cannot starve, so FIFO it is until there is a
//! > measured reason to change it.
//!
//! Both halves of that stand. What follows does not reorder by SIZE,
//! and it cannot starve.
//!
//! # What it reorders by, and why that is not the same objection
//!
//! The radix prefix cache already knows how much of an incoming prompt
//! is already computed. Nothing read that at admission time, so a job
//! whose whole 6000-token system prompt is sitting in the page store
//! waited behind a job that has to prefill every token of its own.
//! Running the cached one first does not just reorder the work, it
//! REMOVES work: those pages are attended, not recomputed.
//!
//! Size-ordering punishes big requests because size is a property of
//! the request that never changes. Cache depth is a property of the
//! SERVER's state, and a job that loses today wins as soon as somebody
//! ahead of it publishes the prefix it shares -- which is the common
//! case, because jobs that share a prefix arrive together.
//!
//! # It cannot starve, and that is a test rather than an argument
//!
//! Two bounds, both hard:
//!
//! - a job may be passed over at most [`MAX_SKIPS`] times, after which
//! it is the head of the line and nothing may overtake it;
//! - only the first [`WINDOW`] waiting jobs are considered at all, so a
//! long queue cannot be scanned into a different order end to end.
//!
//! The first is what makes starvation impossible rather than unlikely:
//! a job's wait is bounded by `MAX_SKIPS` admissions, not by the
//! arrival pattern. `a_job_cannot_be_passed_over_forever` is that
//! bound, and it fails if either bound is removed.
//!
//! # The measured reason
//!
//! The bar the batcher set was a measurement, and the measurement is
//! not wall clock -- it is PREFILL TOKENS, counted, the same
//! acceptance number `n` > 1 is held to.
//!
//! With cache depths held FIXED a reordering saves nothing: the same
//! jobs, the same hits, a different order.
//! `reordering_alone_saves_nothing_when_hits_cannot_be_lost` says so,
//! because the first draft of that test asserted a saving and the
//! arithmetic did not agree.
//!
//! The saving is under PAGE PRESSURE, which is the state a busy server
//! is in: cached pages are evictable, so a job whose prefix is cached
//! now LOSES it if it waits behind enough uncached work to turn the
//! pool over. Admitting it first converts a hit that would have been
//! lost into a hit that is taken.
//! `under_eviction_pressure_the_policy_prefills_fewer_tokens` counts
//! that: 3000 prefill tokens on FIFO against 1200.
/// How many waiting jobs are looked at.
///
/// Small on purpose. The point is to let a cached job jump a short
/// queue of uncached ones, not to sort the whole backlog: scanning
/// further costs a radix walk per job per tick and buys less each
/// time, because the jobs deepest in the queue are the ones most
/// likely to have been overtaken already.
pub const WINDOW: usize = 8;
/// How many times a job may be passed over before it becomes
/// untouchable.
///
/// This is the anti-starvation bound and the only reason this policy
/// is admissible at all. At zero it is strict FIFO; at infinity it is
/// the starvation bug the batcher refused. Four is short enough that a
/// passed-over job is admitted within a handful of ticks and long
/// enough that a genuinely cached job usually gets through.
pub const MAX_SKIPS: u32 = 4;
/// The skip counter rides on the JOB, not in a parallel structure
/// here.
///
/// A deque of counters beside the waiting queue would have to agree
/// with it through four separate mutation sites -- the channel drain,
/// the idle-block receive, the abort pass that rebuilds the queue, and
/// admission itself -- which is exactly the two-structures-that-must-
/// agree shape this repo has fixed a dozen instances of. On the job it
/// moves with the job and cannot desync.
///
/// Both inputs below are therefore built per tick from the queue
/// itself, so they are the same length by construction.
/// Which waiting job to admit next, given how much of each one's
/// prompt is already computed.
///
/// Takes DEPTHS rather than jobs: the policy ranks numbers, and where
/// the numbers come from is the caller's business. That also makes
/// every case below testable without building a `Job`, which needs a
/// reply channel and an abort handle to exist at all.
///
/// Returns an index into `depths`. Always `0` when the head has been
/// passed over its limit, when the queue is one deep, or when no job
/// in the window has a strictly deeper hit than the head -- so the
/// ordinary case is FIFO and costs one comparison.
pub