Files
TheRock/rocm-systems/projects/rocprofiler-systems/tests/pytest/test_hpc.py
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

299 lines
9.7 KiB
Python

# Copyright (c) Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
"""
HPC Example Tests.
"""
from __future__ import annotations
import pytest
from conftest import RocprofsysTest
from pathlib import Path
pytestmark = [pytest.mark.hpc]
# =============================================================================
# HPC Example Fixtures
# =============================================================================
@pytest.fixture
def hpc_openmp_environment() -> dict[str, str]:
"""Environment variables for HPC OpenMP tests."""
return {
"ROCPROFSYS_TRACE": "ON",
"ROCPROFSYS_PROFILE": "ON",
"ROCPROFSYS_TIME_OUTPUT": "OFF",
"ROCPROFSYS_USE_OMPT": "ON",
"ROCPROFSYS_TIMEMORY_COMPONENTS": "wall_clock,trip_count,peak_rss",
"OMP_PROC_BIND": "spread",
"OMP_PLACES": "threads",
"OMP_NUM_THREADS": "2",
"ROCPROFSYS_COUT_OUTPUT": "ON",
}
@pytest.fixture
def hpc_hip_environment() -> dict[str, str]:
"""Environment variables for HPC HIP tests."""
return {
"ROCPROFSYS_TRACE": "ON",
"ROCPROFSYS_PROFILE": "ON",
"ROCPROFSYS_TIME_OUTPUT": "OFF",
"ROCPROFSYS_TIMEMORY_COMPONENTS": "wall_clock,trip_count,peak_rss",
"ROCPROFSYS_COUT_OUTPUT": "ON",
}
@pytest.fixture
def kfd_rules(validation_rules_dir) -> list[Path]:
"""Get validation rules for KFD event tests."""
rules_dir = validation_rules_dir / "kfd"
return [
rules_dir / "kfd-rules.json",
]
@pytest.fixture
def matrix_exponential_rules(validation_rules_dir) -> list[Path]:
"""Get validation rules for matrix exponential tests."""
rules_dir = validation_rules_dir / "hpc" / "matrix-exponential"
return [
rules_dir / "sdk-metrics-rules.json",
]
@pytest.fixture
def split_copy_compute_hw_queues_rules(validation_rules_dir) -> list[Path]:
"""Get validation rules for split copy compute hw queues tests."""
rules_dir = validation_rules_dir / "hpc" / "split-copy-compute"
return [
rules_dir / "sdk-metrics-rules.json",
]
# =============================================================================
# HPC Tests
# =============================================================================
@pytest.mark.gpu
class TestJacobi(RocprofsysTest):
openmp_non_usm_run_args = ["-m", "512"]
# With OMPX_APU_MAPS=1, it takes longer, so reduce domain size
openmp_usm_run_args = ["-m", "64"]
hip_run_args = ["-g", "2", "1"]
@pytest.mark.slow
@pytest.mark.openmp
@pytest.mark.xnack
@pytest.mark.rocpd("hpc_openmp_environment")
@pytest.mark.parametrize("mode", ["sys_run"])
def test_usm(self, mode, hpc_openmp_environment, gpu_info, kfd_rules):
env = hpc_openmp_environment.copy()
env["ROCPROFSYS_ROCM_DOMAINS"] = "hip_api,kernel_dispatch,memory_copy"
env["HSA_XNACK"] = "1"
env["ROCPROFSYS_USE_AMD_SMI"] = "OFF"
if "apu" not in gpu_info.categories:
# Forces zero-copy behavior on non-APU GPUs
# Without this, it would be implicit zero-copy behavior
env["OMPX_APU_MAPS"] = "1"
result = self.run_test(
mode,
target="jacobi-fortran-usm",
env=env,
run_args=self.openmp_usm_run_args,
check_target_arch=True,
)
if "apu" in gpu_info.categories:
# We expect no omp_target_data_op_emi (CPU and GPU share the same memory)
self.assert_regex(
result,
subtest_name="USM Zero-Copy Validation (APU)",
fail_regex=["omp_target_data_op_emi"],
)
self.assert_perfetto(
result,
subtest_name="Perfetto USM Zero-Copy Validation (APU)",
fail_regex=["omp_target_data_op_emi"],
)
else:
# We expect to see only one omp_target_data_op_emi
# Corresponds to the Fortran array descriptor being transferred
# at the start of the program
self.assert_regex(
result,
subtest_name="USM Zero-Copy validation (Non-APU)",
pass_regex=[r"omp_target_data_op_emi\s*\|\s*1\s*\|\s*1\s*\|"],
)
self.assert_perfetto(
result,
subtest_name="Perfetto USM Zero-Copy validation (Non-APU)",
categories=["rocm_ompt_api"],
pass_regex=[r"omp_target_data_op_emi\s*\|\s*1\s*\|\s*1\s*\|"],
)
@pytest.mark.openmp
@pytest.mark.roctx
@pytest.mark.parametrize("mode", ["binary_rewrite", "sys_run"])
def test_roctx(self, mode, hpc_openmp_environment):
env = hpc_openmp_environment.copy()
env["ROCPROFSYS_ROCM_DOMAINS"] = "hip_api,kernel_dispatch,roctx,memory_copy"
env["ROCPROFSYS_COUT_OUTPUT"] = "OFF"
result = self.run_test(
mode,
target="jacobi-fortran-targetdata-markers",
env=env,
check_target_arch=True,
run_args=self.openmp_non_usm_run_args,
)
self.assert_regex(result)
# Going through dyninst (binary_rewrite or runtime_instrument) makes the host
# functions visible, changing the depth of the ROCTx markers as
# _QMjacobi_modPinit_jacobi is captured.
# sys_run does not go through dyninst, and hence needs a different depth check
expected_depths = (
[2, 2] if mode in ["binary_rewrite", "runtime_instrument"] else [1, 1]
)
self.assert_perfetto(
result,
subtest_name="Perfetto ROCtx marker validation",
categories=["rocm_marker_api"],
labels=["init", "run"],
counts=[1, 1],
depths=expected_depths,
)
@pytest.mark.hip
@pytest.mark.mpi
@pytest.mark.multi_gpu(2)
@pytest.mark.rocpd("hpc_hip_environment")
@pytest.mark.parametrize("mode", ["sys_run"])
def test_hip(self, mode, hpc_hip_environment):
env = hpc_hip_environment.copy()
env["ROCPROFSYS_PERFETTO_COMBINE_TRACES"] = "ON"
result = self.run_test(
mode,
target="jacobi-hip",
env=env,
run_args=self.hip_run_args,
launcher="mpi",
num_procs=2,
)
self.assert_regex(result)
# Taken from the program's defines.hpp
JACOBI_MAX_LOOPS = 1000
# With -g 2 1, 2 MPI ranks exist. The merged perfetto trace has 2x the per-rank count
self.assert_perfetto(
result,
subtest_name="Laplacian Kernel Count Validation",
perfetto_file="merged.proto",
categories=["rocm_hip_stream"],
print_output=True,
pass_regex=[rf"LocalLaplacianKernel.*\|\s+{JACOBI_MAX_LOOPS * 2}\s+\|"],
)
# hipHostFree is one of the last calls — tracked via rocprofiler-sdk in Perfetto
self.assert_perfetto(
result,
subtest_name="hipHostFree Validation",
perfetto_file="merged.proto",
categories=["rocm_hip_api"],
pass_regex=[r"hipHostFree\s*\|\s*[1-9]"],
)
@pytest.mark.gpu
@pytest.mark.hip
@pytest.mark.openmp
@pytest.mark.roctx
@pytest.mark.class_name("matrix-exponential")
class TestMatrixExponential(RocprofsysTest):
rocblas_gemm_kernel_prefix = ["Cijk_Ailk_Bljk"]
@pytest.mark.rocpd("hpc_hip_environment")
@pytest.mark.parametrize(
"mode",
[
"binary_rewrite",
"sys_run",
],
)
def test(self, mode, hpc_hip_environment, matrix_exponential_rules):
env = hpc_hip_environment.copy()
env["ROCPROFSYS_ROCM_DOMAINS"] = "hip_api,kernel_dispatch,roctx,memory_copy"
env["ROCPROFSYS_USE_OMPT"] = "ON"
result = self.run_test(
mode, target="matrix-exponential-streams-sync-hip", env=env
)
self.assert_regex(result)
# 171 total GEMM dispatches (sum of 1 to 18 from the Taylor series loop),
# but schedule(dynamic) distributes them non-deterministically across
# 4 OpenMP threads, so we verify presence rather than exact per-thread counts
self.assert_perfetto(
result,
subtest_name="Perfetto rocBLAS GEMM Kernel Validation",
print_output=True,
pass_regex=self.rocblas_gemm_kernel_prefix,
)
self.assert_rocpd(
result,
rules_files=matrix_exponential_rules,
)
@pytest.mark.rocm
@pytest.mark.gpu
@pytest.mark.hip
@pytest.mark.class_name("split-copy-compute-hw-queues")
class TestSplitCopyComputeHWQueues(RocprofsysTest):
nstreams = 4
@pytest.mark.rocpd("hpc_hip_environment")
@pytest.mark.parametrize("mode", ["sys_run"])
def test(self, mode, hpc_hip_environment, split_copy_compute_hw_queues_rules):
env = hpc_hip_environment.copy()
env["ROCPROFSYS_ROCM_DOMAINS"] = "hip_api,hsa_api,kernel_dispatch,memory_copy"
env["ROCPROFSYS_COUT_OUTPUT"] = "OFF"
env["ROCPROFSYS_ROCM_GROUP_BY_QUEUE"] = "ON"
result = self.run_test(
mode,
target="split-copy-compute-hw-queues",
env=env,
run_args=[str(self.nstreams)],
check_target_arch=True,
)
self.assert_regex(result)
# We expect to see "nstreams" amount of GPU Kernel Dispatch tracks, each with a cube kernel
self.assert_perfetto(
result,
subtest_name="Stream Count Validation",
categories=["rocm_kernel_dispatch"],
label_substrings=["cube"],
counts=[self.nstreams],
depths=[0],
)
self.assert_rocpd(
result,
rules_files=split_copy_compute_hw_queues_rules,
)