release: v2.11.0 — deep sweep: crash fixes, data-correctness fixes, perf overhaul, settings persistence#75
Merged
Merged
Conversation
…; apply dark visuals once at startup; surface loader-thread panics as an error toast instead of hanging in Loading state
…2 files panicked with index out of bounds; also route parser debug output through tracing instead of eprintln
…sults attached to the wrong file after deletion
…ith Vehicle Speed in the reverse map, making normalization nondeterministic across launches
… unparseable values previously compacted the row left, misaligning every later column; now last-known-value is substituted like the ECUMaster parser
…, field normalization, cursor tracking, auto-update check, and custom channel mappings — previously all of these silently reset every launch; synced via eframe's auto-save hook
…quantized viewport — the O(samples) downsample previously re-ran for every channel every frame; now it only recomputes when the anchored bucket grid shifts. Cache is invalidated on file removal and computed-channel deletion (minmax cache too, same index-shift staleness)
…ening a second file while one was loading silently lost the first; multi-file drag-drop now loads every file instead of only the first. Also add documented-but-missing shortcuts: Esc stops playback, Cmd+E exports the current view as PNG
…lug before writing spec cache files — a hostile or corrupt API response could otherwise escape the cache directory via path separators
…sions crossing midnight produced non-monotonic times, breaking the binary search used by time-shifted computed channels
…ously two full channel copies plus a 512x512 histogram rebuild ran every frame; now only on selection change
… rollover and speeduino truncated v2 header
…/ipc/mcp modules, all 14 parsers, new UI panels, settings-persistence and cache-invalidation contracts, keyboard shortcuts, current dependencies
There was a problem hiding this comment.
Pull request overview
Pre-release sweep for v2.11.0 focused on improving robustness (parser crash/correctness fixes), reducing per-frame CPU cost via caching and event-driven IPC, and persisting user-facing preferences across restarts.
Changes:
- Added regression tests for Speeduino truncated v2 headers and Haltech column-alignment + midnight rollover cases.
- Implemented settings persistence (new
UserSettingsfields +eframe::App::savesynchronization) and converted several preference types toSerialize/Deserialize. - Introduced performance-oriented caches: chart downsample caching keyed by a quantized viewport key, and a cached scatter-heatmap histogram built once per axis selection; replaced IPC polling repaint with a repaint callback.
Reviewed changes
Copilot reviewed 19 out of 20 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/parsers/speeduino_tests.rs | Adds regression test ensuring truncated v2 headers error instead of panicking. |
| tests/parsers/haltech_tests.rs | Adds regression tests for Haltech unparseable-field alignment and midnight rollover monotonicity. |
| tests/core/settings_tests.rs | Updates settings tests to include new persisted fields via ..UserSettings::default(). |
| src/units.rs | Makes unit preference enums/struct serializable for persistence. |
| src/ui/scatter_plot.rs | Caches scatter heatmap histograms per (file, x, y) to avoid rebuilding every frame. |
| src/ui/histogram.rs.backup | Removes stale backup file from the repo. |
| src/ui/export.rs.bak | Removes stale backup file from the repo. |
| src/ui/chart.rs | Adds per-channel downsample caching keyed by a quantized viewport key; reduces per-frame downsample work. |
| src/state.rs | Introduces cache types (DownsampleCache, ScatterHistogramCache) and DownsampleViewKey; makes FontScale serializable. |
| src/settings.rs | Expands UserSettings for persisted preferences (units, font scale, normalization, etc.) and derives PartialEq for change detection. |
| src/parsers/speeduino.rs | Adds explicit v2 header truncation check and migrates debug output to tracing. |
| src/parsers/haltech.rs | Preserves column alignment by using last-known-value substitution; adds midnight rollover handling for monotonic times. |
| src/normalize.rs | Removes ambiguous "Speed" alias from RPM normalization map to avoid nondeterministic collisions. |
| src/ipc/server.rs | Adds repaint callback to wake the GUI on command arrival (event-driven IPC). |
| src/ipc/handler.rs | Clears chart caches when computed channels are removed to avoid index-based cache staleness. |
| src/app.rs | Applies dark theme once at startup, queues file loads, improves loader disconnect handling, persists settings on save, and switches IPC handling to event-driven repaint. |
| src/adapters/cache.rs | Sanitizes API-supplied vendor/id into a filename-safe slug to harden cache writes against path traversal. |
| CLAUDE.md | Updates architecture/developer documentation to match current modules and new persistence + caching contracts. |
| Cargo.toml | Bumps version to 2.11.0 and sets codegen-units = 1 for release builds. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+888
to
+916
| // Derive the cache key for this viewport. The bucketed downsampler | ||
| // below is anchored to a fixed grid, so its output only changes when | ||
| // the first bucket index or the bucket width changes — steady frames | ||
| // (idle, cursor moves within a bucket) reuse the cached points. | ||
| let n_buckets = (MAX_CHART_POINTS / 2).max(1); | ||
| let view_key = match viewport { | ||
| Some((vmin, vmax)) if vmax > vmin => { | ||
| let pad = (vmax - vmin) * 0.1; | ||
| let padded_span = (vmax - vmin) + 2.0 * pad; | ||
| let bucket_size = padded_span / n_buckets as f64; | ||
| if bucket_size <= 0.0 { | ||
| DownsampleViewKey::Full | ||
| } else { | ||
| let raw_lo = vmin - pad; | ||
| DownsampleViewKey::Bucketed { | ||
| k_lo: (raw_lo / bucket_size).floor() as i64, | ||
| bucket_bits: bucket_size.to_bits(), | ||
| } | ||
| } | ||
| } | ||
| _ => DownsampleViewKey::Full, | ||
| }; | ||
|
|
||
| if let Some((cached_key, points)) = self.downsample_cache.get(&(file_index, channel_index)) | ||
| { | ||
| if *cached_key == view_key { | ||
| return Some(points.clone()); | ||
| } | ||
| } |
Collaborator
Author
There was a problem hiding this comment.
Addressed in 05e0c99 — the cache key now includes plot_area_id, so a channel shown in two stacked plots with different viewports keeps separate entries instead of evicting itself each frame.
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.
Summary
Deep sweep of the app ahead of v2.11.0: crash and data-correctness fixes across the parsers and app state, a per-frame performance overhaul, settings persistence, dependency refresh, and a CLAUDE.md rewrite to match the current codebase.
Bug fixes
eprintln!totracing.N/A, text gears) compacted the row left, misaligning every later column — now filled with last-known-value like the ECUMaster parser.RPM@-0.1s).Speednormalized to RPM or Vehicle Speed nondeterministically per launch (HashMap iteration-order collision); ambiguous RPM alias removed.analysis_resultswere not reindexed on file removal, attaching cached analyses to the wrong file.Performance
codegen-units = 1for release builds.Features
Escstops playback,Cmd+Eexports the current view as PNG.Chores
cargo update; stale.bakfiles removed fromsrc/ui/; version bumped to 2.11.0.Test plan
cargo fmt --all -- --checkandcargo clippy -- -D warningsclean.Deferred (follow-ups, not in this PR)