Debugging Kernels
When a test fails (cmp reports a difference), you need to figure out why your
kernel's output doesn't match the reference. This guide covers the tools
available for debugging.
Quick Debugging Checklist
- Rebuild from clean: after any edit,
make cleanbefore rerunning; an existingtest-<label>/is not rebuilt, so its result may be stale - Check the reference: Is
ref.pycorrect? - Inspect data: Use
migetwithtextmode to print values - Run debug build:
make clean, thenmake TEST=<id> GOAL=debugx - Launch Portrait: Visualize execution in the browser
- Check pipeline traces: See instruction-by-instruction execution
- Check wavelet traffic: See what data flowed between PEs
1. Inspecting Data with miget
Before launching heavy debug tools, check what data looks like:
View initial data (from compiled image)
# Print array 'a' as human-readable text
miget image=bench.img map=bench.map symbol=a text
# For multi-tile: include the region name
miget image=bench.img map=bench.map symbol=send.a text
# Dump as binary file
miget image=bench.img map=bench.map symbol=a data=initial.bin
View simulation results (from core dump)
Make deletes the core, and in some lessons the map, as intermediate files once
the test has run. Rebuild and keep both, then work in the test directory
(test-1/ instead of test-tutorial/ in lessons with two tutorial rows):
make test-tutorial/bench-sim.core test-tutorial/bench.map
cd test-tutorial
# Print the result array after simulation
miget image=bench-sim.core map=bench.map symbol=recv.a text
# Compare with initial data
miget image=bench.img map=bench.map symbol=send.a text
miget image=bench-sim.core map=bench.map symbol=recv.a text
Interpreting miget text output
0000 0001 0002 0003
text prints only the values, as 16-bit hexadecimal words (width= sets how
many per line). Use decimal or hp instead of text for decimal or
half-precision output.
Ordering control
# Specify dimension ordering
miget image=bench.img map=bench.map symbol=A order="n m" text
2. Debug Build with GOAL=debugx
The debug build produces extra artifacts needed for Portrait and pipeline visualization:
make clean
make TEST=1 GOAL=debugx
Clean first: debugx reuses an existing simulation log, which then has no pipeline or landing records.
This generates (inside the row's test directory, test-tutorial/ in most
tutorials):
| File | Description |
|---|---|
pipeline.bin | Binary pipeline trace (instruction execution per cycle) |
region.json | Tile geometry and region tree |
listing.json | Source code ↔ assembly mapping |
landing.json | Wavelet traffic traces |
debuginfo.json | Source-level debug information |
bench-sim.log | Full simulation log |
3. Portrait — Web-Based Visualization
Portrait is an interactive browser tool for inspecting execution.
Launching
# After running GOAL=debugx, navigate to the test directory
cd test-tutorial/
portrait
Portrait prints the address to open in a web browser:
http://hostname:8080/paint.html
Portrait Panels
| Panel | Description |
|---|---|
| Floor Plan | SVG view of the tile layout. Click a tile to inspect it. |
| Region Tree | Hierarchical view of paint regions. |
| Source Code | Shows the Tungsten source or the Yeti assembly, chosen from a drop-down. |
| Pipeline View | Cycle-by-cycle instruction execution for the selected tile. |
| Tile Report | Summary of a selected tile's configuration. |
| Route Plan | Visual routing for the selected tile's colors. |
| Wavelet Log | Timeline of wavelet traffic on the selected tile. |
Common Portrait Workflow
- Open Floor Plan — verify tiles are where you expect them.
- Click a tile — inspect its source, pipeline, and wavelet traffic.
- Check Pipeline View — look for stalls, unexpected instruction sequences.
- Check Wavelet Log — verify data arrived at the right time, right value.
Portrait Command-Line Options
portrait port=9090 # use a different port
portrait quiet=1 # do not print the address
4. Pipeline Traces
The pipeline trace shows cycle-by-cycle execution for a specific tile. Portrait fetches this data on-demand when you click a tile.
What to look for
| Issue | Symptom in Pipeline View |
|---|---|
| Deadlock | Tile stalls at a receive instruction, never proceeds |
| Wrong order | Data processed in unexpected sequence |
| Missing data | Fewer wavelets received than expected |
| Infinite loop | Execution never terminates (hits cycle limit) |
Cycle Budget
Set cycles=N in the Makefile's SIMFLAGS, keeping its $(SIMOPTS). If the
simulation hits the cycle limit without completing, the core dump will show
the state at timeout.
Increase cycles if your kernel legitimately needs more time.
5. Wavelet Traffic Analysis
In Portrait
The Wavelet Log panel shows all wavelets that arrived at or departed from a tile, with timestamps and values.
From the Simulation Log
With debug=landing, the simulation log records each wavelet landing:
make clean
make TEST=1 SIMOPTS=debug=landing
grep ' landing ' test-tutorial/bench-sim.log | head -20
Inspect memory at a cycle with meminsp
Use the image, map, and log from the debug run to inspect a tile's memory:
meminsp img_path=bench.img map_path=bench.map log_path=bench-sim.log \
tile_str=T1.0
At the prompt, list the available symbols, then inspect one at a cycle:
symbols
seek 100
print recv.result
diff recv.result @0 @200
Replace recv.result with your symbol name. See the
meminsp reference for watchpoints and other
commands.
6. Common Debugging Scenarios
Scenario: Test fails with cmp error
# 1. Check what output you got (rebuild the core first, as in section 1)
miget image=bench-sim.core map=bench.map symbol=recv.a text
# 2. Check what you expected (out-ref.bin is written by ../ref.py)
xxd out-ref.bin | head
# 3. Compare byte-by-byte
cmp -l out-sim.bin out-ref.bin | head
Scenario: Simulation times out (hits cycle limit)
# Increase cycles in the Makefile, keeping $(SIMOPTS)
SIMFLAGS=cycles=10000 $(SIMOPTS)
Or check for deadlocks — is a tile waiting on data that never arrives? Run debugx and check Portrait's pipeline view:
make clean
make TEST=1 GOAL=debugx
Scenario: Array has wrong values
# Check initial values — is the initializer correct?
miget image=bench.img map=bench.map symbol=a text
# Check values after simulation (rebuild the core first, as in section 1)
miget image=bench-sim.core map=bench.map symbol=a text
# Compare initial vs final
diff <(miget image=bench.img map=bench.map symbol=a text) \
<(miget image=bench-sim.core map=bench.map symbol=a text)
Scenario: Routing problem (data not arriving)
# 1. Check the colors along the route in bench.paint
# Without a colorpair swap, the sender's tx color must equal the
# receiver's rx color; with one, a sender on a can reach a receiver on b
# 2. Verify direction codes
# Sender: [C>R] means data goes right
# Receiver: [L>C] means data comes from left
# These must be consistent with tile positions (hstack = left-to-right)
Scenario: Switch positions not advancing (flip / serial drain)
If you use multi-position routing ([C>R ; L>R]) with flip, data
from interior tiles may not arrive at the receiver.
# 1. Check that flip is LOCAL:
# - flip advances the SENDING tile's own input switch
# - It does NOT advance downstream tiles
# - With [C>R ; L>R]: tile starts injecting (C>R),
# after flip switches to passthrough (L>R)
# - Rightmost tile drains first, then tiles further left
# 2. Common mistakes:
# - [L>R ; C>R] with flip: tile starts in passthrough, but
# flip advances the LOCAL switch, not the downstream one.
# Use this pattern with control(ADV) wavelets instead, as in
# the Switch protocols topic.
# - [C>R ; L>R] with flip: correct for serial drain.
# Tiles closest to receiver drain first.
See lesson 10, Switches for a working example of flip-based switch ordering.
Scenario: Floating-point mismatch
Half-precision (hp) has limited precision. Small rounding differences between
hardware (16-bit FP) and Python (np.float16) can cause cmp to fail even
when the logic is correct.
# In ref.py, use float16 arithmetic throughout:
a = np.fromfile(in_name, dtype=np.float16)
result = (a * np.float16(2.0)) # keep in float16
result.astype('float16').tofile(outfile)
Scenario: MP message not arriving
Message passing debugging:
# 1. Verify all tiles in the MP path have mp(bank) in paint
# Missing mp() on relay tiles is a common mistake
# 2. Check header construction:
# - dest_col must be << 4 in w[1] to place it in header bits 31:20
# - north (0x80) only if the destination has a smaller row ID than the
# sender, south (0x40) only if it has a larger one; both clear for a
# same-row destination
# - length field must match the number of data wavelets
# 3. Verify wavelets are 32-bit (full wavelets)
# Sending raw xp on an MP color sends a half-wavelet, which is undefined
# behavior on a message-passing color
# Fix: send a u32, built with a union, u32 shifts or a (u32) cast
# 4. Check message ordering when receiving from multiple senders:
# MP messages from different tiles may arrive in arbitrary order.
# Use payload tagging (embed an ID of the sender) to identify the source.
# The Collectives over messages topic tags its messages this way.
7. Useful Debug Flags
Makefile level
# More simulation cycles
SIMFLAGS=cycles=10000 $(SIMOPTS)
Command line
# Record wavelet landings (debug=landing) or the pipeline (debug=hwtile)
# in the simulation log; clean first so the simulation reruns
make clean
make TEST=1 MODE=sim SIMOPTS=debug=landing
# Run debug build, after cleaning for the same reason
make clean
make TEST=1 GOAL=debugx
Also See
- Portrait Debug Tool Documentation — full Portrait reference
- miset/miget Tools Documentation — complete
miget/misetreference