Files
TheRock/rocm-systems/experimental/python/perfxpert/docs/guides/python-api.md
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

19 KiB
Raw Blame History

Python API (perfxpert.api)

perfxpert.api is a 1:1 mirror of the 8 agent-hierarchy MCP tools. Every callable here IS the same function the MCP server wraps — the Python API and the MCP surface share a single implementation. Use this module to embed PerfXpert's analysis brain in your own tooling without running the MCP server.

Cross-links:

  • MCP server — the same 8 agent tools
    • 48 classifier / knowledge tools re-exposed over stdio JSON-RPC. This API is the same surface as the MCP tools.
  • Agent hierarchy — tier map, fence-slice pattern, and where each agent lives in source.
  • Agentic mode guide — air-gap vs LLM, PERFXPERT_LLM_FALLBACK_CHAIN, typed-error taxonomy.

Exported callables

The mirror drops the perfxpert_ prefix (which is only applied at MCP registration):

MCP tool name Python API
perfxpert_agent_root perfxpert.api.agent_root
perfxpert_agent_analysis perfxpert.api.agent_analysis
perfxpert_agent_recommendation perfxpert.api.agent_recommendation
perfxpert_agent_correctness perfxpert.api.agent_correctness
perfxpert_agent_compute_specialist perfxpert.api.agent_compute_specialist
perfxpert_agent_memory_specialist perfxpert.api.agent_memory_specialist
perfxpert_agent_latency_specialist perfxpert.api.agent_latency_specialist
perfxpert_agent_diff_specialist perfxpert.api.agent_diff_specialist
perfxpert_trace_diff_diff_runs perfxpert.api.trace_diff_diff_runs
perfxpert_rccl_analysis_analyze_collectives perfxpert.tools.rccl_analysis.analyze_collectives
perfxpert_interconnect_lookup_peaks perfxpert.tools.interconnect.lookup_peaks

Every agent callable honors PERFXPERT_AIRGAP=1 and the full provider / fallback-chain ladder (PERFXPERT_LLM_FALLBACK_CHAIN) because the agent tools defer to perfxpert.agents.runtime.build_session.

trace_diff_diff_runs is deterministic and credential-free — it reads two rocpd databases and produces a schema-0.3.1 diff dict (see schemas.md for the full contract). This is the same engine perfxpert diff, perfxpert ci, and perfxpert analyze --baseline use.

The two communication-analysis tools are deterministic (no LLM, no credentials) and map 1:1 onto their module functions:

# SKIP-SAMPLE — illustrative RCCL analysis call (requires a rocpd .db)
from perfxpert.tools import rccl_analysis, interconnect

peaks = interconnect.lookup_peaks("gfx942")       # MI300X XGMI spec
peaks["achievable_gbps"]                           # -> 340.0

result = rccl_analysis.analyze_collectives(
    "merged.db", gfx_id="gfx942"
)
result["summary"]["dominant_op"]                   # -> "AllReduce"
result["summary"]["overlap_pct"]                   # comm/compute overlap %

Quickstart

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
from perfxpert import api

out = api.agent_root(
    database_path="trace.db",
    user_query="why slow?",
    airgap=True,
)
print(out["primary_bottleneck"])
print(out["narrative"])
for rec in out["recommendations"]:
    print(rec["name"], rec["title"])

api.agent_root(...) is the same call perfxpert analyze makes under the hood — passing database_path=<path> + user_query=<str> gives you the equivalent of the CLI's end-to-end report in a Python dict.

Hotspot output shape

Each entry in out["hotspots"] is a dict with name, calls, total_duration, avg_duration, min_duration, max_duration, and percent_of_total. When the caller supplied a source_dir to the root agent, every hotspot also carries a source_locations: list[dict] field:

# SKIP-SAMPLE — illustrative output shape for hotspot source correlation
{
    "name": "ns::matmul<float>(float*, float*)",
    "calls": 128,
    "total_duration": 92_000_000,
    "percent_of_total": 48.5,
    "source_locations": [
        {"file": "src/ops.hip",  "line": 42, "kind": "definition"},
        {"file": "src/main.hip", "line": 88, "kind": "launch"},
    ],
}

kind is "definition" (the __global__ symbol declaration) or "launch" (a detected hipLaunchKernelGGL / triple-angle dispatch site). The list is empty when the Tier-0 scanner ran but found no matching basename, and the field is absent entirely when no source scan was performed. The source_locations field is the same shape as hotspots[i].source_locations in the JSON report (schema 0.3.1).

Input schemas (one example per agent)

Field names come from perfxpert/agents/schemas.py (Pydantic models; frozen to prevent mutation during handoff). Schemas cap at ≤10 input fields and ≤5 output fields per agent — CI-enforced in tests/test_agents/test_schema_field_caps.py.

agent_root — Layer-0 entry point

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
out = api.agent_root(
    user_query="Propose the first optimization for my hot kernel.",
    database_path="/tmp/trace.db",        # optional
    source_dir="./my_app",                 # optional — Tier 0 source scan
    provider="anthropic",                  # anthropic|openai|ollama|private|opencode
    airgap=False,                          # True ⇒ deterministic path, no LLM
    session_id=None,                       # optional — for session persistence
    progress_callback=print,               # optional — live phase updates
)

Output: narrative: str, recommendations: list[dict], primary_bottleneck: str, warnings: list[str], metadata: dict.

Live progress feedback

Every agent tool (agent_root, agent_analysis, agent_recommendation, agent_correctness, agent_compute_specialist, agent_memory_specialist, agent_latency_specialist, agent_diff_specialist) accepts an optional progress_callback: Callable[[str], None]. When set, the runtime fires short status strings as each agent phase enters / exits and when the fallback chain cascades across providers — useful for driving a spinner, streaming to a web UI, or piping into a log aggregator:

# SKIP-SAMPLE — illustrative Python API call
events = []
out = api.agent_root(
    database_path="/tmp/trace.db",
    provider="anthropic",
    progress_callback=events.append,
)
# events == ["entering root", ..., "exit root"]

progress_callback=None (the default) is zero-overhead — the runtime short-circuits all emission when no callback is registered. This is the same mechanism the perfxpert analyze CLI uses to draw its Rich spinner (see the Getting Started guide §6).

agent_analysis — Layer-1 bottleneck classifier

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
out = api.agent_analysis(
    input={
        "database_path": "/tmp/trace.db",
        "top_kernels": 10,
        "att_dir": None,                   # optional — auto-detected
    },
    airgap=True,
)

Output: primary_bottleneck, confidence, time_breakdown, hot_kernels, counter_data_available.

agent_recommendation — Layer-1 technique proposer

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
findings = api.agent_analysis(
    input={"database_path": "/tmp/trace.db"},
    airgap=True,
)

out = api.agent_recommendation(
    input={
        "findings": findings,
        "kernel_filter": None,
        "edit_history": [],
        "seen_recommendation_hashes": [],
    },
    airgap=True,
)

Output: recommendations (flat, ranked, deduplicated), specialist_used (compute/memory/latency/none), plateau_detected.

agent_correctness — Layer-1 gate-verdict narrator

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
# gate_verdict is a dict mirroring runtime.gate_cascade.GateVerdict.
out = api.agent_correctness(
    input={
        "gate_verdict": {
            "status": "reject",
            "failing_gate": "sol",
            "detail": "L2 hit rate regressed from 72% to 38%",
            "delta_pct": -47.2,
            "metrics": {},
            "rejected_patch_sha": "abc123",
            "per_kernel_deltas": {"gemm_k0": -12.4},
        },
        "kernel_name": "gemm_k0",
        "last_technique": "lds_blocking",
        "edit_history": [],
    },
    airgap=True,
)

Output: verdict (pass/reject/regressed), action (accept/revert/reject_and_log), narrative, alternative_technique, follow_up_task_id.

agent_compute_specialist — Layer-2 compute-bound expert

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
out = api.agent_compute_specialist(
    input={
        "gfx_id": "gfx942",
        "hot_kernels": [{"name": "gemm_k0", "duration_ns": 12000000}],
        "counter_data": {"vgpr_used": 128, "waves_per_eu": 4},
        "source_hints": {},
    },
    airgap=True,
)

Output: techniques (list of {name, rationale, expected_impact, effort, risk}), confidence, citations.

agent_memory_specialist — Layer-2 memory-bound expert

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
out = api.agent_memory_specialist(
    input={
        "gfx_id": "gfx942",
        "hot_kernels": [{"name": "stream_copy", "duration_ns": 8000000}],
        "memcpy_data": {"host_to_device_bytes": 1024 * 1024 * 512},
        "counter_data": {"l2_hit_rate": 0.41},
    },
    airgap=True,
)

Output: same shape as compute specialist — techniques, confidence, citations.

agent_latency_specialist — Layer-2 launch / dependency-chain expert

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
out = api.agent_latency_specialist(
    input={
        "gfx_id": "gfx942",
        "hot_kernels": [{"name": "launch_heavy_loop", "count": 10000}],
        "api_overhead_pct": 34.2,
        "avg_kernel_duration_us": 6.4,
    },
    airgap=True,
)

Output: same shape — techniques, confidence, citations.

agent_diff_specialist — Layer-2 run-to-run diff narrator

Compares a baseline rocprofiler-sdk database against a new run and returns a structured verdict (improved / regressed / neutral) plus ranked per-kernel deltas and a prose narrative. Wraps trace_diff.diff_runs internally — the arithmetic is deterministic; the LLM (when attached) only rewrites the narrative.

# SKIP-SAMPLE — illustrative Python API call (requires two real .db files)
out = api.agent_diff_specialist(
    baseline_db="baseline.db",
    new_db="new.db",
    top_kernels=20,
    user_intent="summarize the diff",
    airgap=True,
)
# {'wall_delta_pct': +12.3,
#  'regressions': [{'name': 'matmul', 'delta_pct': +34.2, ...}, ...],
#  'improvements': [...],
#  'verdict': 'regressed',
#  'narrative': 'The new run finished in +12.3% wall-time vs baseline. '
#               '4 kernels regressed, 1 improved. Top regression: matmul (+34.2%).',
#  'confidence': 0.7}
print(out["verdict"], out["narrative"])
for k in out["regressions"][:3]:
    print(f"  {k['name']}: {k['delta_pct']:+.1f}%")

Output keys: wall_delta_pct, regressions, improvements, verdict ∈ {improved, regressed, neutral}, narrative, confidence (0..1). Use this when the backend TUI LLM decides "compare two runs" rather than "re-analyze twice" — agent_diff_specialist is one tool call; running agent_root twice is two.

trace_diff_diff_runs — compare two rocpd databases

Deterministic, credential-free — no LLM required. Same engine as perfxpert diff, perfxpert ci, and the --baseline splice.

# SKIP-SAMPLE — illustrative Python API call (requires two real .db files)
from perfxpert import api

diff = api.trace_diff_diff_runs(
    baseline_db="baseline.db",
    new_db="new.db",
    top_kernels=20,
)
# schema_version == "0.3.1"
print(f"wall delta: {diff['wall_delta_pct']:+.2f}%")
for k in diff["primary_regressions"]:
    print(f"  REGRESSED {k['name']}: {k['delta_pct']:+.1f}%")

Output keys: schema_version, baseline_db, new_db, wall_delta_ns, wall_delta_pct, per_kernel, primary_regressions, primary_improvements, narrative. See schemas.md for the trace_diff contract.

roofline_plot_points — per-kernel live-roofline points

Builds the (arithmetic_intensity, achieved_flops_per_s) points used by the webview's Live Roofline chart. READ_ONLY against a rocpd database — no network, no writes, no LLM. The same payload is embedded under "roofline" in the agentic JSON output.

# SKIP-SAMPLE — illustrative Python API call (requires a Tier-2 .db with
# SQ_INSTS_VALU + FETCH_SIZE + WRITE_SIZE counters).
from perfxpert.tools import roofline

rf = roofline.plot_points("trace.db", top_k=10)
# {'schema_version': '0.3.x',
#  'arch': 'gfx942',
#  'arch_peaks': {'fp32': 1.634e14, 'fp16': 1.307e15, ...},
#  'dtype': 'bf16',
#  'dtype_confidence': 'from_kernel_name',
#  'kernels': [{'name': 'gemm_bf16_kernel',
#               'ai': 48.2,
#               'achieved_flops_per_s': 1.12e14,
#               'bottleneck_class': 'compute',
#               'fp_type': 'bf16',
#               'confidence': 'high',
#               'duration_pct': 94.3}],
#  'ridge_point': {'ai': 30.8, 'flops_per_s': 1.634e14}}
for k in rf["kernels"]:
    print(f"{k['name']}: AI={k['ai']:.1f}, "
          f"{k['achieved_flops_per_s']/1e12:.1f} TF/s, {k['bottleneck_class']}")

Formula — deterministic, no LLM involvement:

flops = SQ_INSTS_VALU × 64 + sum(SQ_INSTS_VALU_MFMA_MOPS_* × 512)
      # fallback when only the legacy aggregate counter is present:
      + SQ_INSTS_VALU_MFMA × mfma_flops_per_inst[dtype]
bytes = (FETCH_SIZE + WRITE_SIZE) × 1024       # TCC KiB → bytes
ai    = flops / bytes
rate  = flops / (duration_ns / 1e9)

Dtype detection is a regex over the demangled kernel name (_bf16, _fp16, _fp8, _int8; falls back to fp32 + dtype_confidence: "default"). Pass dtype_hint="bf16" to force a single dtype for every kernel — useful when your kernels don't follow the naming convention. See schemas.md for the full contract.

Error handling

All callables raise the standard provider taxonomy on LLM failure — AuthError, RateLimitError, QuotaExceededError, TransientError, FatalError, TimeoutError, and ProviderChainExhausted when a PERFXPERT_LLM_FALLBACK_CHAIN cascade runs out of candidates. Import from perfxpert.providers._exceptions; see agentic-mode.md §"Fallback chain" for the full table of which errors cascade vs surface immediately.

# SKIP-SAMPLE — illustrative Python API call (requires real trace.db / running session)
from perfxpert import api
from perfxpert.providers._exceptions import (
    RateLimitError,
    QuotaExceededError,
    ProviderChainExhausted,
)

try:
    out = api.agent_root(
        database_path="trace.db",
        user_query="why slow?",
        provider="anthropic",
    )
except QuotaExceededError:
    # Retry is futile — fall through to airgap.
    out = api.agent_root(
        database_path="trace.db",
        user_query="why slow?",
        airgap=True,
    )

Advanced-specialist classifier / knowledge tools

These are raw callables (not agent entry points) that specialists invoke internally; each is also exposed over the MCP wire.

Tool Python import Role
kernel_fusion.find_fusion_candidates from perfxpert.tools.kernel_fusion import find_fusion_candidates Adjacent-short-kernel fusion candidates — ranked list with (est_speedup_lo, est_speedup_hi) brackets.
gpu_runtime_monitor.parse_amd_smi_json from perfxpert.tools.gpu_runtime_monitor import parse_amd_smi_json Parse a captured amd-smi monitor --json log.
gpu_runtime_monitor.parse_rocm_smi_json from perfxpert.tools.gpu_runtime_monitor import parse_rocm_smi_json Parse a captured rocm-smi --json log.
gpu_runtime_monitor.analyze_thermal from perfxpert.tools.gpu_runtime_monitor import analyze_thermal Thermal envelope + throttle-event summary over a captured log.
unified_memory.analyze_paging from perfxpert.tools.unified_memory import analyze_paging HtoD/DtoH paging + MI300X cross-die (XCD) penalty analysis.
dependency_graph.reconstruct_dag from perfxpert.tools.dependency_graph import reconstruct_dag DAG reconstruction + critical_path + bubbles + total_bubble_ns + sync_event_count.
rccl_analysis.analyze_collectives from perfxpert.tools.rccl_analysis import analyze_collectives RCCL collective-ops analysis — per-op effective_bw_gbps, efficiency_pct, efficiency_label.
interconnect.lookup_peaks from perfxpert.tools.interconnect import lookup_peaks XGMI / Infinity-Fabric / PCIe peak bandwidth lookup (used by analyze_collectives for efficiency ratios).
roofline.plot_points from perfxpert.tools.roofline import plot_points Live Roofline — per-kernel (ai, achieved_flops_per_s, bottleneck_class, fp_type, confidence) from pmc_events.
pragma.lookup_pragmas from perfxpert.tools.pragma import lookup_pragmas Enumerate the 3 allowlisted LLVM loop-hint pragmas (+ 7 rejected entries kept for fence visibility).
pragma.explain_pragma from perfxpert.tools.pragma import explain_pragma Full catalog entry for a given pragma_id.
pragma.suggest_pragmas_for_kernel from perfxpert.tools.pragma import suggest_pragmas_for_kernel Amdahl-gated pragma candidates for a hot kernel.
predict_impact.predict_change_impact from perfxpert.tools.predict_impact import predict_change_impact Change-Impact Prediction: return {predicted_speedup_range, confidence, rationale, roofline_delta, assumptions, source_citation, prediction_id} for a baseline DB + kernel + change_type. Amdahl + tier-2 gates enforced internally. Stub today — durable prediction store lands in a follow-up; status field surfaces "unsupported" when hit.
predict_impact.list_supported_changes from perfxpert.tools.predict_impact import list_supported_changes Enumerate the change_type ids in knowledge/change_impact_models.yaml. Returns [{id, applies_to, required_metrics}].
predict_impact.explain_prediction from perfxpert.tools.predict_impact import explain_prediction Re-hydrate a prediction by its prediction_id. In-process only today; durable store lands in a follow-up.

All are READ_ONLY (safe for external callers) and deterministic (no LLM, no sudo, no live device access). The runtime-monitor parsers ingest a user-supplied JSON log — set PERFXPERT_GPU_MONITOR_LOG=<path> to let specialists pick it up automatically.

See also

  • MCP server — same 8 agents available over JSON-RPC; identical input/output schemas.
  • Agent hierarchy — tier diagram and source-tree locations.
  • perfxpert/agents/schemas.py — authoritative Pydantic schema definitions (frozen models, field caps).