Files
TheRock/rocm-systems/projects/rocprofiler-compute/tests/test_analysis_orm.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

245 lines
7.8 KiB
Python

# Copyright (c) Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
"""Unit tests for analysis_orm.py static methods."""
import numpy as np
import pytest
from sqlalchemy import text
from sqlalchemy.exc import IntegrityError
from utils.analysis_orm import (
CodeObjectStore,
Database,
Dispatch,
InstructionLine,
Kernel,
PCSampleStallReason,
PCSampleStallReasonLookup,
PCSampleState,
Workload,
)
@pytest.mark.parametrize(
("value", "expected"),
[
({"k": float("nan")}, {"k": None}),
({"k": float("inf")}, {"k": None}),
({"k": float("-inf")}, {"k": None}),
({"k": np.float64("nan")}, {"k": None}),
(
{"i": 1, "f": 2.5, "s": "text", "n": None},
{"i": 1, "f": 2.5, "s": "text", "n": None},
),
({"a": [{"b": float("nan")}]}, {"a": [{"b": None}]}),
({"a": ({"b": float("inf")},)}, {"a": [{"b": None}]}),
],
ids=[
"nan",
"inf",
"neg_inf",
"numpy_nan",
"valid_passthrough",
"nested_list",
"nested_tuple",
],
)
def test_json_sanitize(value, expected):
assert Database._json_sanitize(value) == expected
def add_kernel_with_durations(
session, workload: Workload, name: str, durations: list[int]
) -> Kernel:
"""Add a kernel to *workload* with one dispatch per entry in *durations*."""
kernel = Kernel(kernel_name=name, workload=workload)
session.add(kernel)
for dispatch_id, duration in enumerate(durations):
session.add(
Dispatch(
dispatch_id=dispatch_id,
gpu_id=0,
start_timestamp=0,
end_timestamp=duration,
kernel=kernel,
)
)
return kernel
# =============================================================================
# kernel view: median duration algorithm
# =============================================================================
@pytest.mark.parametrize(
("durations", "expected_median"),
[
([30, 10, 20], 20.0), # odd: middle value
([40, 10, 30, 20], 25.0), # even: mean of two middle values
([42], 42.0), # single dispatch
],
ids=["odd", "even", "single"],
)
def test_kernel_view_median(db_session, durations, expected_median):
"""The kernel view computes median duration for odd/even/single counts."""
workload = Workload(name="w", sub_name="s")
db_session.add(workload)
add_kernel_with_durations(db_session, workload, "k", durations)
Database.create_views()
db_session.commit()
row = db_session.execute(
text("SELECT duration_ns_median FROM compute_kernel_view")
).fetchone()
assert row[0] == expected_median
def test_kernel_view_aggregates(db_session):
"""The kernel view reports count/sum/min/max/mean over dispatch durations."""
workload = Workload(name="w", sub_name="s")
db_session.add(workload)
add_kernel_with_durations(db_session, workload, "k", [10, 20, 30])
Database.create_views()
db_session.commit()
row = db_session.execute(
text(
"SELECT dispatch_count, duration_ns_sum, duration_ns_min, "
"duration_ns_max, duration_ns_mean FROM compute_kernel_view"
)
).fetchone()
assert row == (3, 60, 10, 30, 20.0)
# =============================================================================
# unique constraints
# =============================================================================
def test_duplicate_kernel_rejected(db_session):
"""A second kernel with the same (workload_id, kernel_name) is rejected."""
workload = Workload(name="w", sub_name="s")
db_session.add(workload)
db_session.add(Kernel(kernel_name="k", workload=workload))
db_session.add(Kernel(kernel_name="k", workload=workload))
with pytest.raises(IntegrityError):
db_session.commit()
def test_duplicate_dispatch_rejected(db_session):
"""A second dispatch with the same (kernel_uuid, dispatch_id) is rejected."""
workload = Workload(name="w", sub_name="s")
db_session.add(workload)
kernel = Kernel(kernel_name="k", workload=workload)
db_session.add(kernel)
db_session.add(Dispatch(dispatch_id=0, kernel=kernel))
db_session.add(Dispatch(dispatch_id=0, kernel=kernel))
with pytest.raises(IntegrityError):
db_session.commit()
def test_duplicate_stall_reason_lookup_rejected(db_session):
"""A second stall-reason lookup with the same text is rejected."""
db_session.add(PCSampleStallReasonLookup(text="WAITCNT"))
db_session.add(PCSampleStallReasonLookup(text="WAITCNT"))
with pytest.raises(IntegrityError):
db_session.commit()
# =============================================================================
# get_view_sql
# =============================================================================
def test_get_view_sql_returns_copy(db_session):
"""Mutating the returned dict does not poison the cached view SQL."""
view_sql = Database.get_view_sql()
view_sql.clear()
assert Database.get_view_sql() # cache still populated
# =============================================================================
# get_or_create_type
# =============================================================================
def test_get_or_create_type_dedups(db_session):
"""The same text returns one cached row; a new text creates another."""
first = Database.get_or_create_type(PCSampleStallReasonLookup, "WAITCNT")
again = Database.get_or_create_type(PCSampleStallReasonLookup, "WAITCNT")
other = Database.get_or_create_type(PCSampleStallReasonLookup, "BARRIER_WAIT")
db_session.commit()
assert first is again
assert other is not first
assert db_session.query(PCSampleStallReasonLookup).count() == 2
def test_get_or_create_type_dedups_across_calls(db_session):
"""Reusing a text after a commit (e.g. a second workload) creates no
duplicate row, respecting the unique constraint."""
Database.get_or_create_type(PCSampleStallReasonLookup, "WAITCNT")
db_session.commit()
Database.get_or_create_type(PCSampleStallReasonLookup, "WAITCNT")
db_session.commit()
assert db_session.query(PCSampleStallReasonLookup).count() == 1
# =============================================================================
# pc_sampling view
# =============================================================================
def test_pc_sampling_view_flattens_normalized_tables(db_session):
"""The pc_sampling view flattens the normalized tables and rebuilds
stall_reason as a JSON dict."""
workload = Workload(name="w", sub_name="s")
db_session.add(workload)
kernel = Kernel(kernel_name="vecCopy", workload=workload)
db_session.add(kernel)
code_object = CodeObjectStore(
pid=1, code_object_id=5, load_base=0x1000, workload=workload
)
db_session.add(code_object)
line = InstructionLine(
code_object_offset=0x10,
comment="/s/a.cpp:1",
instruction="v_mov",
code_object_store=code_object,
kernel=kernel,
)
db_session.add(line)
state = PCSampleState(
total_count=3, issue_count=1, stall_count=2, instruction_line=line
)
db_session.add(state)
reason_lookup = PCSampleStallReasonLookup(text="WAITCNT")
db_session.add(reason_lookup)
db_session.add(
PCSampleStallReason(
pc_sample_state=state, stall_reason_lookup=reason_lookup, count=2
)
)
Database.create_views()
db_session.commit()
row = db_session.execute(
text(
"SELECT kernel_name, offset, instruction, source, count, "
"count_issue, count_stall, stall_reason FROM compute_pc_sampling_view"
)
).fetchone()
assert row == (
"vecCopy",
0x10,
"v_mov",
"/s/a.cpp:1",
3,
1,
2,
'{"WAITCNT":2}',
)