Files
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

385 lines
12 KiB
Python

# Copyright (c) Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
"""
Tests for the transpose example.
Equivalent to rocprof-sys-rocm-tests.cmake
Note: MPI multi-process execution is exercised if built with MPI support.
This module tests the transpose HIP example with various instrumentation modes:
- Baseline execution (no instrumentation)
- Sampling instrumentation
- Binary rewrite instrumentation
- Runtime instrumentation
- sys-run wrapper execution
It also validates outputs including:
- Perfetto traces
- ROCpd databases
- ROCProfiler counter data
"""
from __future__ import annotations
import pytest
from pathlib import Path
from conftest import RocprofsysTest
pytestmark = [
pytest.mark.transpose,
pytest.mark.gpu,
pytest.mark.rocm,
]
from rocprofsys import (
GPUInfo,
)
# =============================================================================
# Transpose fixtures
# =============================================================================
@pytest.fixture
def transpose_env() -> dict[str, str]:
"""Environment variables for transpose tests."""
return {
"ROCPROFSYS_ROCM_DOMAINS": "hip_runtime_api,kernel_dispatch,memory_copy,memory_allocation,hsa_api",
"ROCPROFSYS_AMD_SMI_METRICS": "busy,temp,power,mem_usage,gfx_clock,mem_clock",
}
@pytest.fixture
def rocprofiler_env(transpose_env: dict[str, str], gpu_info: GPUInfo) -> dict[str, str]:
"""Environment with ROCm events configured."""
env = transpose_env.copy()
env["ROCPROFSYS_ROCM_EVENTS"] = gpu_info.rocm_events_for_test
return env
@pytest.fixture
def gpu_perf_counter_env(
transpose_env: dict[str, str], gpu_info: GPUInfo
) -> dict[str, str]:
"""Environment with GPU perf counters configured."""
env = transpose_env.copy()
env["ROCPROFSYS_GPU_PERF_COUNTERS"] = gpu_info.gpu_perf_counters_for_test
return env
@pytest.fixture
def transpose_rules(validation_rules_dir: Path) -> list[Path]:
"""Get validation rules files for transpose tests."""
rules_dir = validation_rules_dir / "transpose"
return [
validation_rules_dir / "default-rules.json",
rules_dir / "validation-rules.json",
rules_dir / "amd-smi-rules.json",
rules_dir / "cpu-metrics-rules.json",
rules_dir / "timer-sampling-rules.json",
rules_dir / "sdk-metrics-rules.json",
]
@pytest.fixture
def rocprofiler_rules(validation_rules_dir: Path) -> list[Path]:
"""Get validation rules for GPU hardware counter RocPD output."""
rules_dir = validation_rules_dir / "transpose"
return [
validation_rules_dir / "default-rules.json",
rules_dir / "hw-counter-rules.json",
]
# ============================================================================
# Test Class: Basic Transpose Tests
# ============================================================================
@pytest.mark.mpi_optional("transpose")
class TestTranspose(RocprofsysTest):
BINARY_REWRITE_ARGS = [
"-e",
"-v",
"2",
"--print-instructions",
"-E",
"uniform_int_distribution",
]
RUNTIME_INSTRUMENT_ARGS = [
"-e",
"-v",
"1",
"--label",
"file",
"line",
"return",
"args",
"-E",
"uniform_int_distribution",
]
TWO_KERNELS_RUN_ARGS = ["1", "2", "2"]
LOOPS_BINARY_REWRITE_ARGS = [
"-e",
"-v",
"2",
"--label",
"return",
"args",
"-l",
"-i",
"8",
"-E",
"uniform_int_distribution",
]
LOOPS_RUN_ARGS = ["2", "100", "50"]
SAMPLING_RUN_ARGS = ["4", "500", "100"]
SAMPLING_ENV = {
"ROCPROFSYS_SAMPLING_REALTIME": "ON",
"ROCPROFSYS_SAMPLING_REALTIME_FREQ": "300",
"ROCPROFSYS_SAMPLING_CPUTIME": "OFF",
}
@pytest.mark.parametrize(
"mode",
[
"baseline",
"binary_rewrite",
"runtime_instrument",
"sys_run",
],
)
def test(self, mode, transpose_env):
result = self.run_test(
mode,
"transpose",
env=transpose_env,
binary_rewrite_args=self.BINARY_REWRITE_ARGS,
runtime_instrument_args=self.RUNTIME_INSTRUMENT_ARGS,
check_target_arch=True,
launcher="mpi",
num_procs=2,
)
self.assert_regex(result)
if mode != "baseline":
self.assert_perfetto(result)
@pytest.mark.timeout(120)
@pytest.mark.rocpd("transpose_env")
def test_sampling(self, transpose_env, transpose_rules):
env = transpose_env.copy()
env.update(self.SAMPLING_ENV)
result = self.run_test(
"sampling",
target="transpose",
env=env,
run_args=self.SAMPLING_RUN_ARGS,
check_target_arch=True,
launcher="mpi",
num_procs=2,
)
self.assert_regex(result)
self.assert_perfetto(
result,
subtest_name="Perfetto HIP API Call Validation",
categories=["hip_runtime_api"],
)
self.assert_rocpd(result, rules_files=transpose_rules)
@pytest.mark.parametrize(
"mode",
[
pytest.param("sampling", marks=pytest.mark.timeout(120)),
pytest.param("sys_run"),
],
)
def test_two_kernels(self, mode, transpose_env):
result = self.run_test(
mode,
"transpose",
env=transpose_env,
run_args=self.TWO_KERNELS_RUN_ARGS,
check_target_arch=True,
)
self.assert_regex(result)
@pytest.mark.locks
@pytest.mark.timeout(60)
def test_mutex_locks(self, transpose_env):
"""
Regression test for a self-deadlock: pthread_mutex_gotcha used to
intercept the trace cache's own internal lock (buffer_storage's
m_mutex), recursively re-entering it on the same thread while
recording the trace event for the lock acquisition itself. This
hung rocprof-sys-run indefinitely with -I mutex-locks enabled.
"""
result = self.run_test(
"sys_run",
"transpose",
env=transpose_env,
sys_run_args=["-I", "mutex-locks"],
run_args=["2", "50", "10"],
check_target_arch=True,
)
self.assert_regex(result)
@pytest.mark.timeout(120)
@pytest.mark.loops
@pytest.mark.parametrize("mode", ["sampling", "binary_rewrite"])
def test_loops(self, mode, transpose_env):
result = self.run_test(
mode,
"transpose",
env=transpose_env,
binary_rewrite_args=self.LOOPS_BINARY_REWRITE_ARGS,
run_args=self.LOOPS_RUN_ARGS,
check_target_arch=True,
)
self.assert_regex(
result,
mode,
binary_rewrite_fail_regex=["0 instrumented loops in procedure transpose"],
)
@pytest.mark.timeout(120)
@pytest.mark.parametrize("mode", ["sampling", "sys_run"])
@pytest.mark.parametrize(
"iterations,tile_dim,block_rows",
[
(1, 16, 16),
(2, 32, 32),
(5, 64, 64),
],
)
def test_parametrized(self, mode, iterations, tile_dim, block_rows, transpose_env):
result = self.run_test(
mode,
"transpose",
env=transpose_env,
run_args=[str(iterations), str(tile_dim), str(block_rows)],
fail_message=f"Config ({iterations}, {tile_dim}, {block_rows}) failed",
check_target_arch=True,
)
self.assert_regex(result)
@pytest.mark.rocm_min_version("7.0")
@pytest.mark.hip_stream
@pytest.mark.timeout(120)
@pytest.mark.parametrize("mode", ["sampling", "sys_run"])
@pytest.mark.parametrize(
"type",
[
pytest.param("group-by-queue", marks=pytest.mark.group_by_queue),
pytest.param("group-by-stream", marks=pytest.mark.group_by_stream),
],
)
def test_hip_stream(self, mode, type):
if type == "group-by-queue":
env = {"ROCPROFSYS_ROCM_GROUP_BY_QUEUE": "YES"}
else:
env = {"ROCPROFSYS_ROCM_GROUP_BY_QUEUE": "NO"}
result = self.run_test(
mode,
"transpose",
env=env,
check_target_arch=True,
launcher="mpi",
num_procs=2,
)
self.assert_regex(result)
# ============================================================================
# Test Class: ROCProfiler Counter Collection
# ============================================================================
@pytest.mark.mpi_optional("transpose")
@pytest.mark.rocprofiler
@pytest.mark.parametrize("mode", ["sampling", "binary_rewrite"])
@pytest.mark.class_name("transpose-rocprofiler")
class TestTransposeROCProfiler(RocprofsysTest):
BINARY_REWRITE_ARGS = ["-e", "-v", "2", "-E", "uniform_int_distribution"]
@pytest.mark.timeout(120)
@pytest.mark.rocpd("rocprofiler_env")
def test(self, mode, rocprofiler_env, gpu_info, rocprofiler_rules):
result = self.run_test(
mode,
"transpose",
env=rocprofiler_env,
check_target_arch=True,
launcher="mpi",
num_procs=2,
binary_rewrite_args=self.BINARY_REWRITE_ARGS,
)
self.assert_regex(result)
# Counter file device ID depends on GPU topology, search across IDs 0-9
counter_files = []
for pattern in gpu_info.expected_counter_files:
matches = list(result.output_dir.glob(pattern))
counter_files.extend(matches if matches else [result.output_dir / pattern])
self.assert_file_exists(
counter_files,
description="Counter file",
subtest_name="Counter file check",
)
if mode == "sampling":
self.assert_perfetto(
result,
subtest_name="Perfetto counter validation",
counter_names=gpu_info.counter_names,
check_counter_pairing=True,
)
self.assert_rocpd(
result,
subtest_name="RocPD HW counter validation",
rules_files=rocprofiler_rules,
)
# ============================================================================
# Test Class: GPU Performance Counter Collection (Device Counting Service)
# ============================================================================
@pytest.mark.mpi_optional("transpose")
@pytest.mark.rocprofiler
@pytest.mark.class_name("transpose-gpu-perf-counters")
@pytest.mark.timeout(120)
class TestTransposeGPUPerfCounters(RocprofsysTest):
@pytest.mark.rocpd("gpu_perf_counter_env")
def test(
self,
gpu_perf_counter_env,
gpu_info,
validation_rules_dir,
):
unsupported = gpu_info.unsupported_perf_counter_archs
if unsupported:
pytest.skip(
"transpose GPU perf counter test skipped on "
f"{', '.join(sorted(unsupported))}"
)
result = self.run_test(
"sampling",
"transpose",
env=gpu_perf_counter_env,
check_target_arch=True,
launcher="mpi",
num_procs=2,
)
self.assert_regex(result)
self.assert_perfetto(
result,
subtest_name="Perfetto GPU perf counter validation",
counter_names=gpu_info.counter_names,
)
rules_dir = validation_rules_dir / "transpose"
self.assert_rocpd(
result,
subtest_name="ROCpd GPU perf counter validation",
rules_files=[rules_dir / "gpu-perf-counter-rules.json"],
)