Skip to content
Merged
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
259 changes: 210 additions & 49 deletions docs/adapters.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ The supported tools are grouped as follows:
| Family | Tools |
| --- | --- |
| Workspace | `initialize_workspace`, `workspace_status`, `workload_configuration_status`, `configure_workload`, `list_capabilities`, `start_capability_setup`, `get_capability_setup`, `cancel_capability_setup`, `prepare_adapter`, `prepare_workload_dependencies`, `validate_workspace` |
| Capture and import | `plan_capture`, `execute_capture_plan`, `import_artifact`, `import_nvbench`, `import_kernel_build`, `extract_benchmark_samples`, `extract_pyperf`, `extract_python_startup`, `extract_pytest`, `extract_coverage`, `extract_memray`, `extract_perfetto`, `extract_nsight_systems`, `extract_kernel_validation`, `extract_compute_sanitizer`, `extract_nvbench`, `extract_observations` |
| Capture and import | `plan_capture`, `execute_capture_plan`, `import_artifact`, `import_nvbench`, `import_kernel_build`, `extract_benchmark_samples`, `extract_pyperf`, `extract_python_startup`, `extract_pytest`, `extract_coverage`, `extract_memray`, `extract_perfetto`, `extract_nsight_systems`, `extract_kernel_validation`, `extract_compute_sanitizer`, `extract_nvbench`, `extract_nsight_compute`, `extract_observations` |
| Detached capture | `start_detached_capture`, `get_detached_capture`, `cancel_detached_capture` |
| Discovery | `list_declared_workflows`, `get_declared_workflow`, `list_runs`, `list_findings` |
| Investigations | `create_investigation`, `list_investigations`, `get_investigation`, `record_hypothesis`, `get_hypothesis` |
Expand Down
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ readme = "README.md"
license = "MIT"
requires-python = ">=3.12"
dependencies = [
"defusedxml>=0.7.1,<0.8",
"anyio>=4.9,<5",
"duckdb>=1.5.4,<1.6",
"defusedxml>=0.7.1,<0.8",
"ijson>=3.4,<4",
"mcp==2.0.0",
"mcp-types==2.0.0",
Expand Down Expand Up @@ -87,7 +87,6 @@ packages = ["src/flameox"]
addopts = "-ra --strict-config --strict-markers --durations=10 -p no:randomly -m 'not performance and not optional and not process'"
testpaths = ["tests"]
markers = [
"requires_compute_sanitizer: requires NVIDIA Compute Sanitizer and a compatible GPU",
"unit: deterministic tests for one semantic owner",
"integration: tests crossing two or more Flameox services",
"process: tests that spawn, transport to, or cancel another process",
Expand All @@ -104,6 +103,9 @@ markers = [
"requires_systemd: requires a systemd user manager",
"requires_toxiproxy: requires the pinned Toxiproxy server binary",
"requires_torch: requires the optional PyTorch provider",
"requires_compute_sanitizer: requires NVIDIA Compute Sanitizer and a compatible GPU",
"requires_ncu: requires NVIDIA Nsight Compute and its official Python report interface",
"requires_rocprofv3: requires rocprofv3 and a compatible AMD GPU",
"requires_triton: requires the optional Triton provider and a compatible GPU",
"requires_nvbench: requires a configured NVBench benchmark executable and compatible GPU",
"requires_cute: requires the optional CuTe DSL provider and a compatible GPU",
Expand Down
7 changes: 6 additions & 1 deletion src/flameox/adapters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from flameox.adapters.kernel_build import * # noqa: F403
from flameox.adapters.kernel_validation import * # noqa: F403
from flameox.adapters.memray import * # noqa: F403
from flameox.adapters.nsight_compute import * # noqa: F403
from flameox.adapters.nsight_systems import * # noqa: F403
from flameox.adapters.nvbench import * # noqa: F403
from flameox.adapters.observations import * # noqa: F403
Expand All @@ -31,13 +32,14 @@
_MODULES = (
"benchmark_samples",
"client_setup",
"compute_sanitizer",
"coverage",
"compute_sanitizer",
"inference",
"kernel_build",
"kernel_validation",
"memray",
"nsight_systems",
"nsight_compute",
"nvbench",
"observations",
"options",
Expand Down Expand Up @@ -89,6 +91,9 @@
"MooncakeRequestRow",
"MooncakeTraceParser",
"MooncakeTraceSummary",
"NsightComputeExtractionResult",
"NsightComputeExtractor",
"NsightComputeOptions",
"NsightSystemsExtractionResult",
"NsightSystemsExtractor",
"NvbenchBenchmark",
Expand Down
155 changes: 154 additions & 1 deletion src/flameox/adapters/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
compute_sanitizer_options,
compute_sanitizer_suppression_path,
cute_compiler_options,
nsight_compute_options,
nvbench_options,
rocprofv3_options,
triton_compiler_options,
)
from flameox.adapters.torch_profiler import SdkTorchProfilerOptions, torch_profiler_options
Expand Down Expand Up @@ -282,6 +284,63 @@ class CaptureInvocation:
),
preserve_artifact_on_nonzero=True,
),
BuiltinAdapter(
name="rocprofv3",
dependency_kind="executable",
dependency="rocprofv3",
supported_modes=("pftrace",),
supported_formats=("pftrace",),
features=(
"hip_api",
"kernel_dispatch",
"memory_copy",
"memory_allocation",
"scratch_memory",
"marker_ranges",
),
remediation=(
"Install rocprofiler-sdk with rocprofv3 from ROCm and verify AMD GPU access.",
),
version_args=("--version",),
supported_platforms=("linux",),
output_filename="rocprofv3_results.pftrace",
artifact_kinds=(ArtifactKind.EXECUTION_TRACE,),
expected_overhead=(
"ROCm tracing overhead depends on the selected API, dispatch, memory, scratch, "
"and marker domains."
),
capture_limitations=(
"PFTrace contains only the explicitly selected rocprofv3 trace domains.",
"Counter collection and the raw rocprofiler SDK are not enabled.",
),
preserve_artifact_on_nonzero=True,
),
BuiltinAdapter(
name="nsight.compute",
dependency_kind="executable",
dependency="ncu",
supported_modes=("profile",),
supported_formats=("ncu-rep", "ncu-repz"),
features=("gpu_metrics", "report_sections", "rules", "source_correlation"),
remediation=(
"Install NVIDIA Nsight Compute and grant access to NVIDIA GPU performance "
"counters.",
),
version_args=("--version",),
permissions=("nvidia_gpu_performance_counters",),
supported_platforms=("linux", "windows"),
output_filename="nsight-compute.ncu-rep",
artifact_kinds=(ArtifactKind.KERNEL_PROFILE,),
expected_overhead=(
"Kernel replay and metric collection can substantially change execution time."
),
capture_limitations=(
"Only the selected set or explicit sections and bounded launches are profiled.",
"Counter availability depends on GPU, driver, and system permissions.",
"Roofline evidence is exposed only when present in the official report.",
),
preserve_artifact_on_nonzero=True,
),
BuiltinAdapter(
name="triton.compiler",
dependency_kind="internal",
Expand Down Expand Up @@ -353,7 +412,7 @@ def builtin_adapter(name: str) -> BuiltinAdapter | None:
return BUILTIN_ADAPTERS.get(name)


def build_capture_invocation(
def build_capture_invocation( # noqa: C901 - provider routing is intentionally explicit
adapter_name: str,
workload_argv: tuple[str, ...],
output_root: Path,
Expand Down Expand Up @@ -451,6 +510,22 @@ def build_capture_invocation(
executable=executable,
options=options,
)
elif adapter_name == "rocprofv3":
return _rocprofv3_capture_invocation(
adapter,
workload_argv,
output_root,
executable=executable,
options=options,
)
elif adapter_name == "nsight.compute":
return _nsight_compute_capture_invocation(
adapter,
workload_argv,
output,
executable=executable,
options=options,
)
elif adapter_name == "triton.compiler":
return _triton_compiler_capture_invocation(
adapter,
Expand Down Expand Up @@ -767,6 +842,84 @@ def _nvbench_capture_invocation(
)


def _rocprofv3_capture_invocation(
adapter: BuiltinAdapter,
workload_argv: tuple[str, ...],
output_root: Path,
*,
executable: str | None,
options: dict[str, object] | None,
) -> CaptureInvocation:
selected = rocprofv3_options(options)
argv_parts: list[str] = [
_require_executable(adapter.name, executable),
"--output-format",
"pftrace",
"-o",
"rocprofv3",
"-d",
str(output_root),
]
for enabled, flag in (
(selected.hip_trace, "--hip-trace"),
(selected.kernel_trace, "--kernel-trace"),
(selected.memory_copy_trace, "--memory-copy-trace"),
(selected.memory_allocation_trace, "--memory-allocation-trace"),
(selected.scratch_memory_trace, "--scratch-memory-trace"),
(selected.marker_trace, "--marker-trace"),
):
if enabled:
argv_parts.append(flag)
argv = (*argv_parts, "--", *workload_argv)
return CaptureInvocation(
argv=argv,
artifact_kinds=adapter.artifact_kinds,
expected_overhead=adapter.expected_overhead or "",
limitations=adapter.capture_limitations,
environment={},
)


def _nsight_compute_capture_invocation(
adapter: BuiltinAdapter,
workload_argv: tuple[str, ...],
output: str,
*,
executable: str | None,
options: dict[str, object] | None,
) -> CaptureInvocation:
selected = nsight_compute_options(options)
argv_parts: list[str] = [
_require_executable(adapter.name, executable),
"--export",
output,
"--force-overwrite",
"--replay-mode",
selected.replay_mode,
"--launch-skip",
str(selected.launch_skip),
"--launch-count",
str(selected.launch_count),
]
if selected.set is not None:
argv_parts.extend(("--set", selected.set))
else:
for section in selected.sections or ():
argv_parts.extend(("--section", section))
if selected.kernel_name is not None:
argv_parts.extend(
("--kernel-name-base", "demangled", "--kernel-name", selected.kernel_name)
)
argv = (*argv_parts, *workload_argv)
return CaptureInvocation(
argv=argv,
artifact_kinds=adapter.artifact_kinds,
expected_overhead=adapter.expected_overhead or "",
limitations=adapter.capture_limitations,
environment={},
)


def _triton_compiler_capture_invocation(
adapter: BuiltinAdapter,
workload_argv: tuple[str, ...],
Expand Down
Loading
Loading