-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathextract_and_replay.py
More file actions
147 lines (122 loc) · 4.71 KB
/
Copy pathextract_and_replay.py
File metadata and controls
147 lines (122 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved.
"""Extract and replay a GPU kernel from the mini_pipeline example.
Demonstrates the full kerncap workflow using the Python API:
1. Compile the mini_pipeline HIP application
2. Profile it to find hot kernels
3. Extract a target kernel into a standalone reproducer
4. Replay the captured kernel in isolation
5. Validate the reproducer for correctness
Prerequisites:
- ROCm installed (hipcc, rocprofv3 on PATH)
- AMD GPU (MI300+ recommended)
- kerncap installed: pip install -e kerncap/
Usage:
python examples/extract_and_replay.py
python examples/extract_and_replay.py --kernel histogram_atomic
python examples/extract_and_replay.py --kernel vector_add --iterations 50
"""
import argparse
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
from kerncap import Kerncap
def compile_mini_pipeline(source: Path, build_dir: Path) -> Path:
"""Compile mini_pipeline.hip and return the path to the binary."""
if not shutil.which("hipcc"):
print("ERROR: hipcc not found. Install ROCm and ensure hipcc is on PATH.")
sys.exit(1)
binary = build_dir / "mini_pipeline"
print(f"Compiling {source.name} ...")
result = subprocess.run(
["hipcc", "-O2", "-g", "-o", str(binary), str(source)],
capture_output=True,
text=True,
)
if result.returncode != 0:
print(f"Compilation failed:\n{result.stderr}")
sys.exit(1)
print(f" Built: {binary}")
return binary
def main() -> None:
parser = argparse.ArgumentParser(
description="Extract and replay a kernel from the mini_pipeline example"
)
parser.add_argument(
"--kernel",
default="vector_scale",
help="Kernel name to extract (default: vector_scale)",
)
parser.add_argument(
"--iterations",
type=int,
default=10,
help="Number of replay iterations for benchmarking (default: 10)",
)
parser.add_argument(
"--output",
type=str,
default=None,
help="Output directory for the reproducer (default: temp directory)",
)
args = parser.parse_args()
examples_dir = Path(__file__).resolve().parent
hip_source = examples_dir / "mini_pipeline.hip"
if not hip_source.exists():
print(f"ERROR: {hip_source} not found")
sys.exit(1)
kc = Kerncap()
with tempfile.TemporaryDirectory(prefix="kerncap_example_") as tmpdir:
build_dir = Path(tmpdir) / "build"
build_dir.mkdir()
binary = compile_mini_pipeline(hip_source, build_dir)
# --- 1. Profile ---
print("\n--- Profile ---")
profile = kc.profile([str(binary)])
print(f" Found {len(profile)} kernel(s):")
for k in profile[:10]:
print(f" {k.name}: {k.total_duration_ns / 1e6:.2f} ms ({k.percentage:.1f}%)")
matching = [k for k in profile if args.kernel in k.name]
if not matching:
print(f"\nERROR: kernel '{args.kernel}' not found in profile.")
print("Available kernels:", ", ".join(k.name for k in profile))
sys.exit(1)
target = matching[0].name
print(f"\n Target kernel: {target}")
# --- 2. Extract ---
output_dir = args.output or str(Path(tmpdir) / "reproducer")
print(f"\n--- Extract (kernel={args.kernel}) ---")
result = kc.extract(
kernel_name=args.kernel,
cmd=[str(binary)],
source_dir=str(build_dir),
output=output_dir,
)
print(f" Reproducer: {result.output_dir}")
print(f" Has source: {result.has_source}")
# --- 3. Replay ---
print(f"\n--- Replay (iterations={args.iterations}) ---")
replay = kc.replay(result.output_dir, iterations=args.iterations)
if replay.returncode != 0:
print(f" Replay failed (rc={replay.returncode}):")
print(f" {replay.stderr}")
sys.exit(1)
if replay.timing_us is not None:
print(f" Average kernel time: {replay.timing_us:.1f} us")
else:
print(f" Replay output:\n{replay.stdout}")
# --- 4. Validate ---
print("\n--- Validate ---")
validation = kc.validate(result.output_dir)
print(f" Passed: {validation.passed}")
if not validation.passed:
print(f" Details: {validation.details}")
# Keep the reproducer around if the user specified --output
if args.output:
print(f"\nReproducer saved to: {result.output_dir}")
print("To replay manually:")
print(f" cd {result.output_dir} && make run")
if __name__ == "__main__":
main()