Conversation
Clients written for llama-server read per-request speeds from a top-level `timings` object, which TabbyAPI does not emit, so they show nothing even though the same figures are in the finish chunk (theroyallab#454). Build `timings` from the finish chunk that `get_usage_stats` already reads, with llama.cpp's keys and semantics (server_slot_stats::to_json): prompt_n excludes cached tokens, and the draft keys are present only when draft tokens were produced. Generation rates divide by gen_tokens rather than llama.cpp's n_gen - 1: exllamav3 stamps the start of generation before the decode pass that produces the first token, so gen_time already spans every generated token. Attach it top-level on non-streaming chat and text completions, and on the last chunk of a stream (the usage chunk with include_usage, otherwise the finish_reason chunk), for single-generation requests only. `usage` is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Is your pull request related to a problem? Please describe.
Part of #454. TabbyAPI has no top-level
timingsobject, so clients that read llama-server'stimings(llama-swap, benchmark tools) get no speed figures from it.Why should this feature be added?
The numbers are already in the finish chunk that
usagereads. This exposes them in llama.cpp's shape without changingusageor the backend.Examples
Test fixture: 1000 prompt tokens (900 cached), 50 generated in 1.2 s, draft 40 accepted / 8 rejected. Output of
get_timings:Where it goes:
/v1/chat/completionsand/v1/completions: top level.include_usage, and thefinish_reasonchunk without it.usagestill aggregates them.Additional context
Keys. They follow llama.cpp's
server_slot_stats::to_json.prompt_nexcludes cached tokens, as in llama.cpp, andusage.prompt_tokensis unchanged.draft_nanddraft_n_acceptedappear only when draft tokens were produced, matching llama.cpp'sn_draft_tokens > 0guard.Generation rate divides by
predicted_n, notn - 1. llama.cpp usesn_gen - 1because its first token comes from the last prompt batch, outside the generation time. exllamav3 works differently:time_first_tokenbefore the decode pass that produces the first token (generator.py#L638-L640).So
time_generate(job.py#L761) already covers every token.Measured directly on exllamav3 1.5.0 (no draft model, greedy, no stop conditions, fixed token counts, two runs each):
time_generate(s)One token costs one pass rather than zero, and ÷ n is flat. Current main agrees: a
max_tokens: 1chat request returns"completion_tokens": 1, "completion_time": 0.11. With ÷ n,predicted_per_secondalso matchesusage.completion_tokens_per_sec(the backend's owngen_tokens / gen_time), up to rounding.Resolution. Times keep the finish chunk's 10 ms rounding. Changing it would touch
handle_finish_chunk, which #443 also edits.Live check. Run against a server on main 53da791 and on this branch, with GLM-5.3-Flash EXL3 on exllamav3 1.5.0, torch 2.10.0+cu128, and an MTP draft:
include_usagetimingstimingsfinish_reasontimingsdraft_n51 / accepted 45n: 2timingstimings: nullinclude_usagetimingstimingsThat run used the
n - 1rate I started with. The switch to ÷ n came after the measurement above and is covered by unit tests.Tests.
tests/test_timings.pyhas 24 tests. It fails to import on main (cannot import name 'Timings') and passes on this branch. The async stream drivers need a loaded model, so their compose and serialize functions are tested instead.🤖 Generated with Claude Code