Repository navigation
Add Halidoscope for interactive trace and profiling visualization. - #9356
Open
parkerziegler wants to merge 92 commits into
Open
parkerziegler wants to merge 92 commits into
parkerziegler wants to merge 92 commits into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #9356 +/- ##
==========================================
+ Coverage 71.03% 71.14% +0.10%
==========================================
Files 262 263 +1
Lines 81073 81373 +300
Branches 19768 19825 +57
==========================================
+ Hits 57593 57892 +299
+ Misses 17512 17464 -48
- Partials 5968 6017 +49 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Member
|
@parkerziegler — some quick-to-fix clang-tidy diagnostics: |
parkerziegler
force-pushed
the
parkerziegler/halidoscope
branch
3 times, most recently
from
August 20, 2026 19:22
6b30e1b to
1061c18
Compare
alexreinking
force-pushed
the
parkerziegler/halidoscope
branch
from
August 24, 2026 19:22
e85bf54 to
df45af3
Compare
alexreinking
marked this pull request as ready for review
August 24, 2026 19:22
2 of 5 tasks
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
… Funcs on playback. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…th mode-specific renderers. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…formation by Func.
…the notion of producer-consumer in the original Halide paper. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
… there are no intervening loads. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
alexreinking
force-pushed
the
parkerziegler/halidoscope
branch
from
September 3, 2026 16:57
df45af3 to
8e4ba63
Compare
alexreinking
force-pushed
the
parkerziegler/halidoscope
branch
from
September 29, 2026 19:23
8e4ba63 to
e18cbcd
Compare
Member
|
Needs a skip for wasm with no threads |
Tracing emitted the begin produce/consume event in a LetStmt outside the ProducerConsumer node, but the end event at the end of the node's body. Later passes wrap the body of these nodes in a condition: skip stages guards producers of conditionally-used Funcs, and sliding window guards consumers during warm-up iterations. When the condition was false, the begin event fired with no matching end. Both events now go inside the body, so a skipped body emits neither. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a halide_trace_bounds_required trace event, enabled per Func with Func::trace_bounds_required() or for all Funcs with the trace_bounds_required target feature (included in trace_all). At each loop level where bounds inference defines the region of a Func required by its consumers, an event reports that region using the same .s0.<arg>.min/max symbols that bounds inference defines. Its parent is the innermost enclosing traced event. This lets trace consumers distinguish values that matter from values computed outside the required region (e.g. due to TailStrategy::RoundUp in a consumer), which may be computed from uninitialized memory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The profiler report turned colors off while printing the text performance warnings, but turned them back on before rendering the same warnings into the JSON output. On a color terminal, warnings containing SI-suffixed counts (e.g. "2097K") then carried raw escape codes into JSON strings, which made the JSON invalid. Keep colors off until the JSON warnings have been rendered too. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
On Windows the profiler's sampling thread can sleep longer than a short pipeline run, so the run gets no samples and the time-gated gather warning never fires. Double the work per run until the warning appears. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…egler/halidoscope
Lets the host choose the fd that JIT-compiled pipelines write binary trace events to, applying to the shared runtime now and whenever it is created. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lidoscope - Trace through the runtime's binary trace writer into a zstd-compressed file, with a configurable size limit, and trace bounds_required events. - Write the profile via halide_profiler_set_json_output and accumulate it over the profiling runs with a ProfilerScope. - Rename HalidoscopeOptions fields (path, output_dir, profile_runs) and add trace_file_size_limit. - Add JITUserContext overloads of Pipeline::halidoscope. - Add Generator::halidoscope, which takes the same arguments as the Callable returned by compile_to_callable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Read zstd-compressed traces. - Show each realize/produce/consume node as a box covering the region it spans, using bounds_required events to exclude overcomputed values from value ranges. - Render inputs from their loads. - Add black/white point controls, slice selection for Funcs with more than two dims, and a hover probe showing the value under the cursor. - Show cumulative stats and warnings in the profile table. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Lets the host choose the fd that JIT-compiled pipelines write binary trace events to, applying to the shared runtime now and whenever it is created. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Key store/load/redundant/reuse/thread metrics on the full coordinate of multi-dimensional Funcs instead of (x, y, c), which aliased higher dims and made e.g. redundant-store views data-dependent. Metric views get the same slice sliders as value views. - Plot mode as SVG with zoom-scaled height and fixed on-screen stroke. - On-canvas slice sliders; RGB default only for extent 3 or 4. - Profile tab revamp: treemap, table, cross-tab Func context menu (now including render modes), profiler fields in the trace Funcs panel. - Deselect Func on background click; don't scroll on warning click. - Pause playback when leaving the trace tab; default to per-Func normalization; render-mode changes take effect during playback. - Make assembly text selectable in the stmt HTML. - Stmt tab and Generator::halidoscope plumbing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the zstd dependency with a small dependency-free codec for trace packets (tools/halide_trace_compression.h), shared by libHalide's trace writer and the Halidoscope GUI (via a C shim compiled with cc). Each word of a packet is predicted from the previous packet with the same size and parent, from earlier words in the packet, or from the last value seen at the same Func and coordinates, and the residual is range coded. It matches zstd -19 on bilateral_grid traces and compresses ~10-17x. The trace is split into independent 64 MB chunks whose headers record their decoded size, so chunks decode in parallel directly into one preallocated buffer. The runtime now zeroes packet padding so it compresses well. The GUI no longer copies trace data after decompression: packets are views into the decompressed words, parsed while later chunks are still decoding. Func names are interned, thread and producer lookups are inherited from the parent at parse time instead of walking parent chains afterwards, and per-Func access statistics are computed in parallel. Loading a 651 MB trace drops from 4.0s to 1.1s (raw) and 4.75s to 1.6s (compressed). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The thread palette was Set3, which has 12 colors, so elements written by any later thread rendered black, like untouched elements. Use Set3 for up to 12 threads and evenly spaced hues beyond that, computed in Rust and sent to the frontend so the legend matches. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reject chunks whose decoded size isn't a multiple of 4 or can't hold their packet count, which could misplace later chunks past the end of the output buffer. Reject decoded packet sizes that aren't a multiple of 4. In the GUI, allocate the decompressed trace fallibly and lazily zeroed, so a corrupt size claim reports an error instead of aborting. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drop the unused 64x64.png and strip the 512px and 1024px images from icon.icns, which accounted for most of the icon bytes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
abadams
force-pushed
the
parkerziegler/halidoscope
branch
from
October 7, 2026 20:15
e18cbcd to
bcb08a3
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The WebAssembly JIT supports neither the profiler (without wasm_threads) nor tracing to a file, so skip correctness_halidoscope there. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This branch has not been deployed
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.
This PR introduces Halidoscope, a new tool for interactively visualizing Halide traces and performance information captured by the Halide profiler.
Motivation
Understanding the performance characteristics of a Halide program (and, specifically, its schedule) can be tricky for experts and downright daunting for newer Halide developers. Today, the primary developer tooling we have to aid folks in understanding their Halide programs is
HalideTraceViz. WhileHalideTraceVizprovides good visual intuition for how a schedule executes, it doesn't provide much insight into how effectively a given schedule balances trade-offs in cache locality, redundant recomputation, and parallelism. Halidoscope attempts to fill this gap by:FuncStore / Load Frequency, Redundant Stores, Reuse Distance, and Thread CoverageNaNs /Infs, and real-time liveness information (e.g.,Funcbuffer liveness, active producer-consumer relationships)High-Level API
Halidoscope ships as both a GUI and CLI that can be invoked through a new
Pipeline::halidoscopemember function or directly from the command line.Calling Halidoscope via
Pipeline::halidoscopeHalide developers can launch Halidoscope via a call to
Pipeline::halidoscope(either in C++ or via the Python bindings) like so:Under the hood, the
Pipeline::halidoscopemember function will:Users can specify a
HalidoscopeOptionsstruct to control how Halidoscope executes with the following fields.halidoscope_pathstd::optional<std::string>$PATHand error if not found.halidoscope_output_dirstd::optional<std::string>.hltraceand profile JSON files to a temporary directory that is destroyed on process exit.halidoscope_profile_runsstd::optional<int>Calling Halidoscope from the command line
Users can also call launch Halidoscope directly from the command line, pointing it at a pre-recorded Halide trace binary and (optionally) a profile JSON file.
The Halidoscope CLI also comes with several commands (documented in the README.md and printable via
halidoscope --help) that can provide useful, high-level information on a trace (for both humans and agents).halidoscope list— List theFuncs in a trace, along with their dimensionality.halidoscope stats— Print statistics (minimum/maximum coordinates, minimum/maximum value, maximum store/load counts, and thread count) for one or allFuncs in a trace.halidoscope dot— Generate a Graphviz DOT representation of the pipeline's dataflow graph.halidoscope snapshot— Snapshot aFunc's values at a given packet index for a given render mode, writing the underlying data to a JSON file.Stack and High-Level Architecture
Halidoscope is a completely standalone Tauri application in
tools/halidoscope— it has no dependency on the Halide runtime.Warning
The only slight exception to this is our use of
bindgento derive Rust bindings forhalide_trace_packet_t, which ensures that our Rust packet parser always reads the correct offsets for Halide's packet format.bindgenis run at build-time against a user's local version of the Halide source. However, note that there is no actual runtime FFI between Halidoscope's Rust parser and the Halide runtime or C ABI.Backend
The Halidoscope backend is implemented in Rust and contains the following main modules:
trace.rs— Responsible for parsing a.hltracefile and accumulating trace-level statistics and metadata.render.rs— Computation supporting Halidoscope's render modes, where trace data is converted to RGBAVec<u8>buffers (for display) and binary payloads for histogram data andNaN/Infoverlayscommands.rs— Sets up the Tauri IPC API for communication with the frontend.cli.rs— Handles calls to the Halidoscope CLI.Communication is done entirely over IPC using Tauri commands.
Frontend
The frontend is implemented in TypeScript and React, using Jotai for state management and Tailwind for styling and CSS management. We use Vite as our frontend build system. This is about as standard a frontend stack as you'll find in modern web dev.
By default, Tauri uses a system's native WebView for rendering, which allows us to avoid bundling a full browser engine with the Halidoscope binary. Today, the Halidoscope binary weighs in at 10.5 MB uncompressed and 3.7 MB gzipped.
Breaking changes
No changes here are breaking; all changes are purely additive. Still, it is likely worth reviewing the additions to the
PipelineAPI a bit more carefully to confirm.Checklist