Skip to content

Commit d3833b0

Browse files
committed
server : keep the tokens a recompute restore replays out of the request's prompt stats
A recompute restore re-enters prompt processing to put back the cells the park dropped. Those tokens are submitted with is_prompt set, so every one of them was added to n_prompt_processed and pushed t_prompt_last to the end of the replay, while n_gen deliberately carries across the park. The reported prompt length grew with every park, and the generation time covered only the tokens after the last re-prefill, so predicted_per_second was inflated by the ratio of the two. The replay is still counted in the server-wide prompt metrics, where it is real compute; it just no longer moves the slot's prompt count or the prompt/generation boundary.
1 parent 9bcd8ab commit d3833b0

2 files changed

Lines changed: 30 additions & 4 deletions

File tree

tools/server/server-context.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5177,8 +5177,12 @@ struct server_context_impl {
51775177
}
51785178

51795179
metrics_queue_prompt(n_tokens_out);
5180-
slot.stats.n_prompt_processed += n_tokens_out;
5181-
slot.stats.update_prompt_last();
5180+
5181+
// [TAG_PREEMPT] a re-prefill puts back what a park dropped: real compute, counted above, but it is not the request's prompt
5182+
if (!slot.preempt_reprefill) {
5183+
slot.stats.n_prompt_processed += n_tokens_out;
5184+
slot.stats.update_prompt_last();
5185+
}
51825186

51835187
// add the mtmd chunk to cache
51845188
{
@@ -5918,7 +5922,8 @@ struct server_context_impl {
59185922
n_prompt_tokens++;
59195923

59205924
auto & slot = slots[t.id_slot];
5921-
if (slot.stats.is_set()) {
5925+
// [TAG_PREEMPT] replayed tokens stay out of the slot's prompt count, they were counted when the request first processed its prompt
5926+
if (slot.stats.is_set() && !slot.preempt_reprefill) {
59225927
slot.stats.n_prompt_processed++;
59235928
}
59245929
}
@@ -5936,7 +5941,8 @@ struct server_context_impl {
59365941
for (int i = off; i < off + n_tokens; ++i) {
59375942
const auto & t = batch.tokens[i];
59385943
auto & slot = slots[t.id_slot];
5939-
if (t.is_prompt && slot.stats.is_set()) {
5944+
// [TAG_PREEMPT] a re-prefill must not move the prompt/generation boundary: n_gen carries across the park, so the generation time would then cover only the tokens after it
5945+
if (t.is_prompt && slot.stats.is_set() && !slot.preempt_reprefill) {
59405946
slot.stats.set_prompt_last(t_now);
59415947
}
59425948
}

tools/server/tests/unit/test_preempt.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,26 @@ def test_a_recompute_park_is_reported_to_the_client_and_to_metrics():
878878
assert plain.body["preempt"] == {"parks": 0, "recomputes": 0}
879879

880880

881+
def test_a_recompute_restore_does_not_count_its_replay_as_prompt():
882+
# the re-prefill puts back what the park dropped: counted as prompt it would move the prompt/generation boundary, and since n_gen carries across the park the generation time would then cover only the tokens after the last re-prefill
883+
os.environ["LLAMA_ARG_PREEMPT_RAM"] = "1"
884+
os.environ["LLAMA_SERVER_PREEMPT_EVERY"] = "8"
885+
_start(n_ctx=2048, n_batch=2048)
886+
887+
n_prompt = 1950
888+
n_predict = 24
889+
res = _complete(n_predict, _prompt_of(n_prompt, _PROMPT_C))
890+
891+
assert res.status_code == 200, res.body
892+
assert res.body["preempt"]["recomputes"] >= 1, res.body["preempt"]
893+
894+
timings = res.body["timings"]
895+
assert timings["prompt_n"] == n_prompt, timings
896+
assert timings["predicted_n"] == n_predict, timings
897+
# every re-prefill happens inside the generation, so the generation holds the longer time of the two
898+
assert timings["predicted_ms"] > timings["prompt_ms"], timings
899+
900+
881901
def test_slots_reports_the_recomputes_of_the_current_task():
882902
# a reader watching the slots sees the same count the request is given at the end
883903
os.environ["LLAMA_ARG_PREEMPT_RAM"] = "1"

0 commit comments

Comments
 (0)