wafer-cli 0.2.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wafer/GUIDE.md +118 -0
- wafer/__init__.py +3 -0
- wafer/analytics.py +306 -0
- wafer/api_client.py +195 -0
- wafer/auth.py +432 -0
- wafer/autotuner.py +1080 -0
- wafer/billing.py +233 -0
- wafer/cli.py +7289 -0
- wafer/config.py +105 -0
- wafer/corpus.py +366 -0
- wafer/evaluate.py +4593 -0
- wafer/global_config.py +350 -0
- wafer/gpu_run.py +307 -0
- wafer/inference.py +148 -0
- wafer/kernel_scope.py +552 -0
- wafer/ncu_analyze.py +651 -0
- wafer/nsys_analyze.py +1042 -0
- wafer/nsys_profile.py +510 -0
- wafer/output.py +248 -0
- wafer/problems.py +357 -0
- wafer/rocprof_compute.py +490 -0
- wafer/rocprof_sdk.py +274 -0
- wafer/rocprof_systems.py +520 -0
- wafer/skills/wafer-guide/SKILL.md +129 -0
- wafer/ssh_keys.py +261 -0
- wafer/target_lock.py +270 -0
- wafer/targets.py +842 -0
- wafer/targets_ops.py +717 -0
- wafer/templates/__init__.py +0 -0
- wafer/templates/ask_docs.py +61 -0
- wafer/templates/optimize_kernel.py +71 -0
- wafer/templates/optimize_kernelbench.py +137 -0
- wafer/templates/trace_analyze.py +74 -0
- wafer/tracelens.py +218 -0
- wafer/wevin_cli.py +577 -0
- wafer/workspaces.py +852 -0
- wafer_cli-0.2.14.dist-info/METADATA +16 -0
- wafer_cli-0.2.14.dist-info/RECORD +41 -0
- wafer_cli-0.2.14.dist-info/WHEEL +5 -0
- wafer_cli-0.2.14.dist-info/entry_points.txt +2 -0
- wafer_cli-0.2.14.dist-info/top_level.txt +1 -0
wafer/rocprof_compute.py
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"""ROCprof-Compute - CLI wrapper for rocprof-compute tool.
|
|
2
|
+
|
|
3
|
+
This module provides the CLI wrapper for the `wafer rocprof-compute` command.
|
|
4
|
+
It supports multiple subcommands:
|
|
5
|
+
- check: Check rocprof-compute installation
|
|
6
|
+
- profile: Run profiling on a command
|
|
7
|
+
- analyze: Analyze existing workload data
|
|
8
|
+
- gui: Launch GUI viewer for analyzing results
|
|
9
|
+
- list-metrics: List available metrics for architecture
|
|
10
|
+
|
|
11
|
+
This follows the design in Wafer-391: ROCprofiler Tools Architecture.
|
|
12
|
+
Architecture follows similar patterns from the codebase.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import subprocess
|
|
17
|
+
import sys
|
|
18
|
+
from dataclasses import asdict
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def print_usage() -> None:
|
|
23
|
+
"""Print CLI usage information."""
|
|
24
|
+
print("Usage: wafer rocprof-compute <subcommand> [options]", file=sys.stderr)
|
|
25
|
+
print("", file=sys.stderr)
|
|
26
|
+
print("Subcommands:", file=sys.stderr)
|
|
27
|
+
print(" check Check rocprof-compute installation status", file=sys.stderr)
|
|
28
|
+
print(" profile COMMAND Profile a command", file=sys.stderr)
|
|
29
|
+
print(" analyze PATH Analyze existing workload", file=sys.stderr)
|
|
30
|
+
print(" gui <folder> Launch GUI viewer for profiling results", file=sys.stderr)
|
|
31
|
+
print(" list-metrics ARCH List metrics for architecture", file=sys.stderr)
|
|
32
|
+
print("", file=sys.stderr)
|
|
33
|
+
print("Profile Options:", file=sys.stderr)
|
|
34
|
+
print(" --name NAME Workload name (required)", file=sys.stderr)
|
|
35
|
+
print(" --path DIR Workload base path", file=sys.stderr)
|
|
36
|
+
print(" --kernel K1,K2 Kernel name filter", file=sys.stderr)
|
|
37
|
+
print(" --dispatch D1,D2 Dispatch ID filter", file=sys.stderr)
|
|
38
|
+
print(" --block B1,B2 Hardware block filter", file=sys.stderr)
|
|
39
|
+
print(" --no-roof Skip roofline data", file=sys.stderr)
|
|
40
|
+
print(" --roof-only Profile roofline only (fastest)", file=sys.stderr)
|
|
41
|
+
print(" --hip-trace Enable HIP trace", file=sys.stderr)
|
|
42
|
+
print("", file=sys.stderr)
|
|
43
|
+
print("Analyze Options:", file=sys.stderr)
|
|
44
|
+
print(" --list-stats List all detected kernels and dispatches", file=sys.stderr)
|
|
45
|
+
print("", file=sys.stderr)
|
|
46
|
+
print("GUI Options:", file=sys.stderr)
|
|
47
|
+
print(" --port PORT Port for GUI server (default: 8050)", file=sys.stderr)
|
|
48
|
+
print(" --json Output result as JSON", file=sys.stderr)
|
|
49
|
+
print(" --external Use external rocprof-compute binary (default: bundled)", file=sys.stderr)
|
|
50
|
+
print("", file=sys.stderr)
|
|
51
|
+
print("Examples:", file=sys.stderr)
|
|
52
|
+
print(" wafer rocprof-compute check", file=sys.stderr)
|
|
53
|
+
print(" wafer rocprof-compute profile --name vcopy -- './vcopy -n 1048576'", file=sys.stderr)
|
|
54
|
+
print(" wafer rocprof-compute profile --name vcopy --roof-only -- './vcopy -n 1048576'", file=sys.stderr)
|
|
55
|
+
print(" wafer rocprof-compute analyze ./workloads/vcopy", file=sys.stderr)
|
|
56
|
+
print(" wafer rocprof-compute analyze ./workloads/vcopy --list-stats", file=sys.stderr)
|
|
57
|
+
print(" wafer rocprof-compute gui ./workloads/vcopy", file=sys.stderr)
|
|
58
|
+
print(" wafer rocprof-compute list-metrics gfx90a", file=sys.stderr)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def check_command(json_output: bool = False) -> str:
|
|
62
|
+
"""CLI wrapper for checking rocprof-compute installation.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
json_output: If True, return JSON; otherwise print human-readable
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Status message or JSON string
|
|
69
|
+
"""
|
|
70
|
+
from dataclasses import asdict
|
|
71
|
+
|
|
72
|
+
from wafer_core.lib.rocprofiler.compute import (
|
|
73
|
+
check_installation as core_check, # pragma: no cover
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
result = core_check()
|
|
77
|
+
|
|
78
|
+
if json_output:
|
|
79
|
+
result_dict = asdict(result) if hasattr(result, "__dataclass_fields__") else result
|
|
80
|
+
return json.dumps(result_dict, indent=2)
|
|
81
|
+
else:
|
|
82
|
+
if result.installed:
|
|
83
|
+
print("✓ rocprof-compute is installed", file=sys.stderr)
|
|
84
|
+
if result.path:
|
|
85
|
+
print(f" Path: {result.path}", file=sys.stderr)
|
|
86
|
+
if result.version:
|
|
87
|
+
print(f" Version: {result.version}", file=sys.stderr)
|
|
88
|
+
return "rocprof-compute is installed"
|
|
89
|
+
else:
|
|
90
|
+
print("✗ rocprof-compute is not installed", file=sys.stderr)
|
|
91
|
+
print("", file=sys.stderr)
|
|
92
|
+
print("rocprof-compute is required to use this feature.", file=sys.stderr)
|
|
93
|
+
print("", file=sys.stderr)
|
|
94
|
+
print("Installation options:", file=sys.stderr)
|
|
95
|
+
print(" 1. Install ROCm toolkit (includes rocprof-compute):", file=sys.stderr)
|
|
96
|
+
print(" sudo apt-get install rocm-dev", file=sys.stderr)
|
|
97
|
+
print("", file=sys.stderr)
|
|
98
|
+
print(" 2. Install rocprofiler-compute package:", file=sys.stderr)
|
|
99
|
+
print(" sudo apt-get install rocprofiler-compute", file=sys.stderr)
|
|
100
|
+
print("", file=sys.stderr)
|
|
101
|
+
print(" 3. Add ROCm to PATH if already installed:", file=sys.stderr)
|
|
102
|
+
print(" export PATH=/opt/rocm/bin:$PATH", file=sys.stderr)
|
|
103
|
+
print("", file=sys.stderr)
|
|
104
|
+
if result.install_command:
|
|
105
|
+
print(f"Suggested command: {result.install_command}", file=sys.stderr)
|
|
106
|
+
return "rocprof-compute is not installed"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def check_installation() -> dict:
|
|
110
|
+
"""Legacy function for backward compatibility."""
|
|
111
|
+
from dataclasses import asdict
|
|
112
|
+
|
|
113
|
+
from wafer_core.lib.rocprofiler.compute import (
|
|
114
|
+
check_installation as core_check, # pragma: no cover
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
result = core_check()
|
|
118
|
+
if hasattr(result, "__dataclass_fields__"):
|
|
119
|
+
return asdict(result)
|
|
120
|
+
elif hasattr(result, "__dict__"):
|
|
121
|
+
return result.__dict__
|
|
122
|
+
return result
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def gui_command(
|
|
126
|
+
folder_path: str,
|
|
127
|
+
port: int = 8050,
|
|
128
|
+
json_output: bool = False,
|
|
129
|
+
use_bundled: bool = True,
|
|
130
|
+
) -> str:
|
|
131
|
+
"""Launch rocprof-compute analyze GUI.
|
|
132
|
+
|
|
133
|
+
By default, uses the bundled GUI viewer (GPU-agnostic, works on any platform).
|
|
134
|
+
Can optionally use external rocprof-compute binary if installed.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
folder_path: Path to folder containing ROCprofiler results
|
|
138
|
+
port: Port number for the GUI server (default: 8050)
|
|
139
|
+
json_output: If True, return JSON with status; otherwise launch the GUI
|
|
140
|
+
use_bundled: If True, use bundled GUI viewer (default: True)
|
|
141
|
+
If False, use external rocprof-compute binary
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Success message or JSON output
|
|
145
|
+
|
|
146
|
+
Raises:
|
|
147
|
+
FileNotFoundError: If folder doesn't exist
|
|
148
|
+
RuntimeError: If launch fails
|
|
149
|
+
"""
|
|
150
|
+
from dataclasses import asdict
|
|
151
|
+
|
|
152
|
+
if use_bundled:
|
|
153
|
+
# Use bundled GUI viewer (no rocprof-compute needed)
|
|
154
|
+
from wafer_core.lib.rocprofiler.compute import launch_gui_server # pragma: no cover
|
|
155
|
+
|
|
156
|
+
# For JSON mode, run in background to return immediately
|
|
157
|
+
# For interactive mode, run in foreground (blocking)
|
|
158
|
+
launch_result = launch_gui_server(folder_path, port, background=json_output)
|
|
159
|
+
|
|
160
|
+
if not launch_result.success:
|
|
161
|
+
raise RuntimeError(launch_result.error or "Failed to launch bundled GUI")
|
|
162
|
+
|
|
163
|
+
result_dict = asdict(launch_result)
|
|
164
|
+
result_dict["command"] = "bundled-gui-viewer"
|
|
165
|
+
|
|
166
|
+
if json_output:
|
|
167
|
+
return json.dumps(result_dict, indent=2)
|
|
168
|
+
else:
|
|
169
|
+
print("Launching bundled rocprof-compute GUI viewer...", file=sys.stderr)
|
|
170
|
+
print(f"Folder: {launch_result.folder}", file=sys.stderr)
|
|
171
|
+
print(f"Port: {launch_result.port}", file=sys.stderr)
|
|
172
|
+
print(f"URL: {launch_result.url}", file=sys.stderr)
|
|
173
|
+
print("", file=sys.stderr)
|
|
174
|
+
print(f"Open {launch_result.url} in your browser", file=sys.stderr)
|
|
175
|
+
print("Press Ctrl+C to stop the server", file=sys.stderr)
|
|
176
|
+
|
|
177
|
+
# The launch_gui_server with background=False is blocking, so we never reach here
|
|
178
|
+
# unless there's an error
|
|
179
|
+
return "GUI server stopped."
|
|
180
|
+
else:
|
|
181
|
+
# Legacy: use external rocprof-compute binary
|
|
182
|
+
from wafer_core.lib.rocprofiler.compute import launch_gui as core_launch # pragma: no cover
|
|
183
|
+
|
|
184
|
+
launch_result = core_launch(folder_path, port)
|
|
185
|
+
|
|
186
|
+
if not launch_result.success:
|
|
187
|
+
raise RuntimeError(launch_result.error or "Failed to launch GUI")
|
|
188
|
+
|
|
189
|
+
result_dict = asdict(launch_result)
|
|
190
|
+
result_dict["command"] = " ".join(launch_result.command or [])
|
|
191
|
+
|
|
192
|
+
if json_output:
|
|
193
|
+
return json.dumps(result_dict, indent=2)
|
|
194
|
+
else:
|
|
195
|
+
print("Launching external rocprof-compute GUI...", file=sys.stderr)
|
|
196
|
+
print(f"Folder: {launch_result.folder}", file=sys.stderr)
|
|
197
|
+
print(f"Port: {launch_result.port}", file=sys.stderr)
|
|
198
|
+
print(f"URL: {launch_result.url}", file=sys.stderr)
|
|
199
|
+
print(f"Command: {result_dict['command']}", file=sys.stderr)
|
|
200
|
+
print("", file=sys.stderr)
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
subprocess.run(launch_result.command, check=True)
|
|
204
|
+
except subprocess.CalledProcessError as e:
|
|
205
|
+
raise RuntimeError(f"rocprof-compute failed with exit code {e.returncode}")
|
|
206
|
+
except KeyboardInterrupt:
|
|
207
|
+
print("\nGUI server stopped.", file=sys.stderr)
|
|
208
|
+
|
|
209
|
+
return "GUI server stopped."
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def launch_gui(
|
|
213
|
+
folder_path: str,
|
|
214
|
+
port: int = 8050,
|
|
215
|
+
json_output: bool = False,
|
|
216
|
+
use_bundled: bool = True,
|
|
217
|
+
) -> str:
|
|
218
|
+
"""Legacy function for backward compatibility. Use gui_command() instead."""
|
|
219
|
+
return gui_command(folder_path, port, json_output, use_bundled)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def profile_command(
|
|
223
|
+
command: str,
|
|
224
|
+
name: str,
|
|
225
|
+
path: str | None = None,
|
|
226
|
+
kernel: str | None = None,
|
|
227
|
+
dispatch: str | None = None,
|
|
228
|
+
block: str | None = None,
|
|
229
|
+
no_roof: bool = False,
|
|
230
|
+
roof_only: bool = False,
|
|
231
|
+
hip_trace: bool = False,
|
|
232
|
+
verbose: int = 0,
|
|
233
|
+
json_output: bool = False,
|
|
234
|
+
) -> str:
|
|
235
|
+
"""Run rocprof-compute profiling.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
command: Shell command to profile
|
|
239
|
+
name: Workload name
|
|
240
|
+
path: Base path for workload directory
|
|
241
|
+
kernel: Comma-separated kernel name filters
|
|
242
|
+
dispatch: Comma-separated dispatch ID filters
|
|
243
|
+
block: Comma-separated hardware block filters
|
|
244
|
+
no_roof: Skip roofline data collection
|
|
245
|
+
roof_only: Profile roofline data only (fastest)
|
|
246
|
+
hip_trace: Enable HIP trace
|
|
247
|
+
verbose: Verbosity level (0-3)
|
|
248
|
+
json_output: Return JSON output
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Success message or JSON string
|
|
252
|
+
|
|
253
|
+
Raises:
|
|
254
|
+
RuntimeError: If profiling fails
|
|
255
|
+
"""
|
|
256
|
+
import shlex
|
|
257
|
+
|
|
258
|
+
from wafer_core.lib.rocprofiler.compute import run_profile # pragma: no cover
|
|
259
|
+
|
|
260
|
+
# Parse command string
|
|
261
|
+
cmd_list = shlex.split(command)
|
|
262
|
+
|
|
263
|
+
# Parse filter lists
|
|
264
|
+
kernel_list = kernel.split(",") if kernel else None
|
|
265
|
+
dispatch_list = [int(d) for d in dispatch.split(",")] if dispatch else None
|
|
266
|
+
block_list = block.split(",") if block else None
|
|
267
|
+
|
|
268
|
+
result = run_profile(
|
|
269
|
+
target_command=cmd_list,
|
|
270
|
+
workload_name=name,
|
|
271
|
+
workload_path=Path(path) if path else None,
|
|
272
|
+
kernel_filter=kernel_list,
|
|
273
|
+
dispatch_filter=dispatch_list,
|
|
274
|
+
block_filter=block_list,
|
|
275
|
+
no_roof=no_roof,
|
|
276
|
+
roof_only=roof_only,
|
|
277
|
+
hip_trace=hip_trace,
|
|
278
|
+
verbose=verbose,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
if json_output:
|
|
282
|
+
result_dict = asdict(result)
|
|
283
|
+
return json.dumps(result_dict, indent=2)
|
|
284
|
+
else:
|
|
285
|
+
if result.success:
|
|
286
|
+
print("✓ Profiling completed", file=sys.stderr)
|
|
287
|
+
if result.workload_path:
|
|
288
|
+
print(f" Workload: {result.workload_path}", file=sys.stderr)
|
|
289
|
+
if result.output_files:
|
|
290
|
+
print(f" Generated {len(result.output_files)} files", file=sys.stderr)
|
|
291
|
+
return f"Results in: {result.workload_path}"
|
|
292
|
+
else:
|
|
293
|
+
print("✗ Profiling failed", file=sys.stderr)
|
|
294
|
+
print("", file=sys.stderr)
|
|
295
|
+
|
|
296
|
+
# Show stderr output (contains actual error details)
|
|
297
|
+
# Note: rocprof-compute may write errors to stdout instead of stderr
|
|
298
|
+
error_output = result.stderr or result.stdout
|
|
299
|
+
if error_output and error_output.strip():
|
|
300
|
+
print("rocprof-compute output:", file=sys.stderr)
|
|
301
|
+
print("─" * 60, file=sys.stderr)
|
|
302
|
+
print(error_output.strip(), file=sys.stderr)
|
|
303
|
+
print("─" * 60, file=sys.stderr)
|
|
304
|
+
print("", file=sys.stderr)
|
|
305
|
+
|
|
306
|
+
# Show command that was run
|
|
307
|
+
if result.command:
|
|
308
|
+
print(f"Command: {' '.join(result.command)}", file=sys.stderr)
|
|
309
|
+
print("", file=sys.stderr)
|
|
310
|
+
|
|
311
|
+
# Show high-level error
|
|
312
|
+
if result.error:
|
|
313
|
+
print(f"Error: {result.error}", file=sys.stderr)
|
|
314
|
+
|
|
315
|
+
# Create helpful error message
|
|
316
|
+
# Check both stderr and stdout since rocprof-compute may use either
|
|
317
|
+
combined_output = (result.stderr or "") + (result.stdout or "")
|
|
318
|
+
error_msg = "Profiling failed"
|
|
319
|
+
if "error while loading shared libraries" in combined_output.lower():
|
|
320
|
+
error_msg += "\n\nThis looks like a missing dependency. Check the output above for the specific library."
|
|
321
|
+
elif "not found" in combined_output.lower() or "no such file" in combined_output.lower():
|
|
322
|
+
error_msg += "\n\nThe command or a required file was not found. Check the paths above."
|
|
323
|
+
elif "distribution does not meet version requirements" in combined_output.lower():
|
|
324
|
+
error_msg += "\n\nThis looks like a Python dependency version mismatch. Check the output above for the specific package."
|
|
325
|
+
elif result.error and "exit code" in result.error.lower():
|
|
326
|
+
error_msg += "\n\nThe profiling tool exited with an error. See output above for details."
|
|
327
|
+
|
|
328
|
+
raise RuntimeError(error_msg)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def analyze_command(
|
|
332
|
+
workload_path: str,
|
|
333
|
+
kernel: str | None = None,
|
|
334
|
+
dispatch: str | None = None,
|
|
335
|
+
block: str | None = None,
|
|
336
|
+
output: str | None = None,
|
|
337
|
+
list_stats: bool = False,
|
|
338
|
+
json_output: bool = False,
|
|
339
|
+
gui: bool = False,
|
|
340
|
+
port: int = 8050,
|
|
341
|
+
external: bool = False,
|
|
342
|
+
) -> str:
|
|
343
|
+
"""Analyze rocprof-compute workload.
|
|
344
|
+
|
|
345
|
+
This calls the native rocprof-compute analyze tool to generate comprehensive
|
|
346
|
+
analysis output matching what you get from running rocprof-compute directly.
|
|
347
|
+
|
|
348
|
+
For programmatic access to parsed data (without running the native tool),
|
|
349
|
+
use parse_workload() from the Python API instead.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
workload_path: Path to workload directory
|
|
353
|
+
kernel: Comma-separated kernel filters
|
|
354
|
+
dispatch: Comma-separated dispatch filters
|
|
355
|
+
block: Comma-separated block filters
|
|
356
|
+
output: Output file path
|
|
357
|
+
list_stats: List all detected kernels and dispatches
|
|
358
|
+
json_output: Return JSON output (uses parse_workload for structured data)
|
|
359
|
+
gui: Launch GUI viewer instead of text analysis
|
|
360
|
+
port: Port for GUI server (default: 8050)
|
|
361
|
+
external: Use external rocprof-compute binary for GUI (default: bundled)
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
Analysis output or JSON string
|
|
365
|
+
|
|
366
|
+
Raises:
|
|
367
|
+
RuntimeError: If analysis fails
|
|
368
|
+
"""
|
|
369
|
+
from wafer_core.lib.rocprofiler.compute import parse_workload, run_analysis # pragma: no cover
|
|
370
|
+
|
|
371
|
+
# If GUI mode, delegate to GUI launch
|
|
372
|
+
if gui:
|
|
373
|
+
return gui_command(workload_path, port, json_output, use_bundled=not external)
|
|
374
|
+
|
|
375
|
+
# For JSON output, use parse_workload (fast CSV parsing)
|
|
376
|
+
if json_output:
|
|
377
|
+
result = parse_workload(workload_path)
|
|
378
|
+
result_dict = asdict(result)
|
|
379
|
+
# Convert dataclass lists to dicts
|
|
380
|
+
if result.kernels:
|
|
381
|
+
result_dict["kernels"] = [asdict(k) for k in result.kernels]
|
|
382
|
+
if result.roofline:
|
|
383
|
+
result_dict["roofline"] = [asdict(r) for r in result.roofline]
|
|
384
|
+
return json.dumps(result_dict, indent=2)
|
|
385
|
+
|
|
386
|
+
# For text output, call native rocprof-compute analyze for full output
|
|
387
|
+
# Parse filter lists
|
|
388
|
+
kernel_list = kernel.split(",") if kernel else None
|
|
389
|
+
dispatch_list = [int(d) for d in dispatch.split(",")] if dispatch else None
|
|
390
|
+
block_list = block.split(",") if block else None
|
|
391
|
+
|
|
392
|
+
result = run_analysis(
|
|
393
|
+
workload_path=workload_path,
|
|
394
|
+
kernel_filter=kernel_list,
|
|
395
|
+
dispatch_filter=dispatch_list,
|
|
396
|
+
block_filter=block_list,
|
|
397
|
+
output_file=output,
|
|
398
|
+
list_stats=list_stats,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
if result.success:
|
|
402
|
+
# Output is already streamed in real-time by run_analysis
|
|
403
|
+
# Just return success message
|
|
404
|
+
return "Analysis completed"
|
|
405
|
+
else:
|
|
406
|
+
print("✗ Analysis failed", file=sys.stderr)
|
|
407
|
+
print("", file=sys.stderr)
|
|
408
|
+
|
|
409
|
+
# Show stderr output (contains actual error details)
|
|
410
|
+
# Note: rocprof-compute may write errors to stdout instead of stderr
|
|
411
|
+
error_output = result.stderr or result.stdout
|
|
412
|
+
if error_output and error_output.strip():
|
|
413
|
+
print("rocprof-compute output:", file=sys.stderr)
|
|
414
|
+
print("─" * 60, file=sys.stderr)
|
|
415
|
+
print(error_output.strip(), file=sys.stderr)
|
|
416
|
+
print("─" * 60, file=sys.stderr)
|
|
417
|
+
print("", file=sys.stderr)
|
|
418
|
+
|
|
419
|
+
# Show command that was run
|
|
420
|
+
if result.command:
|
|
421
|
+
print(f"Command: {' '.join(result.command)}", file=sys.stderr)
|
|
422
|
+
print("", file=sys.stderr)
|
|
423
|
+
|
|
424
|
+
# Show high-level error
|
|
425
|
+
if result.error:
|
|
426
|
+
print(f"Error: {result.error}", file=sys.stderr)
|
|
427
|
+
|
|
428
|
+
# Create helpful error message
|
|
429
|
+
# Check both stderr and stdout since rocprof-compute may use either
|
|
430
|
+
combined_output = (result.stderr or "") + (result.stdout or "")
|
|
431
|
+
error_msg = "Analysis failed"
|
|
432
|
+
if "error while loading shared libraries" in combined_output.lower():
|
|
433
|
+
error_msg += "\n\nThis looks like a missing dependency. Check the output above for the specific library."
|
|
434
|
+
elif "not found" in combined_output.lower() or "no such file" in combined_output.lower():
|
|
435
|
+
error_msg += "\n\nThe workload directory or required files were not found. Check the path above."
|
|
436
|
+
elif "distribution does not meet version requirements" in combined_output.lower():
|
|
437
|
+
error_msg += "\n\nThis looks like a Python dependency version mismatch. Check the output above for the specific package."
|
|
438
|
+
elif result.error and "exit code" in result.error.lower():
|
|
439
|
+
error_msg += "\n\nThe analysis tool exited with an error. See output above for details."
|
|
440
|
+
|
|
441
|
+
raise RuntimeError(error_msg)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def list_metrics_command(arch: str) -> str:
|
|
445
|
+
"""List available metrics for architecture.
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
arch: Architecture name (e.g., "gfx90a", "gfx942")
|
|
449
|
+
|
|
450
|
+
Returns:
|
|
451
|
+
Metrics list output
|
|
452
|
+
"""
|
|
453
|
+
import os
|
|
454
|
+
import shutil
|
|
455
|
+
import subprocess
|
|
456
|
+
|
|
457
|
+
from wafer_core.lib.rocprofiler.compute import find_rocprof_compute # pragma: no cover
|
|
458
|
+
|
|
459
|
+
rocprof_path = find_rocprof_compute()
|
|
460
|
+
if not rocprof_path:
|
|
461
|
+
raise RuntimeError("rocprof-compute not found. Install ROCm toolkit.")
|
|
462
|
+
|
|
463
|
+
# Build command: rocprof-compute profile --list-metrics <arch>
|
|
464
|
+
cmd = [rocprof_path, "profile", "--list-metrics", arch]
|
|
465
|
+
|
|
466
|
+
# Preserve terminal formatting
|
|
467
|
+
env = os.environ.copy()
|
|
468
|
+
env['TERM'] = 'xterm-256color'
|
|
469
|
+
env['FORCE_COLOR'] = '1'
|
|
470
|
+
env['COLUMNS'] = str(shutil.get_terminal_size().columns)
|
|
471
|
+
env['LINES'] = str(shutil.get_terminal_size().lines)
|
|
472
|
+
|
|
473
|
+
result = subprocess.run(
|
|
474
|
+
cmd,
|
|
475
|
+
capture_output=True,
|
|
476
|
+
text=True,
|
|
477
|
+
env=env
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
if result.returncode == 0:
|
|
481
|
+
print(result.stdout, end='')
|
|
482
|
+
return result.stdout
|
|
483
|
+
else:
|
|
484
|
+
print(f"✗ Failed to list metrics for {arch}", file=sys.stderr)
|
|
485
|
+
if result.stderr:
|
|
486
|
+
print("Error output:", file=sys.stderr)
|
|
487
|
+
print(result.stderr, file=sys.stderr)
|
|
488
|
+
if result.stdout:
|
|
489
|
+
print(result.stdout, file=sys.stderr)
|
|
490
|
+
raise RuntimeError(f"Failed to list metrics for {arch}")
|