Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Reflex

A fast, GPU-accelerated CPU pipeline trace visualizer built with GPUI (Zed’s rendering framework).

Reflex displays instruction execution timelines, queue occupancy, performance counters, and pipeline stage progression from CPU simulator traces.

Features

  • Pipeline visualization — GPU-rendered instruction timeline with smooth panning, zooming, and scrolling at 60fps
  • Performance counters — Sparklines, heatmap overview, and numeric display for 200+ hardware counters
  • Minimap — Full-trace overview with draggable range selection and pipeline position indicator
  • Multicursor — Place multiple cursors to measure cycle deltas between pipeline events, with undo/redo
  • Queue panels — Live retire, dispatch, and issue queue occupancy at the cursor position
  • Timeline overlay — Counter sparkline strip above the pipeline view for correlation
  • Tabbed interface — Open multiple traces side-by-side with independent viewport state
  • Konata & µScope formats — Native support for Konata text traces and µScope binary traces
  • macOS & Linux — Native builds for both platforms

Quick Start

git clone --recurse-submodules <repo-url>
cargo run --release -- path/to/trace.uscope

Or drag and drop trace files onto the window.

Getting Started

Prerequisites

  • Rust (stable toolchain)
  • macOS or Linux (GPUI supports both)
  • Linux requires additional system libraries (see Building from Source)

Clone and Build

git clone --recurse-submodules https://github.com/zarubaf/reflex.git
cd reflex
cargo build --release

The --recurse-submodules flag is required because the µScope crate is included as a git submodule.

Opening a Trace

# Open a trace file directly
cargo run --release -- path/to/trace.uscope

# Start with an empty window
cargo run --release

You can also:

  • Drag and drop trace files onto the Reflex window
  • Use Cmd+O to open a file dialog
  • Use Cmd+G to generate a random test trace

First Steps

  1. Open a trace file — the pipeline view shows instruction execution timelines
  2. Scroll to pan, Ctrl+Scroll to zoom
  3. Click on the timeline to place the cursor and select an instruction
  4. Press Cmd+I to see trace metadata (format, clock, duration)
  5. Switch to the Counters tab to see performance counter data
  6. Press ? to see the full keyboard shortcut reference

Pipeline Viewer

The pipeline viewer is the main view in Reflex, showing instruction execution timelines as colored stage spans.

Layout

The pipeline viewer has three areas:

  • Label pane (left) — Instruction addresses and disassembly, with a resizable splitter
  • Timeline pane (right) — Canvas-rendered pipeline stages with cycle ruler header
  • Queue panels (bottom/left/right dock) — Retire, dispatch, and issue queue state

Stage Rendering

Each instruction occupies one row. Pipeline stages are rendered as colored rectangles:

  • Each stage has a unique color based on its position in the pipeline
  • Stage names (e.g., Al, Ds, Is, RdEx, Cp) are shown inside the rectangles when zoomed in
  • At low zoom levels, stages are rendered as thin colored bars for performance

Zoom and Pan

ActionEffect
Scroll / TrackpadPan horizontally and vertically
Ctrl + ScrollZoom in/out (both axes, preserving aspect ratio)
Cmd + = / Cmd + -Zoom in / out
Cmd + 0Zoom to fit (show entire trace)
Arrow keysPan in the corresponding direction

Zoom uses a focal-point model: the point under the cursor stays fixed while the view scales around it. Both horizontal (cycles) and vertical (rows) axes zoom together.

Row Selection

Click on an instruction row to select it. The selected row is highlighted, and its details appear in the queue panels and status bar.

  • j / k — Select next / previous instruction
  • The status bar shows: instruction count, cycle range, zoom level, selected instruction address, and cursor position

Tooltips

Hover over an instruction to see its annotations as a tooltip. Annotations come from the trace source and typically include operand details, execution metadata, and pipeline events.

Click vs Drag

  • Click (press + release without movement) — Selects the instruction row and places the cursor at the clicked cycle
  • Drag (press + move) — Pans the viewport without moving the cursor

This distinction prevents accidental cursor jumps during navigation.

Navigation & Cursors

Cursors

Reflex supports multiple cursors for measuring cycle distances between pipeline events.

Placing a Cursor

Click on the timeline to place the active cursor at that cycle. The cursor appears as a vertical line with a labeled head showing the cycle number.

Multicursor

KeyAction
Cmd+MAdd a new cursor at the current position
Cmd+Shift+MRemove the active cursor
[Switch to previous cursor
]Switch to next cursor

Each cursor has a distinct color from a built-in palette. When multiple cursors are placed, the header shows delta values between consecutive cursors.

Cursor Undo/Redo

All cursor operations (moving, adding, removing) are recorded in a history stack:

KeyAction
Cmd+ZUndo last cursor change
Cmd+Shift+ZRedo
Cmd+YRedo (alternative)

The history stores complete cursor state snapshots, so undoing an “add cursor” operation removes the cursor entirely, and undoing a “remove” restores it.

History is capped at 100 entries. New cursor movements clear the redo stack.

Press Cmd+F to open the search bar. Search matches against instruction disassembly text (addresses and mnemonics).

Go to Cycle

Press Cmd+L to open the “Go to Cycle” bar. Enter a cycle number to jump the viewport to that position.

Tab Navigation

KeyAction
Ctrl+TabNext tab
Ctrl+Shift+TabPrevious tab
Cmd+WClose current tab

Each tab has its own independent trace, viewport state, and cursor positions.

Performance Counters

Reflex can parse and display performance counters from µScope traces. Counters track metrics like committed instructions, cache misses, branch mispredictions, and stall cycles.

How Counters Are Detected

Counters are automatically detected from the µScope trace schema. A storage is recognized as a counter if it has:

  • Exactly 1 slot (dense, not sparse)
  • A single U64 field
  • Values updated via DA_SLOT_ADD (incremental additions)

Common counters include committed_insns, cycles, retired_insns, mispredicts, dcache_misses, icache_misses.

Counter Panel

Switch to the Counters tab (next to Pipeline Viewer) to see the counter panel. It has two view modes, toggled by clicking the mode button in the header.

Detail Mode

Shows each counter as a row with:

  • Mode indicator (T/R/D) — click to cycle between display modes
  • Counter name
  • Value at cursor — numeric value at the current cursor position
  • Sparkline — min-max envelope visualization below each counter

Heatmap Mode

Shows all counters as a compact matrix:

  • One row per counter (~6px per row)
  • Color intensity = per-cycle delta activity
  • Per-counter normalization (each row’s max maps to full brightness)
  • Counter names shown when rows are tall enough

The heatmap is designed for scanning 200+ counters at a glance to spot activity patterns and anomalies.

Display Modes

Click the mode indicator (T/R/D) on any counter row to cycle through:

ModeLabelDescription
TotalTRaw cumulative value
RateRDelta per cycle over a 64-cycle window (e.g., IPC)
DeltaDSingle-cycle change

Counter Range

The counter panel displays data for the counter range, which is independent from the pipeline viewport. By default, the counter range covers the full trace. Use the minimap handles to narrow the range to a region of interest.

This independence means you can view full-trace IPC trends in the counter panel while the pipeline view is zoomed into a specific region for detailed inspection.

Konata Traces

Konata format traces do not include performance counters. The counter panel will show “No performance counters in this trace” for Konata files.

Minimap

The minimap is a persistent strip above the main view showing the full trace duration with a counter trendline and navigation controls.

Layout

The minimap shows:

  • Counter trendline — filled bars showing one counter’s per-cycle deltas across the entire trace
  • Counter range handles — draggable pill-shaped handles controlling which range the counter panel displays
  • Dimmed regions — areas outside the counter range are darkened
  • Pipeline indicator — subtle yellow bar at the bottom showing where the pipeline viewport is positioned
  • Cursor marker — vertical line at the active cursor position

Counter Range vs Pipeline Viewport

The minimap manages two independent concepts:

ElementControlsVisual
Handles (blue pills)Counter panel rangeBlue border rectangle with draggable edges
Yellow bar (bottom)Pipeline viewport positionRead-only indicator

The counter range defaults to the full trace. Use the handles to narrow it. The pipeline viewport is controlled by scrolling/zooming in the pipeline view.

Interactions

Dragging

  • Drag handle body — Pan the counter range (preserves width)
  • Drag left/right handle — Resize the counter range
  • Scroll wheel — Zoom the counter range in/out (centered on mouse position)

Clicking

  • Click anywhere (not on a handle) — Centers the pipeline viewport on the clicked cycle and scrolls vertically to show instructions active at that cycle
  • Clicking does NOT move the cursor — cursors are only moved by clicking in the pipeline view

Click vs Drag Detection

The minimap distinguishes between clicks (< 4px movement) and drags (>= 4px movement). Dragging the handles does not trigger a pipeline jump.

Trendline

The minimap displays one counter as a trendline. By default, it shows the first counter in the trace (typically committed_insns). The trendline uses min-max envelope downsampling:

  • Data is cached and only recomputed when the counter, trace, or canvas width changes
  • Inside the counter range: brighter fill
  • Outside the counter range: dimmer fill

Timeline Overlay

The timeline overlay shows a selected counter’s sparkline directly above the pipeline stages, synchronized with the pipeline view’s scroll and zoom.

Toggle

Press Cmd+Shift+O to toggle the overlay on/off.

When enabled, a 30px strip appears between the pipeline header and the stage content. The pipeline stages shift down to accommodate it.

Display

The overlay shows:

  • Min-max envelope bars of the selected counter’s per-cycle deltas
  • Data synchronized with the pipeline viewport (same visible cycle range)
  • Subtle background distinguishing it from the pipeline header
  • Rates recompute automatically at the current zoom level

Use Case

The overlay lets you correlate counter behavior with pipeline events without switching to the Counters tab. For example:

  • Watch IPC drop while inspecting a cache miss stall in the pipeline
  • See branch misprediction spikes aligned with flush events
  • Monitor dispatch queue pressure alongside instruction flow

Counter Selection

The overlay shows the first counter by default. The selected counter can be configured via the overlay_counter state (currently toggled via the action, which cycles the first counter on/off).

Queue Panels

The queue panels show the state of the CPU’s internal queues at the current cursor cycle. They update in real-time as you move the cursor.

Queue Types

Retire Queue

Shows the retire buffer (ROB) occupancy. Each slot shows:

  • Slot index (hex)
  • Current pipeline stage
  • Instruction disassembly

The header shows Retire Queue (occupied/total) @ cycle N.

Dispatch Queues

Shows dispatch queue entries grouped by queue instance. Each entry shows:

  • Instruction disassembly
  • Wait time in cycles since entering the dispatch stage

Queue names come from the µScope DUT property cpu.dispatch_queue_names.

Issue Queues

Shows issue queue entries with ready/waiting status:

  • Green dot = ready to issue (all operands available)
  • Red dot = waiting (operands pending)

Each entry shows instruction disassembly and wait time. The header shows ready/total counts.

Data Source

Queue data is NOT pre-computed — it’s calculated on-the-fly from the pipeline trace at the cursor cycle. The queue panel reads metadata from the µScope trace:

DUT PropertyPurpose
cpu.retire_queue_sizeNumber of ROB slots (default: 128)
cpu.dispatch_queue_stagesStage names that represent “in dispatch queue”
cpu.dispatch_queue_namesDisplay names for dispatch queue instances
cpu.issue_queue_stagesStage names that represent “in issue queue”
cpu.issue_queue_namesDisplay names for issue queue instances
cpu.retire_queue_stagesStage names that represent “in retire queue”

Layout

Queue panels are docked in a configurable position:

KeyLayout
Alt+Cmd+1Bottom (horizontal split)
Alt+Cmd+2Left (vertical split)
Alt+Cmd+3Right (vertical split)

Toggle queue panel visibility with Cmd+B.

The Issue Queue panel shares a tab bar with the Log panel.

Configuration

Counter Presets

Counter display preferences can be saved in a TOML configuration file. Reflex searches for counters.toml in the following order:

  1. Next to the trace file (e.g., trace.counters.toml)
  2. In the same directory as the trace file (counters.toml)
  3. User config directory:
    • macOS: ~/Library/Application Support/reflex/counters.toml
    • Linux: ~/.config/reflex/counters.toml

If no config file is found, Reflex uses defaults (show all counters, no overlay).

File Format

[presets.performance]
name = "Overall Performance"
counters = ["committed_insns", "cycles"]
overlay = ["committed_insns"]

[presets.performance.display_modes]
committed_insns = "rate"
cycles = "total"

[presets.cache]
name = "Cache Analysis"
counters = ["dcache_misses", "icache_misses"]
overlay = []

[presets.cache.display_modes]
dcache_misses = "delta"
icache_misses = "delta"

[presets.branch]
name = "Branch Prediction"
counters = ["mispredicts", "committed_insns"]
overlay = ["mispredicts"]

[presets.branch.display_modes]
mispredicts = "rate"

Preset Fields

FieldTypeDescription
nameStringHuman-readable preset name
countersArrayCounter names to show (empty = show all)
display_modesTablePer-counter display mode: "total", "rate", or "delta"
overlayArrayCounter names to show as timeline overlay (empty = no overlay)

Error Handling

If the config file contains syntax errors, Reflex logs a warning to stderr and falls back to defaults. The application never crashes due to a malformed config file.

Layout Presets

The queue panel layout is switchable via keyboard shortcuts:

KeyLayout
Alt+Cmd+1Bottom dock
Alt+Cmd+2Left dock
Alt+Cmd+3Right dock

Layout state is not persisted between sessions.

Keyboard Shortcuts

Viewport

KeyAction
Scroll / TrackpadPan
Ctrl + ScrollZoom in/out
Cmd + = / Cmd + +Zoom in
Cmd + -Zoom out
Cmd + 0Zoom to fit
Left / Right / Up / DownPan

Selection

KeyAction
jSelect next instruction
kSelect previous instruction
Click (timeline)Select row + place cursor

Cursors

KeyAction
Cmd + MAdd cursor
Cmd + Shift + MRemove active cursor
[Previous cursor
]Next cursor
Cmd + ZUndo cursor change
Cmd + Shift + ZRedo cursor change
Cmd + YRedo cursor change

Search & Navigation

KeyAction
Cmd + FToggle search
Cmd + LGo to cycle

Files & Tabs

KeyAction
Cmd + OOpen file
Cmd + RReload current trace
Cmd + WClose tab
Ctrl + TabNext tab
Ctrl + Shift + TabPrevious tab
Cmd + GGenerate random trace

Panels & Layout

KeyAction
Cmd + BToggle queue panels
Cmd + IToggle info overlay
?Toggle help overlay
Cmd + Shift + OToggle counter overlay
Alt + Cmd + 1Queue layout: bottom
Alt + Cmd + 2Queue layout: left
Alt + Cmd + 3Queue layout: right

Other

KeyAction
Alt + Cmd + WConnect WCP
Alt + Cmd + Shift + WDisconnect WCP
Cmd + QQuit

Trace Formats

Reflex supports two trace formats. The format is auto-detected from the file’s magic bytes.

µScope (.uscope)

Binary format from µScope with CPU protocol semantics.

Features:

  • LZ4 compression
  • Checkpointed random access via segments
  • Performance counters (automatically detected)
  • Queue metadata (retire/dispatch/issue queue configuration)
  • Pipeline stage names from schema
  • Instruction annotation via string table
  • RISC-V instruction decoding (RV64GC)
  • Clock domain information

DUT Properties used by Reflex:

PropertyPurpose
cpu.pipeline_stagesPipeline stage names (comma-separated)
cpu.retire_queue_sizeRetire buffer slot count
cpu.dispatch_queue_stagesStage names for dispatch queue membership
cpu.dispatch_queue_namesDisplay names for dispatch queues
cpu.issue_queue_stagesStage names for issue queue membership
cpu.issue_queue_namesDisplay names for issue queues
cpu.retire_queue_stagesStage names for retire queue membership

Trace metadata shown in the info overlay (Cmd+I):

  • File name, format version, flags
  • Clock domain (name, period, frequency)
  • Pipeline stage sequence
  • Duration (cycles and microseconds)
  • Segment count, schema summary, string table size

Konata (.log, .konata, .kanata)

Text-based Kanata log format used by CPU simulators. Compatible with Konata.

Features:

  • Human-readable text format
  • Stage transitions, labels, dependencies
  • Flush/squash events

Limitations compared to µScope:

  • No performance counters
  • No queue metadata
  • No compression or random access
  • No instruction decoding (uses labels from the trace)

Generating Test Traces

Press Cmd+G to generate a random synthetic trace for testing. The generator creates a configurable number of instructions with realistic pipeline stage patterns, dependencies, and timing.

Building from Source

Prerequisites

  • Rust stable toolchain (install)
  • Git with submodule support

macOS

No additional dependencies needed. GPUI uses native Metal rendering.

Linux

Install the following system libraries:

sudo apt-get install -y \
    libwayland-dev \
    libxkbcommon-x11-dev \
    libvulkan-dev \
    libfontconfig1-dev \
    libfreetype6-dev \
    libxcb-shape0-dev \
    libxcb-xfixes0-dev \
    libxcb-cursor-dev \
    libxcb-render0-dev \
    libxcb-randr0-dev \
    libxcb-keysyms1-dev \
    libxcb-xkb-dev \
    libxkbcommon-dev \
    libglib2.0-dev \
    libatk1.0-dev \
    libgtk-3-dev \
    libclang-dev \
    cmake

Clone

git clone --recurse-submodules https://github.com/zarubaf/reflex.git
cd reflex

If you already cloned without --recurse-submodules:

git submodule update --init --recursive

Build

cargo build              # Debug build
cargo build --release     # Release build (recommended for large traces)

Run

cargo run --release -- path/to/trace.uscope

Format and Lint

cargo fmt                 # Format code
cargo clippy              # Lint
cargo test                # Run tests

CI

The project uses GitHub Actions for CI:

  • Build — macOS and Linux release builds
  • Clippy — Lint with -D warnings
  • Formatcargo fmt --check
  • Testcargo test

All CI jobs use actions/checkout@v4 with submodules: recursive to handle the µScope submodule.

Release

Tagged releases (v*) trigger the release workflow:

  • macOS: .app bundle, signed and notarized
  • Linux: standalone binary tarball
  • Both uploaded as GitHub release artifacts