[roctx] Python bindings for rocprofiler-sdk-roctx (#402)
* [roctx] Python bindings for rocprofiler-sdk-roctx * Update CHANGELOG --------- Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
afb27f3f1a
Коммит
14c2dc55ff
@@ -0,0 +1,56 @@
|
||||
#
|
||||
# rocprofv3 python bindings for roctx test(s)
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
|
||||
|
||||
project(
|
||||
rocprofiler-tests-python-bindings
|
||||
LANGUAGES CXX
|
||||
VERSION 0.0.0)
|
||||
|
||||
find_package(rocprofiler-sdk REQUIRED)
|
||||
|
||||
if(NOT Python3_EXECUTABLE)
|
||||
find_package(Python3 3.6 REQUIRED COMPONENTS Interpreter)
|
||||
endif()
|
||||
|
||||
string(REPLACE "LD_PRELOAD=" "ROCPROF_PRELOAD=" PRELOAD_ENV
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}")
|
||||
|
||||
set(tracing-env
|
||||
"${PRELOAD_ENV}"
|
||||
"PYTHONPATH=${rocprofiler-sdk_LIB_DIR}/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages"
|
||||
)
|
||||
|
||||
rocprofiler_configure_pytest_files(CONFIG pytest.ini marker.py COPY validate.py
|
||||
conftest.py)
|
||||
|
||||
add_test(
|
||||
NAME test-roctx-python-bindings-execute
|
||||
COMMAND
|
||||
$<TARGET_FILE:rocprofiler-sdk::rocprofv3> --marker-trace --summary -u sec -d
|
||||
${CMAKE_CURRENT_BINARY_DIR}/marker-python-bindings -o out --output-format csv
|
||||
json pftrace --log-level config -- ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/marker.py)
|
||||
|
||||
set_tests_properties(
|
||||
test-roctx-python-bindings-execute
|
||||
PROPERTIES TIMEOUT 45 LABELS "integration-tests;python-bindings" ENVIRONMENT
|
||||
"${tracing-env}")
|
||||
|
||||
add_test(
|
||||
NAME test-roctx-python-bindings-validate
|
||||
COMMAND
|
||||
${Python3_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/validate.py --agent-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/marker-python-bindings/out_agent_info.csv
|
||||
--marker-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/marker-python-bindings/out_marker_api_trace.csv
|
||||
--json-input ${CMAKE_CURRENT_BINARY_DIR}/marker-python-bindings/out_results.json
|
||||
--pftrace-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/marker-python-bindings/out_results.pftrace)
|
||||
|
||||
set_tests_properties(
|
||||
test-roctx-python-bindings-validate
|
||||
PROPERTIES TIMEOUT 45 LABELS "integration-tests;python-bindings" DEPENDS
|
||||
"test-roctx-python-bindings-execute" FAIL_REGULAR_EXPRESSION
|
||||
"AssertionError")
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import csv
|
||||
import pytest
|
||||
import json
|
||||
|
||||
|
||||
from rocprofiler_sdk.pytest_utils.dotdict import dotdict
|
||||
from rocprofiler_sdk.pytest_utils import collapse_dict_list
|
||||
from rocprofiler_sdk.pytest_utils.perfetto_reader import PerfettoReader
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--agent-input",
|
||||
action="store",
|
||||
help="Path to agent info CSV file.",
|
||||
)
|
||||
parser.addoption(
|
||||
"--marker-input",
|
||||
action="store",
|
||||
help="Path to marker API tracing CSV file.",
|
||||
)
|
||||
parser.addoption(
|
||||
"--json-input",
|
||||
action="store",
|
||||
help="Path to JSON file.",
|
||||
)
|
||||
parser.addoption(
|
||||
"--pftrace-input",
|
||||
action="store",
|
||||
help="Path to Perfetto trace file.",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def agent_info_input_data(request):
|
||||
filename = request.config.getoption("--agent-input")
|
||||
data = []
|
||||
with open(filename, "r") as inp:
|
||||
reader = csv.DictReader(inp)
|
||||
for row in reader:
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def marker_input_data(request):
|
||||
filename = request.config.getoption("--marker-input")
|
||||
data = []
|
||||
with open(filename, "r") as inp:
|
||||
reader = csv.DictReader(inp)
|
||||
for row in reader:
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def json_data(request):
|
||||
filename = request.config.getoption("--json-input")
|
||||
with open(filename, "r") as inp:
|
||||
return dotdict(collapse_dict_list(json.load(inp)))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pftrace_data(request):
|
||||
filename = request.config.getoption("--pftrace-input")
|
||||
return PerfettoReader(filename).read()[0]
|
||||
@@ -0,0 +1,59 @@
|
||||
#!@Python3_EXECUTABLE@
|
||||
|
||||
import os
|
||||
import roctx
|
||||
import random
|
||||
|
||||
from roctx.context_decorators import RoctxRange
|
||||
|
||||
_prefix = ""
|
||||
|
||||
|
||||
@RoctxRange("fib")
|
||||
def fib(n, nmin):
|
||||
with RoctxRange(f"fib(n={n})" if n >= nmin else None):
|
||||
return n if n < 2 else (fib(n - 1, nmin) + fib(n - 2, nmin))
|
||||
|
||||
|
||||
@RoctxRange("sum")
|
||||
def _sum(arr):
|
||||
with RoctxRange(f"sum(nelem={len(arr)})"):
|
||||
return sum(arr)
|
||||
|
||||
|
||||
def inefficient(n):
|
||||
roctx.rangePush(f"inefficient({n})")
|
||||
a = 0
|
||||
for i in range(n):
|
||||
a += i
|
||||
for j in range(n):
|
||||
a += j
|
||||
_len = a * n * n
|
||||
_arr = [random.random() for _ in range(_len)]
|
||||
_ret = _sum(_arr)
|
||||
roctx.rangePop()
|
||||
return _ret
|
||||
|
||||
|
||||
def run(n):
|
||||
idx = roctx.rangeStart(f"run({n})")
|
||||
_ret_a = fib(n, max([n / 2, n - 10]))
|
||||
_ret_b = inefficient(n)
|
||||
roctx.rangeStop(idx)
|
||||
return (_ret_a, _ret_b)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-n", "--num-iterations", help="Number", type=int, default=3)
|
||||
parser.add_argument("-v", "--value", help="Starting value", type=int, default=20)
|
||||
args = parser.parse_args()
|
||||
|
||||
_prefix = os.path.basename(__file__)
|
||||
roctx.mark(f"iterations: {args.num_iterations}")
|
||||
for i in range(args.num_iterations):
|
||||
with RoctxRange("main loop"):
|
||||
ans_a, ans_b = run(args.value)
|
||||
print(f"[{_prefix}] [{i}] result of run({args.value}) = {ans_a}, {ans_b}\n")
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
[pytest]
|
||||
addopts = --durations=20 -rA -s -vv
|
||||
testpaths = validate.py
|
||||
pythonpath = @ROCPROFILER_SDK_TESTS_BINARY_DIR@/pytest-packages
|
||||
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
import re
|
||||
import os
|
||||
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def test_agent_info(agent_info_input_data):
|
||||
logical_node_id = max([int(itr["Logical_Node_Id"]) for itr in agent_info_input_data])
|
||||
|
||||
assert logical_node_id + 1 == len(agent_info_input_data)
|
||||
|
||||
for row in agent_info_input_data:
|
||||
agent_type = row["Agent_Type"]
|
||||
assert agent_type in ("CPU", "GPU")
|
||||
if agent_type == "CPU":
|
||||
assert int(row["Cpu_Cores_Count"]) > 0
|
||||
assert int(row["Simd_Count"]) == 0
|
||||
assert int(row["Max_Waves_Per_Simd"]) == 0
|
||||
else:
|
||||
assert int(row["Cpu_Cores_Count"]) == 0
|
||||
assert int(row["Simd_Count"]) > 0
|
||||
assert int(row["Max_Waves_Per_Simd"]) > 0
|
||||
|
||||
|
||||
def extract_number(pattern, string):
|
||||
match = re.match(pattern, string)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
else:
|
||||
raise ValueError(f"Pattern '{pattern}' not found in '{string}'.")
|
||||
|
||||
|
||||
def find_key_with_substring(data, substring):
|
||||
return next((k for k in data.keys() if substring in k), None)
|
||||
|
||||
|
||||
def check_tot_data(tot_data):
|
||||
iteration_msg = find_key_with_substring(tot_data, "iterations:")
|
||||
assert tot_data[iteration_msg] == 1
|
||||
|
||||
num_iterations = extract_number(r"iterations: (\d+)", iteration_msg)
|
||||
assert tot_data["main loop"] == num_iterations
|
||||
|
||||
if num_iterations > 0:
|
||||
run_msg = find_key_with_substring(tot_data, "run")
|
||||
if run_msg is not None:
|
||||
value = extract_number(r"run\((\d+)\)", run_msg)
|
||||
|
||||
assert tot_data[f"run({value})"] == num_iterations
|
||||
|
||||
assert "fib" in tot_data.keys()
|
||||
assert tot_data[f"fib(n={value})"] == num_iterations
|
||||
for n in range(value, int(max([value / 2, value - 10]))):
|
||||
assert f"fib(n={n})" in tot_data.keys()
|
||||
|
||||
assert tot_data[f"inefficient({value})"] == num_iterations
|
||||
assert tot_data[f"sum"] == num_iterations
|
||||
sum_msg = find_key_with_substring(tot_data, "sum(nelem=")
|
||||
assert tot_data[sum_msg] == num_iterations
|
||||
|
||||
|
||||
def test_marker_api_trace(marker_input_data):
|
||||
functions = []
|
||||
|
||||
for row in marker_input_data:
|
||||
assert row["Domain"] in [
|
||||
"MARKER_CORE_API",
|
||||
"MARKER_CONTROL_API",
|
||||
"MARKER_NAME_API",
|
||||
]
|
||||
assert int(row["Process_Id"]) > 0
|
||||
assert int(row["Thread_Id"]) == 0 or int(row["Thread_Id"]) >= int(
|
||||
row["Process_Id"]
|
||||
)
|
||||
assert int(row["End_Timestamp"]) >= int(row["Start_Timestamp"])
|
||||
|
||||
functions.append(row["Function"])
|
||||
|
||||
check_tot_data(Counter(functions))
|
||||
|
||||
|
||||
def test_marker_api_trace_json(json_data):
|
||||
data = json_data["rocprofiler-sdk-tool"]
|
||||
|
||||
def get_kind_name(kind_id):
|
||||
return data.strings.buffer_records[kind_id]["kind"]
|
||||
|
||||
valid_domain = ("MARKER_CORE_API", "MARKER_CONTROL_API", "MARKER_NAME_API")
|
||||
|
||||
marker_data = data.buffer_records.marker_api
|
||||
|
||||
for marker in marker_data:
|
||||
assert get_kind_name(marker["kind"]) in valid_domain
|
||||
assert marker["thread_id"] >= data["metadata"]["pid"]
|
||||
assert marker["end_timestamp"] >= marker["start_timestamp"]
|
||||
|
||||
tot_data = Counter([m["value"] for m in data.strings.marker_api])
|
||||
check_tot_data(tot_data)
|
||||
|
||||
|
||||
def test_perfetto_data(pftrace_data, json_data):
|
||||
import rocprofiler_sdk.tests.rocprofv3 as rocprofv3
|
||||
|
||||
rocprofv3.test_perfetto_data(
|
||||
pftrace_data, json_data, ("hip", "hsa", "marker", "kernel", "memory_copy")
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit_code = pytest.main(["-x", __file__] + sys.argv[1:])
|
||||
sys.exit(exit_code)
|
||||
Ссылка в новой задаче
Block a user