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
385 lines
12 KiB
Python
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"],
|
|
)
|