Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
730 changes: 730 additions & 0 deletions .github/workflows/hrr-ci.yml

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions projects/clr/hipamd/src/hrr/hip_capture_generated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7788,6 +7788,19 @@ static hipError_t capture_hipModuleEnumerateFunctions(hipFunction_t* functions,
return r;
}

// Generated shim
static hipError_t capture_hipDeviceFlushGPUDirectRDMAWrites(enum hipFlushGPUDirectRDMAWritesTarget target, enum hipFlushGPUDirectRDMAWritesScope scope) {
hipError_t r = g_real_table.hipDeviceFlushGPUDirectRDMAWrites_fn(target, scope);
if (r == hipSuccess) {
hrr_args_hipDeviceFlushGPUDirectRDMAWrites a{};
a.ret = static_cast<int32_t>(r);
a.target = static_cast<decltype(a.target)>(target);
a.scope = static_cast<decltype(a.scope)>(scope);
hrr_cap::writer::write_event_raw(HRR_API_HIPDEVICEFLUSHGPUDIRECTRDMAWRITES, &a.hdr, sizeof(a));
}
return r;
}

// Generated shim
static hipError_t capture___hipPopCallConfiguration(dim3* gridDim, dim3* blockDim, size_t* sharedMem, hipStream_t* stream) {
hipError_t r = g_real_compiler_table.__hipPopCallConfiguration_fn(gridDim, blockDim, sharedMem, stream);
Expand Down Expand Up @@ -8523,6 +8536,7 @@ void hip_capture_build_table() {
g_cap_table.hipDeviceGetLuid_fn = capture_hipDeviceGetLuid;
g_cap_table.hipInitDevice_fn = capture_hipInitDevice;
g_cap_table.hipModuleEnumerateFunctions_fn = capture_hipModuleEnumerateFunctions;
g_cap_table.hipDeviceFlushGPUDirectRDMAWrites_fn = capture_hipDeviceFlushGPUDirectRDMAWrites;
}

void hip_capture_build_compiler_table() {
Expand Down
30 changes: 20 additions & 10 deletions projects/hrr/include/hrr/hrr_api_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -5820,6 +5820,14 @@ typedef struct {
uint64_t module;
} hrr_args_hipModuleEnumerateFunctions;

/* hipError_t hipDeviceFlushGPUDirectRDMAWrites(enum hipFlushGPUDirectRDMAWritesTarget target, enum hipFlushGPUDirectRDMAWritesScope scope) */
typedef struct {
hrr_event_header hdr;
int32_t ret;
uint64_t /* enum hipFlushGPUDirectRDMAWritesTarget */ target;
uint64_t /* enum hipFlushGPUDirectRDMAWritesScope */ scope;
} hrr_args_hipDeviceFlushGPUDirectRDMAWrites;

/* ---- API id enumeration ---- */
typedef enum hrr_api_id {
HRR_API_HIPAPINAME = 0,
Expand Down Expand Up @@ -6367,16 +6375,17 @@ typedef enum hrr_api_id {
HRR_API_HIPDEVICEGETLUID = 542,
HRR_API_HIPINITDEVICE = 543,
HRR_API_HIPMODULEENUMERATEFUNCTIONS = 544,
HRR_API_HIPPOPCALLCONFIGURATION = 545,
HRR_API_HIPPUSHCALLCONFIGURATION = 546,
HRR_API_HIPREGISTERFATBINARY = 547,
HRR_API_HIPREGISTERFUNCTION = 548,
HRR_API_HIPREGISTERMANAGEDVAR = 549,
HRR_API_HIPREGISTERSURFACE = 550,
HRR_API_HIPREGISTERTEXTURE = 551,
HRR_API_HIPREGISTERVAR = 552,
HRR_API_HIPUNREGISTERFATBINARY = 553,
HRR_API_COUNT = 554
HRR_API_HIPDEVICEFLUSHGPUDIRECTRDMAWRITES = 545,
HRR_API_HIPPOPCALLCONFIGURATION = 546,
HRR_API_HIPPUSHCALLCONFIGURATION = 547,
HRR_API_HIPREGISTERFATBINARY = 548,
HRR_API_HIPREGISTERFUNCTION = 549,
HRR_API_HIPREGISTERMANAGEDVAR = 550,
HRR_API_HIPREGISTERSURFACE = 551,
HRR_API_HIPREGISTERTEXTURE = 552,
HRR_API_HIPREGISTERVAR = 553,
HRR_API_HIPUNREGISTERFATBINARY = 554,
HRR_API_COUNT = 555
} hrr_api_id_t;

/* Array of API names indexed by hrr_api_id_t */
Expand Down Expand Up @@ -6927,6 +6936,7 @@ const char* const hrr_api_names[HRR_API_COUNT] = {
"hipDeviceGetLuid",
"hipInitDevice",
"hipModuleEnumerateFunctions",
"hipDeviceFlushGPUDirectRDMAWrites",
"__hipPopCallConfiguration",
"__hipPushCallConfiguration",
"__hipRegisterFatBinary",
Expand Down
48 changes: 30 additions & 18 deletions projects/hrr/playback/hip_playback_generated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5997,6 +5997,16 @@ static hipError_t playback_hipModuleEnumerateFunctions(PlaybackContext& ctx, con
return hipSuccess;
}

static hipError_t playback_hipDeviceFlushGPUDirectRDMAWrites(PlaybackContext& ctx, const uint8_t* payload) {
const auto* a = reinterpret_cast<const hrr_args_hipDeviceFlushGPUDirectRDMAWrites*>(payload);
hipError_t _r = (hipError_t)hipDeviceFlushGPUDirectRDMAWrites((enum hipFlushGPUDirectRDMAWritesTarget)a->target, (enum hipFlushGPUDirectRDMAWritesScope)a->scope);
if (_r != hipSuccess && a->ret != 0 && static_cast<int32_t>(_r) == a->ret) {
hrr_note_recorded_error(ctx, "hipDeviceFlushGPUDirectRDMAWrites", a->ret);
return hipSuccess;
}
return _r;
}

static hipError_t playback___hipPopCallConfiguration(PlaybackContext& ctx, const uint8_t* payload) {
(void)ctx; (void)payload;
return hipSuccess;
Expand Down Expand Up @@ -6588,15 +6598,16 @@ const uint32_t hrr_api_min_payload_size[HRR_API_COUNT] = {
static_cast<uint32_t>(sizeof(hrr_args_hipDeviceGetLuid)), // [542] HRR_API_HIPDEVICEGETLUID
static_cast<uint32_t>(sizeof(hrr_args_hipInitDevice)), // [543] HRR_API_HIPINITDEVICE
static_cast<uint32_t>(sizeof(hrr_args_hipModuleEnumerateFunctions)), // [544] HRR_API_HIPMODULEENUMERATEFUNCTIONS
static_cast<uint32_t>(sizeof(hrr_args___hipPopCallConfiguration)), // [545] HRR_API_HIPPOPCALLCONFIGURATION
static_cast<uint32_t>(sizeof(hrr_args___hipPushCallConfiguration)), // [546] HRR_API_HIPPUSHCALLCONFIGURATION
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterFatBinary)), // [547] HRR_API_HIPREGISTERFATBINARY
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterFunction)), // [548] HRR_API_HIPREGISTERFUNCTION
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterManagedVar)), // [549] HRR_API_HIPREGISTERMANAGEDVAR
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterSurface)), // [550] HRR_API_HIPREGISTERSURFACE
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterTexture)), // [551] HRR_API_HIPREGISTERTEXTURE
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterVar)), // [552] HRR_API_HIPREGISTERVAR
static_cast<uint32_t>(sizeof(hrr_args___hipUnregisterFatBinary)), // [553] HRR_API_HIPUNREGISTERFATBINARY
static_cast<uint32_t>(sizeof(hrr_args_hipDeviceFlushGPUDirectRDMAWrites)), // [545] HRR_API_HIPDEVICEFLUSHGPUDIRECTRDMAWRITES
static_cast<uint32_t>(sizeof(hrr_args___hipPopCallConfiguration)), // [546] HRR_API_HIPPOPCALLCONFIGURATION
static_cast<uint32_t>(sizeof(hrr_args___hipPushCallConfiguration)), // [547] HRR_API_HIPPUSHCALLCONFIGURATION
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterFatBinary)), // [548] HRR_API_HIPREGISTERFATBINARY
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterFunction)), // [549] HRR_API_HIPREGISTERFUNCTION
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterManagedVar)), // [550] HRR_API_HIPREGISTERMANAGEDVAR
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterSurface)), // [551] HRR_API_HIPREGISTERSURFACE
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterTexture)), // [552] HRR_API_HIPREGISTERTEXTURE
static_cast<uint32_t>(sizeof(hrr_args___hipRegisterVar)), // [553] HRR_API_HIPREGISTERVAR
static_cast<uint32_t>(sizeof(hrr_args___hipUnregisterFatBinary)), // [554] HRR_API_HIPUNREGISTERFATBINARY
};

// ============================================================
Expand Down Expand Up @@ -7148,13 +7159,14 @@ hrr_playback_fn_t hrr_playback_dispatch[HRR_API_COUNT] = {
playback_hipDeviceGetLuid, // [542] HRR_API_HIPDEVICEGETLUID
playback_hipInitDevice, // [543] HRR_API_HIPINITDEVICE
playback_hipModuleEnumerateFunctions, // [544] HRR_API_HIPMODULEENUMERATEFUNCTIONS
playback___hipPopCallConfiguration, // [545] HRR_API_HIPPOPCALLCONFIGURATION
playback___hipPushCallConfiguration, // [546] HRR_API_HIPPUSHCALLCONFIGURATION
playback___hipRegisterFatBinary, // [547] HRR_API_HIPREGISTERFATBINARY
playback___hipRegisterFunction, // [548] HRR_API_HIPREGISTERFUNCTION
playback___hipRegisterManagedVar, // [549] HRR_API_HIPREGISTERMANAGEDVAR
playback___hipRegisterSurface, // [550] HRR_API_HIPREGISTERSURFACE
playback___hipRegisterTexture, // [551] HRR_API_HIPREGISTERTEXTURE
playback___hipRegisterVar, // [552] HRR_API_HIPREGISTERVAR
playback___hipUnregisterFatBinary, // [553] HRR_API_HIPUNREGISTERFATBINARY
playback_hipDeviceFlushGPUDirectRDMAWrites, // [545] HRR_API_HIPDEVICEFLUSHGPUDIRECTRDMAWRITES
playback___hipPopCallConfiguration, // [546] HRR_API_HIPPOPCALLCONFIGURATION
playback___hipPushCallConfiguration, // [547] HRR_API_HIPPUSHCALLCONFIGURATION
playback___hipRegisterFatBinary, // [548] HRR_API_HIPREGISTERFATBINARY
playback___hipRegisterFunction, // [549] HRR_API_HIPREGISTERFUNCTION
playback___hipRegisterManagedVar, // [550] HRR_API_HIPREGISTERMANAGEDVAR
playback___hipRegisterSurface, // [551] HRR_API_HIPREGISTERSURFACE
playback___hipRegisterTexture, // [552] HRR_API_HIPREGISTERTEXTURE
playback___hipRegisterVar, // [553] HRR_API_HIPREGISTERVAR
playback___hipUnregisterFatBinary, // [554] HRR_API_HIPUNREGISTERFATBINARY
};
112 changes: 112 additions & 0 deletions projects/hrr/tests/check_expected_cases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env python3
# Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
"""Assert that a Catch2 binary registers exactly the test cases we expect.

A case behind an #if can leave a binary with no signal whatsoever -- not failed,
not skipped, simply absent -- so a fully green run can hide it. That is how
Unit_HRR_Regions_MemcpyFirstTouchMaterialization stayed invisible through a
106/106 gfx950 run: HRR_HAVE_HSA was never defined anywhere in the tree, so the
case compiled out and no report it could have appeared in ever existed.

This check asserts on the *compiled artifact* rather than on the source, which
is what makes it catch that class of problem. It fails in both directions: a
case that disappears is an error, and so is one that appears unannounced,
because an unreviewed addition is how a manifest silently stops meaning
anything.

Case names come from `--list-tests "*" --reporter xml`. The "*" is required --
without it Catch2 omits hidden `[.]` cases, which is most of the integration
suite. The XML reporter is used rather than the console listing because the
console form is a formatted table, and formatting is not a contract.

Usage:
check_expected_cases.py --binary <exe> --manifest <file>
check_expected_cases.py --binary <exe> --manifest <file> --update
"""

import argparse
import subprocess
import sys
import xml.etree.ElementTree as ET

HEADER = [
"# Test cases expected to be present in this binary, one per line, sorted.",
"# Generated by check_expected_cases.py --update; do not hand-edit casually.",
"#",
"# A diff here is a real finding either way. Cases vanish when a guard stops",
"# being satisfied (a missing -D, a find_package that quietly failed), and",
"# that vanishing is otherwise completely silent. Regenerate only when you",
"# intended to add or remove a case, and say so in the commit message.",
]


def listed_cases(binary: str) -> list[str]:
"""Every case the binary registers, hidden ones included."""
proc = subprocess.run(
[binary, "--list-tests", "*", "--reporter", "xml"],
capture_output=True, text=True,
)
if proc.returncode != 0:
sys.exit(f"error: {binary} --list-tests failed ({proc.returncode})\n"
f"{proc.stderr.strip()}")
try:
root = ET.fromstring(proc.stdout)
except ET.ParseError as exc:
sys.exit(f"error: could not parse --list-tests XML from {binary}: {exc}")
names = [e.text or "" for e in root.iter("Name")]
if not names:
sys.exit(f"error: {binary} listed no test cases at all -- that is itself "
f"the failure this check exists to catch")
return sorted(names)


def read_manifest(path: str) -> list[str]:
try:
with open(path, encoding="utf-8") as fh:
return sorted(ln.strip() for ln in fh
if ln.strip() and not ln.startswith("#"))
except FileNotFoundError:
sys.exit(f"error: manifest {path} not found; create it with --update")


def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("--binary", required=True, help="Catch2 test executable")
ap.add_argument("--manifest", required=True, help="expected-cases file")
ap.add_argument("--update", action="store_true",
help="rewrite the manifest from the binary instead of checking")
args = ap.parse_args(argv)

actual = listed_cases(args.binary)

if args.update:
with open(args.manifest, "w", encoding="utf-8") as fh:
fh.write("\n".join(HEADER) + "\n")
fh.write("\n".join(actual) + "\n")
print(f"wrote {len(actual)} case names to {args.manifest}")
return 0

expected = read_manifest(args.manifest)
missing = [n for n in expected if n not in set(actual)]
unexpected = [n for n in actual if n not in set(expected)]

if not missing and not unexpected:
print(f"OK: {len(actual)} test cases present, matching {args.manifest}")
return 0

print(f"FAIL: {args.binary} does not match {args.manifest}", file=sys.stderr)
print(f" expected {len(expected)} cases, found {len(actual)}", file=sys.stderr)
for n in missing:
print(f" MISSING (compiled out or deleted): {n}", file=sys.stderr)
for n in unexpected:
print(f" UNEXPECTED (added without updating manifest): {n}", file=sys.stderr)
if missing:
print("\nA MISSING case is usually a guard that stopped being satisfied -- "
"check that every -D its #if needs is still passed by CMake.",
file=sys.stderr)
return 1


if __name__ == "__main__":
sys.exit(main())
Loading
Loading