Demonstrate SuperCollider-style instrumentation of AMDGPU LDS accesses under rocJITsu DBI.
The concrete deliverable is an opt-in rocJITsu instrumentation mode that can catch at least some LDS races on selected tests. This is intentionally a race-exposure MVP, not a full happens-before sanitizer.
- Prefer the existing HSA tools path if it is practical.
- Fall back to a waitcheck-style
LD_PRELOADpath only if HSA-level interception blocks first-light progress. - Treat hip-moi as the innermost iteration corpus:
- source:
~/workspace/hip-moi - build:
~/workspace/hip-moi-build
- source:
- Treat IREE as periodic broader coverage, not the tight loop:
- source:
~/workspace/iree - build:
~/workspace/iree-build - run a focused IREE subset roughly once per 30-minute session.
- source:
- The local GPU target is RDNA4 /
gfx1201. This MVP is instrumentation-only: rocJITsu should patch the loaded RDNA4 code object in place, not translate it to another architecture. - When running GPU tests, cap parallelism at roughly 8 jobs.
- Split work into chunks that fit roughly into 30-minute sessions.
- Achieve very minimal first-light within about 6 hours.
- Deliver the useful MVP later this week, roughly within 2 days of focused work.
Instrument ordinary non-atomic LDS reads and writes with the SuperCollider redundant-access idea:
- For an LDS read:
- perform the original read,
- delay for a small randomized or configurable window,
- read the same LDS address again,
- report if the two values differ.
- For an LDS write:
- perform the original write,
- delay for a small randomized or configurable window,
- read the same LDS address back,
- report if the observed value differs from the value written.
The first implementation may report by trapping. A report counter is preferred once basic binary patching is proven.
Support first:
- LDS/shared-memory
ds_read*andds_write*. - Common fixed-width forms, starting with
b32, thenb64, thenb128. - Known test kernels from a tiny synthetic HIP test, hip-moi, and IREE.
- Opt-in instrumentation controlled by environment variables.
Reject, skip, or route away at first:
ds_*atomic.global_atomic,flat_atomic,buffer_atomic, ands_atomic.- Explicit cache/fence-like opcodes such as
global_wb,global_inv,buffer_wbinvl1, ands_dcache. - Global memory instrumentation.
- Async copies.
- Full barrier epoch modeling.
- Full per-address shadow memory.
- Precise source-level reporting.
Unsupported cases must produce clear diagnostics. A clean run must not imply coverage when the preflight rejected the kernel.
Use the HSA tools hook first.
Expected invocation shape:
HSA_TOOLS_LIB=/path/to/librocjitsu_dbi_hooks.so \
RJ_DBI_SUPERCOLLIDER=1 \
RJ_DBI_LOG=1 \
RJ_DBI_SC_DELAY=32 \
./appProposed DBI environment variables:
RJ_DBI_SUPERCOLLIDER=1: enable this instrumentation mode.RJ_DBI_LOG=1: print code-object, kernel, patch, skip, and report diagnostics.RJ_DBI_SC_DELAY=N: request an approximate delay between the original LDS access and the duplicate/readback access. This is not an existing rocJITsu variable yet. For the first MVP, define it as the number of emitted simple NOP delay instructions. It should not be documented as exact GPU cycles. Later versions can add a scalar loop or randomized delay window if plain NOPs are not enough to expose races.RJ_DBI_FAIL_CLOSED=1: optional debug mode that rejects kernels with unsupported LDS/fence/atomic features instead of silently skipping them.
Implementation shape:
- Extend the existing rocJITsu HSA tools hook with an opt-in DBI mode.
- Reuse the memory-backed code-object reader registry already used by the DBT hook.
- At
hsa_executable_load_agent_code_object, pass recorded ELF bytes through a DBI SuperCollider patching path. - Create a replacement memory-backed reader over patched bytes.
- Call the saved original HSA load function with the replacement reader.
Fallback shape:
- If memory-backed reader coverage is insufficient, add a waitcheck-style
LD_PRELOADshim that intercepts code-object reader creation earlier, including file and AMD loader extension-table paths.
This is the current best map of where the DBI SuperCollider MVP should live in the rocJITsu tree.
Core patching should start in the existing DBI patch layer:
lib/rocjitsu/src/rocjitsu/code/patch/supercollider_dbi.hlib/rocjitsu/src/rocjitsu/code/patch/supercollider_dbi.cpp
This should own the opt-in patch entry point and the MVP data model:
SuperColliderDbiOptionsSuperColliderDbiResultLdsAccessKindLdsAccessSite- scan/classify helpers for
ds_read*,ds_write*,ds_*atomic, barriers, and fence-like instructions - the first patching entry point that takes an
AmdGpuCodeObjectplus options and returns patched bytes or diagnostics
Keep this separate from patch/instrumentor.{h,cpp} initially. The existing
Instrumentor is a good relocation/trampoline smoke-test path, but it is still
deliberately constrained around BeforeInst and inline s_nop insertion. It
should remain the minimal DBI probe path until the SuperCollider code proves the
richer replacement sequences.
If supercollider_dbi.cpp grows too quickly, split it later into:
lib/rocjitsu/src/rocjitsu/code/patch/lds_access_classifier.{h,cpp}lib/rocjitsu/src/rocjitsu/code/patch/supercollider_emitter.{h,cpp}
The HSA interception source should preferably be a distinct tools library:
lib/rocjitsu/src/rocjitsu/hooks/rj_hsa_dbi_hooks.cpp
This file can reuse the same HSA tools mechanism as rj_hsa_dbt_hooks.cpp, but
with DBI-oriented environment variables such as RJ_DBI_SUPERCOLLIDER=1. The
fastest possible route is to extend rj_hsa_dbt_hooks.cpp in-place, but a
separate rocjitsu_dbi_hooks target avoids tying DBI behavior to
RJ_DBT_TARGET_ISA and avoids surprising existing DBT hook users. DBI should
not ask rocJITsu to translate architectures for this MVP: on this machine, the
loaded and patched target is always RDNA4 / gfx1201. If reader registry
duplication becomes annoying, refactor the common HSA code-object reader
registry into a small shared helper under hooks/.
Tests should be added alongside the current DBI and patch tests:
tests/patch/supercollider_dbi_test.cpptests/dbi/hsa_dbi_supercollider_test.cpptests/kernels/lds_race_supercollider.hip
The first patch test should use synthetic or fixture code objects to prove
classification and controlled patching. The HSA test should mirror the existing
HSA-tools DBT smoke test shape, but set HSA_TOOLS_LIB to the new DBI hooks
library.
Build glue:
lib/rocjitsu/src/rocjitsu/code/CMakeLists.txt: add the new core SuperCollider patch source.lib/rocjitsu/src/rocjitsu/hooks/CMakeLists.txt: add arocjitsu_dbi_hooksshared library target, or intentionally extend the existingrocjitsu_hookstarget if we choose the fastest in-place path.tests/CMakeLists.txt: add unit tests and an HSA DBI hook CTest entry.tests/kernels/CMakeLists.txt: add the synthetic LDS race device kernel.
Instruction emission:
lib/rocjitsu/src/rocjitsu/code/patch/instruction_builder.hlib/rocjitsu/src/rocjitsu/code/patch/instruction_builder.cpp
The first edit here is likely a small encoder for s_trap or another
observable first-light instruction. Real SuperCollider checks will probably
need additional vector/scalar compare, conditional branch, DS load/store, and
reporting helpers unless an existing generated ISA encoder can be reused.
Descriptor/resource updates:
lib/rocjitsu/src/rocjitsu/code/patch/code_object_patcher.{h,cpp}lib/rocjitsu/src/rocjitsu/code/dbt/kernel_descriptor_translator.{h,cpp}
These may not need edits for first-light. They become relevant once the MVP
needs extra scratch, larger VGPR/SGPR allocation, or private segment growth.
CodeObjectPatcher can already patch descriptor bytes, and DBT already has
patterns for recomputing descriptor resource fields after liveness-selected
scratch registers.
Register pressure helpers:
- Use
analysis/liveness.{h,cpp}as-is if possible. It already providesfind_free_run,find_free_sgpr, andfind_free_sgpr_pair. - Use
patch/spill_manager.{h,cpp}as-is if possible. It already models a DBI spill zone appended to per-lane scratch.
These are likely dependencies of the SuperCollider path, not first edits.
- Avoid pushing SuperCollider-specific logic into
patch/instrumentor.{h,cpp}until there is a clear shared abstraction with the existing inline-nop path. - Avoid editing DBT semantic translator files for MVP DBI instrumentation. They are useful references for liveness and descriptor feedback, but the MVP should not couple itself to CDNA4-to-RDNA translation rules.
- Avoid touching IREE or hip-moi source during first-light; use them as test corpora once rocJITsu can patch a tiny local kernel.
First-light is complete when:
- A test application runs under the rocJITsu HSA-level hook.
- rocJITsu intercepts at least one code object.
- rocJITsu identifies at least one LDS instruction.
- rocJITsu patches the loaded binary in a visible way.
- A deliberately racy tiny LDS test produces a report or trap.
First-light does not need to pass IREE or hip-moi yet.
The MVP is complete when:
- rocJITsu has an opt-in DBI SuperCollider mode.
- The mode instruments some ordinary LDS
ds_read*andds_write*instructions. - It catches at least one intentional LDS race.
- It runs against selected hip-moi and IREE tests.
- It emits clear patched/skipped/unsupported diagnostics.
- Unsupported atomics/fences are rejected or skipped explicitly.
- There is a short usage note documenting environment variables, known limitations, and test commands.
Confirm the exact files and APIs to touch:
- HSA tools hook.
- Code-object reader registry.
- DBI
Instrumentor. - Code-object patcher.
- Instruction decoder and metadata helpers.
Output: short notes on the patch path and any immediate blockers.
Add env parsing for an inactive DBI mode:
RJ_DBI_SUPERCOLLIDER=1RJ_DBI_LOG=1RJ_DBI_SC_DELAY=N, interpreted as the number of emitted NOP delay instructions- optional
RJ_DBI_FAIL_CLOSED=1
Output: hook logs that DBI mode is enabled, but still passes original code objects through.
Route memory-backed code-object bytes from the HSA load wrapper into a
try_patch_supercollider_dbi(...) stub.
Output: the stub receives bytes and returns "unchanged" cleanly.
Build the hook and run a tiny HIP or HSA test with:
HSA_TOOLS_LIB=/path/to/librocjitsu_dbi_hooks.so RJ_DBI_SUPERCOLLIDER=1 ./testOutput: the app still runs, and logs show the code-object load path.
Construct AmdGpuCodeObject from recorded ELF bytes.
Output:
- target ISA, expected to remain RDNA4 /
gfx1201for this MVP, - kernel names,
- text ranges,
- per-kernel code sizes.
Walk decoded instructions and count:
ds_read*,ds_write*,ds_*atomic,- barriers and fence-like instructions.
Output: no mutation yet, just per-kernel LDS statistics.
Reject or skip kernels with unsupported instructions.
Output: diagnostics that explain why each kernel is patched or skipped.
Use the current DBI trampoline/instrumentor path to insert one inline nop at a known safe anchor.
Output: live HSA hook patching is proven without SuperCollider logic.
Add a controlled sabotage mode for a known test:
- trap,
- early end,
- or another obvious behavior.
Output: prove the running app executes patched code, not the original code.
Patch one supported LDS read form:
- original read,
- delay,
- duplicate read,
- compare,
- trap or report on mismatch.
Output: one selected ds_read_b32 site can be instrumented.
Patch one supported LDS write form:
- original write,
- delay,
- duplicate read,
- compare against written value,
- trap or report on mismatch.
Output: one selected ds_write_b32 site can be instrumented.
Create or use an out-of-tree tiny test first:
- one clean missing-race variant,
- one missing-barrier racy variant.
Output: clean variant does not report in ordinary runs; racy variant reports or traps at least sometimes.
Extend instruction handling to common wider LDS forms.
Output: DBI can instrument the common LDS widths used by matmul-like kernels.
Support:
- fixed NOP-count delay for debugging,
- configurable NOP-count delay through
RJ_DBI_SC_DELAY, - randomized delay when the needed seed values are easy to materialize.
Output: delay can be tuned without rebuilding.
If trap mode is working, add a device-visible report counter.
Output: tests can finish and report a count instead of always trapping.
Run a narrow hip-moi subset first, then broaden. This is the innermost external iteration corpus for the MVP.
Output:
- patched kernels,
- skipped kernels,
- unsupported opcodes,
- report counts or traps.
Run a narrow IREE ctest -R subset periodically, roughly once per 30-minute
session, after the hip-moi loop has produced useful signal.
Output:
- patched kernels,
- skipped kernels,
- unsupported opcodes,
- report counts or traps.
Add a known-clean and known-racy test pair to rocJITsu or the chosen test location.
Output: a repeatable local regression target for DBI SuperCollider.
Emit consistent logs such as:
dbi-supercollider: patched kernel=... ds_reads=... ds_writes=... skipped=...
dbi-supercollider: unsupported kernel=... reason=...
dbi-supercollider: reports=...
Output: humans and later automation can tell what coverage was actually provided.
Add a short usage note with:
- env vars,
- example hip-moi command,
- example IREE command,
- limitations,
- unsupported instruction policy.
Output: someone else can run the MVP without reverse engineering the hook.
Hour 1:
- Sessions 1 and 2.
Hour 2:
- Sessions 3 and 4.
Hour 3:
- Sessions 5 and 6.
Hour 4:
- Sessions 7 and 8.
Hour 5:
- Session 9 and begin session 10.
Hour 6:
- Finish session 10 or 11.
- Run the tiny racy LDS test.
Expected result: one live code object is patched and at least one selected LDS site can produce an observable report or trap.
Day 1:
- Establish HSA hook path.
- Log and preflight code objects.
- Prove live patching.
- Instrument one
ds_read_b32ords_write_b32site. - Create or run a tiny racy LDS test.
Day 2:
- Generalize common LDS widths.
- Add report counter if trap mode was first.
- Run selected hip-moi tests.
- Run selected IREE tests as periodic broader coverage.
- Stabilize diagnostics.
- Document usage and limitations.
hip-moi shape:
HSA_TOOLS_LIB=/path/to/librocjitsu_dbi_hooks.so \
RJ_DBI_SUPERCOLLIDER=1 \
RJ_DBI_LOG=1 \
RJ_DBI_SC_DELAY=32 \
ctest --test-dir ~/workspace/hip-moi-build --parallel 8IREE shape:
HSA_TOOLS_LIB=/path/to/librocjitsu_dbi_hooks.so \
RJ_DBI_SUPERCOLLIDER=1 \
RJ_DBI_LOG=1 \
RJ_DBI_SC_DELAY=32 \
ctest -R '<small-iree-pattern>' --test-dir ~/workspace/iree-build --parallel 8Start narrow, and keep GPU test fanout near 8. Avoid broad IREE test runs until the unsupported-path diagnostics are trustworthy.
- HSA tools path may not see all code-object creation paths needed by HIP/IREE.
- DBI may need temporary registers or spill handling sooner than expected.
- Because this MVP is instrumentation-only on RDNA4 /
gfx1201, any accidental DBT-style architecture translation would be a bug, not a feature. - Branch/trampoline layout may be harder for dense kernels than for unit tests.
- SuperCollider value checks miss same-value writes and unlucky schedules.
- Trap-first reporting proves instrumentation but is too disruptive for broad test suites.
- Without clear preflight diagnostics, users may overestimate coverage.
This path exercises the DBI building blocks that later sanitizer modes need:
- code-object interception,
- final-ISA decoding,
- LDS instruction classification,
- live binary patching,
- trampoline/probe emission,
- runtime report plumbing,
- skipped/unsupported diagnostics.
At the same time, it avoids the hard parts of hip-moi/Loom-style "proper" instrumentation until the basic DBI substrate is real.