Repository navigation
v2.6.14
简体中文: 查看本版本的中文更新日志
2.6.14 - 2026-10-10
Added
- Tokdash can now say how fast a model actually streamed, not only what it cost. A Model output speed page sits under Intelligence and answers from measured responses only: the rate is total matched output tokens over total matched duration, each response contributing its own clock, so two sessions running at once never borrow each other's time. Across models is a sortable table of model, tool, output tok/s, measured calls and call coverage; Time of day narrows to one model and lays its rate over the local clock by hour and in six-hour windows, each with the number of days behind it, which is where an afternoon slowdown stops being an impression. Every figure carries its denominator -- measured calls against eligible ones, and the dates measurements were actually recorded across, with the view's own range shown beside them -- because a rate over 40 measured calls and a rate over 40,000 of them should not read as the same kind of answer. The page also declines to imply what it does not know: a measured day is no proof of a complete log, since an idle day and a missing log look identical from here; a tool with usage in range but no timing is listed with its reason (that reader has no per-call timing yet, nothing matched in this range, or it is waiting for reprocessing) rather than dropping out of the table; and a How this is calculated disclosure states the duration window and the token basis in the same words the API returns. (#214)
- The same measurement reaches individual sessions. The Sessions tables gained an Output tok/s column for the selected date range, and a session you open carries an Output speed panel: a per-response chart or the response list behind it, a model picker for the sessions that used more than one model, and coverage stated as measured of total responses. It says so when a session mixes two kinds of duration, because those per-response figures stand alone rather than averaging into one number; a session with no matched timing explains why instead of reading as a zero; and an unfinished build reads as pending rather than empty. The column is cache-only by design, so reading a list of fifty sessions never queues fifty timing builds. (#214)
- Timing lives somewhere else on purpose. Nothing in ordinary ingestion, the Overview path or the core session reads extracts per-response timing or creates a timing database; the cache exists only once a speed view asks for it, as a second disposable
output_speed.sqlite3beside the usage database, built by a worker that gets a duty-cycle target (TOKDASH_SPEED_CPU_FRACTION, default0.25), an address-space limit (TOKDASH_SPEED_MEMORY_MB, default 1,024 MiB) and, on Linux, nice 10 and one core. It holds scalar measurements, verdicts and session membership rather than transcripts, publishes atomically so a reader can only ever see a whole snapshot, and fails per input scope so one unreadable session cannot poison an unrelated build. While a build runs, readers keep showing the last successful snapshot and follow its progress over server-sent events only while their page is visible; a build that fails keeps that snapshot and reports the failure. Model and hour aggregates are memoised per publication revision, filter set and local-clock identity (32 entries, 8 MiB of encoded results), and the Overview path never imports that cache at all. (#214) - Eight harnesses report throughput, each on the clock its own logs can actually support, with the exclusions named instead of estimated. Kimi pairs counted usage with a verified step-end decode duration (
server_decode). OMP and Qwen Code subtract time-to-first-token from a same-record duration (post_first_token). Codex and dsh measure a response window between explicit model items with the verified tool intervals clipped out of it (response_window), excluding missing owners, collapsed reasoning, unknown items, interruptions, compaction, output without a complete model-item clock, and retry-contaminated or unfinished steps. OpenCode, KiloCode and mimo give the whole request window from message creation to completion (request_window), which includes request overhead and awaited tools and is labelled as such, and excludes explicit errors, abnormal finishes, absent completions, invalid clocks and mimo's ensemble and replay messages, where one clock covers several calls. Groups keep their source, model, measurement kind and token basis, so two incompatible timing windows are never averaged into one rate. (#214)
Changed
- What the design costs is written down in
docs/development/benchmarks/OUTPUT_SPEED.mdnext to what it saves, including the parts of the bar it has not cleared. Moving timing out of ingestion is what makes a scoped build cheap -- one new Codex response built against 10,000 unrelated native sessions went from 29.2 s to 659 ms as signature observations fell from 10,003 to one, and an earlier publication fix took a 100,000-call build from 600,651 SQLite row changes and 41.1 s to 21 changes and 260 ms -- yet the same report records Overview refresh at 2,493 to 2,690 ms against the pre-feature release (a paired median overhead of 118 ms), a first complete model-page build still at 8.6 s on that fixture, a derived file of 98 MiB on it and 638 MiB on a real 309,823-response history whose full-window build the browser watched take 18.3 minutes, and an ordinary reopen afterwards that asked for another full build. Those two open criteria -- unchanged Overview performance under shared worker load, and acceptable ordinary reopening on real history -- stay listed as open in that document rather than being closed by green correctness checks, which is 3,721 tests, six skips and 150 Chromium assertions. Timing payloads written by an earlier pre-release build are dropped by the primary schema migration, and SQLite reuses those pages without the physical file shrinking on its own. (#214)