Smoother progress reporting #19

Merged
maleszka merged 16 commits from feature/smooth-progress into main 2026-07-06 21:36:56 +02:00
Owner
  • increased rendering cadence to 4Hz (every 250ms)
  • exponential moving average for speed multiplier and download speed over last 3s
  • decoupled rendering from download cadence
- increased rendering cadence to 4Hz (every 250ms) - exponential moving average for speed multiplier and download speed over last 3s - decoupled rendering from download cadence
Replaces the 256 KiB PROGRESS_INTERVAL gate in write_stream with a 250ms
PROGRESS_TICK wall-clock gate, so displayed position/percentage advances
~4x/sec instead of jumping in large uneven steps tied to the flat 320kbps
byte-rate assumption.
next_tick_deadline now returns a fixed worker::PROGRESS_TICK whenever any
entry is Downloading, replacing the per-entry percent-granularity math that
derived redraw timing from the same since-start average being displayed —
removing the compounding jitter that produced.
A retried Stage 1 attempt (or any other out-of-order progress message) must
never make the displayed byte count visibly regress within one continuous
Downloading period. A genuine mark_downloading transition still resets the
value freely, since that starts a new period.
write_stream's error path now carries bytes_written alongside the AppError,
and the retry closure in worker::run tracks the furthest offset any attempt
reached and feeds it forward as the next attempt's skip_bytes instead of
always restarting from the original resume offset. This stops the queue's
displayed progress from visibly regressing after a transient Stage 1 retry,
and re-downloads strictly less data on retry as a side effect.
New standalone type computing a byte-rate EMA from real inter-sample deltas
(3s time constant), decaying continuously with no hard sample expiry so it
cannot itself introduce a discontinuity the way a sliding window can. Not
yet wired into any call site.
DownloadSession now owns a per-entry SpeedTracker map, fed a real sample at
the single point each Progress arrives in handle_msg. Reset to a fresh
tracker whenever spawn_pending marks an entry Downloading (fresh start,
resume, or re-promotion), and removed on any terminal transition. Exposed
via a new speed_bps accessor; not yet consumed by the UI.
ProgressRenderer::render and render_with_prompt now take a speed_bps
accessor (DownloadSession::speed_bps at the one call site in
interactive.rs) instead of computing session_bytes / elapsed_ms inline —
the multiplier and kbps figure now read from the EMA fed by real Progress
samples rather than a growing-denominator average that decayed between
ticks and jumped on arrival.
Closes out the smooth-progress implementation plan's Task 8: a controlled-timing
test proving the speed-cap throttle plus SpeedTracker settle within 5% of the
target multiplier, and a retry test proving a mid-Stage-1 failure's backoff and
reconnect dead time causes at most a transient dip rather than a permanent bias.
Progressive-retry resume (Task 4) can advance skip_bytes past data still
sitting unflushed in BufWriter's internal buffer, letting the next
attempt's set_len zero-extend a hole into the raw bitstream. Flush before
reporting bytes_written on the read/write error paths so a retry only ever
resumes from durably on-disk bytes.
An entry scrolled out of view keeps accumulating real observe() samples
but stops getting tick() calls; when it scrolls back in, one tick() call
with a large dt would glide almost instantly to the current ema_bps and
integrate it across the whole gap, overshooting the real bytes achieved
if the rate dipped partway through. Cap dt per tick step so a long gap is
treated as one bounded catch-up rather than integrated in full.
Records the fixes landed in a939d9c and c36f91f: durable-flush tracking
on Stage 1 retry error paths, and a capped interpolation ceiling on
SpeedTracker::tick.
maleszka deleted branch feature/smooth-progress 2026-07-06 21:36:57 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
maleszka/librespot-dl!19
No description provided.