Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c5425bb
fix(hrr): swap the capture shims into the dispatch table slot by slot
andraghetti Sep 25, 2026
a41fedc
fix(hrr): drop capture events that arrive after the EOF trailer
andraghetti Sep 28, 2026
3796747
docs(hrr): wrap the new DESIGN.md paragraphs like the rest
andraghetti Sep 28, 2026
295fd7e
docs(hrr): say that shutdown leaves the compiler table shims in place
andraghetti Sep 28, 2026
0331f1c
fix(hrr): drop blobs after the trailer and make the slot guards agree
andraghetti Sep 29, 2026
05aed75
Merge branch 'develop' into users/andraghetti/hrr-capture-dispatch-swap
andraghetti Sep 30, 2026
ff982e7
fix(hrr): order blob claims with the trailer so the manifest counts them
andraghetti Oct 1, 2026
d5786f7
fix(hrr): wait for claimed blob writes before finalizing the archive
andraghetti Oct 1, 2026
35292d4
fix(hrr): declare the claimed-write count apart from develop's new gl…
andraghetti Oct 1, 2026
f4ed281
fix(hrr): clear the claimed-write count when a fresh archive opens
andraghetti Oct 1, 2026
222d962
fix(hrr): hold the writer locks across fork
andraghetti Oct 1, 2026
a87ec6b
fix(hrr): say what the fork child's writer reopen relies on
andraghetti Oct 1, 2026
32a2d50
fix(hrr): finish a claimed blob write on every way out, a throw included
andraghetti Oct 1, 2026
b7f9b21
fix(hrr): clear the inherited incomplete flag in a fork child
andraghetti Oct 1, 2026
029d144
fix(hrr): clear the incomplete flag when a fresh archive is opened
andraghetti Oct 1, 2026
b3f14c0
fix(hrr): ignore mark_incomplete past the trailer decision
andraghetti Oct 1, 2026
7ab6716
Merge branch 'develop' into users/andraghetti/hrr-capture-dispatch-swap
andraghetti Oct 5, 2026
cef4f8f
test(hrr): cover the slot-by-slot uninstall and the writer's shutdown…
andraghetti Oct 5, 2026
aca8ef0
fix(hrr): list unreplayable APIs with their events, and fail blob wri…
andraghetti Oct 5, 2026
47846a0
Merge branch 'develop' into users/andraghetti/hrr-capture-dispatch-swap
andraghetti Oct 6, 2026
cdc844f
Merge branch 'develop' into users/andraghetti/hrr-capture-dispatch-swap
andraghetti Oct 6, 2026
ff9bb9b
fix(hrr): list only the archive's own unreplayable APIs
andraghetti Oct 7, 2026
a933b04
test(hrr): skip the dispatch-table tests when HIP does not register
andraghetti Oct 7, 2026
4b9c5cd
Merge branch 'develop' of github.com:ROCm/rocm-systems into users/and…
andraghetti Oct 7, 2026
e19ace1
Merge branch 'develop' into users/andraghetti/hrr-capture-dispatch-swap
andraghetti Oct 7, 2026
3c2064e
Merge branch 'develop' into users/andraghetti/hrr-capture-dispatch-swap
andraghetti Oct 8, 2026
5878045
Merge branch 'develop' into users/andraghetti/hrr-capture-dispatch-swap
andraghetti Oct 9, 2026
8a0f890
fix(hrr): charge the free-space reserve once per deduplicated blob
andraghetti Oct 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 82 additions & 4 deletions projects/clr/hipamd/src/hrr/hip_capture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2366,16 +2366,94 @@ hipError_t capture_hipGraphExecBatchMemOpNodeSetParams(
// Install / uninstall (build_table functions live in hip_capture_generated.cpp)
// ---------------------------------------------------------------------------

namespace {

// Other threads keep calling through the live dispatch tables while the shims go
// in and out, so the tables are written one slot at a time with atomic operations
// and never copied over as a whole. Outside Windows, function-pointer slots are
// accessed through a may_alias view so the store is well-defined against the typed
// table fields; MSVC does no type-based alias analysis and clang-cl disables it by
// default.
template <typename Table> constexpr size_t kDispatchSlots =
(sizeof(Table) - sizeof(size_t)) / sizeof(void*);

#if IS_WINDOWS
struct DispatchSlot {
void* value;
};

void store_slot(DispatchSlot* slot, void* value) {
std::atomic_ref<void*>(slot->value).store(value, std::memory_order_release);
}

void replace_slot(DispatchSlot* slot, void* expected, void* desired) {
std::atomic_ref<void*>(slot->value).compare_exchange_strong(
expected, desired, std::memory_order_release, std::memory_order_relaxed);
}
#elif defined(__GNUC__) || defined(__clang__)
struct DispatchSlot {
void* value;
} __attribute__((__may_alias__));

void store_slot(DispatchSlot* slot, void* value) {
__atomic_store_n(&slot->value, value, __ATOMIC_RELEASE);
}

void replace_slot(DispatchSlot* slot, void* expected, void* desired) {
__atomic_compare_exchange_n(&slot->value, &expected, desired, false, __ATOMIC_RELEASE,
__ATOMIC_RELAXED);
}
#else
#error "Outside Windows, HRR dispatch slots need GCC or Clang"
#endif

template <typename Table> DispatchSlot* dispatch_slots(Table& table) {
static_assert(sizeof(void (*)()) == sizeof(void*),
"dispatch slot atomics need function pointers the size of void*");
static_assert(offsetof(Table, size) == 0 && sizeof(table.size) == sizeof(size_t) &&
(sizeof(Table) - sizeof(size_t)) % sizeof(void*) == 0,
"layout must match HIP dispatch tables: size_t size then void* slots");
static_assert(sizeof(DispatchSlot) == sizeof(void*), "DispatchSlot must be a single pointer");
return reinterpret_cast<DispatchSlot*>(reinterpret_cast<char*>(&table) + sizeof(size_t));
}

// Unlike uninstall this does not compare first: a slot that changed since the
// snapshot still gets its shim, or the archive would silently miss that API.
template <typename Table>
void install_shims(const Table* live, const Table& shims, const Table& real) {
DispatchSlot* slot = dispatch_slots(*const_cast<Table*>(live));
const DispatchSlot* shim = dispatch_slots(const_cast<Table&>(shims));
const DispatchSlot* orig = dispatch_slots(const_cast<Table&>(real));
for (size_t i = 0; i < kDispatchSlots<Table>; ++i) {
if (shim[i].value != orig[i].value) store_slot(&slot[i], shim[i].value);
}
}

// A slot that another component changed after install keeps its new value.
Comment thread
andraghetti marked this conversation as resolved.
Resolved
template <typename Table>
void uninstall_shims(const Table* live, const Table& shims, const Table& real) {
DispatchSlot* slot = dispatch_slots(*const_cast<Table*>(live));
const DispatchSlot* shim = dispatch_slots(const_cast<Table&>(shims));
const DispatchSlot* orig = dispatch_slots(const_cast<Table&>(real));
for (size_t i = 0; i < kDispatchSlots<Table>; ++i) {
if (shim[i].value != orig[i].value) replace_slot(&slot[i], shim[i].value, orig[i].value);
}
}

} // namespace

void hip_capture_install() {
if (g_installed.exchange(true)) return;
std::memcpy(const_cast<HipDispatchTable*>(hip::GetHipDispatchTable()),
&g_cap_table, sizeof(HipDispatchTable));
install_shims(hip::GetHipDispatchTable(), g_cap_table, g_real_table);
}

void hip_capture_uninstall() {
if (!g_installed.exchange(false)) return;
std::memcpy(const_cast<HipDispatchTable*>(hip::GetHipDispatchTable()),
&g_real_table, sizeof(HipDispatchTable));
uninstall_shims(hip::GetHipDispatchTable(), g_cap_table, g_real_table);
}

void hip_capture_install_compiler_table(const HipCompilerDispatchTable& shims) {
install_shims(hip::GetHipCompilerDispatchTable(), shims, g_real_compiler_table);
}

// ---------------------------------------------------------------------------
Expand Down
6 changes: 6 additions & 0 deletions projects/clr/hipamd/src/hrr/hip_capture.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ void hip_capture_uninstall();
// Hook compiler dispatch table for <<<>>> launch path
void hip_capture_build_compiler_table();

struct HipCompilerDispatchTable;

// Swap the compiler shims into the live table. Call only from
// hip_capture_build_compiler_table(), after it snapshots g_real_compiler_table.
void hip_capture_install_compiler_table(const HipCompilerDispatchTable& shims);

// Called from hip_context.cpp init() — performs build + conditional install
void hip_capture_init();

Expand Down
Loading
Loading