Skip to content

Commit 3422a95

Browse files
author
anushe@amd.com
committed
tests: add hip graph bubbles coverage
1 parent 9113c23 commit 3422a95

File tree

8 files changed

+316
-12
lines changed

8 files changed

+316
-12
lines changed

projects/rocprofiler-sdk/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ add_subdirectory(rocdecode)
8888
add_subdirectory(rocjpeg)
8989
add_subdirectory(hip-host-tracing)
9090
add_subdirectory(code-object-multi-threaded)
91+
add_subdirectory(hip-graph-bubbles)
9192

9293
# rocpd validation tests
9394
add_subdirectory(rocpd)

projects/rocprofiler-sdk/tests/bin/hip-graph-bubbles/hip-graph-bubbles.cpp

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ THE SOFTWARE.
2424
#include <rocprofiler-sdk-roctx/roctx.h>
2525

2626
#include <chrono>
27+
#include <cstdlib>
2728
#include <iomanip>
2829
#include <iostream>
2930
#include <vector>
@@ -47,19 +48,79 @@ simpleKernel(int* data, int value)
4748
data[idx] = value + idx;
4849
}
4950

51+
namespace
52+
{
53+
struct config
54+
{
55+
int num_kernels = 2000;
56+
int num_iterations = 200;
57+
int array_size = 256;
58+
int progress_interval = 50;
59+
};
60+
61+
void
62+
print_usage(const char* argv0)
63+
{
64+
std::cerr << "Usage: " << argv0
65+
<< " [num_kernels] [num_iterations] [array_size] [progress_interval]"
66+
<< std::endl;
67+
}
68+
5069
int
51-
main()
70+
parse_positive_integer(const char* arg_name, const char* value)
5271
{
53-
const int NUM_KERNELS = 2000;
54-
const int NUM_ITERATIONS = 200;
55-
const int ARRAY_SIZE = 256;
72+
char* end = nullptr;
73+
auto ret = std::strtol(value, &end, 10);
74+
if(end == value || (end != nullptr && *end != '\0') || ret <= 0)
75+
{
76+
std::cerr << "Invalid " << arg_name << ": " << value << std::endl;
77+
exit(EXIT_FAILURE);
78+
}
79+
80+
return static_cast<int>(ret);
81+
}
5682

57-
std::cout << "Creating HIP graph with " << NUM_KERNELS << " kernel launches" << std::endl;
58-
std::cout << "Will execute graph " << NUM_ITERATIONS << " times" << std::endl;
83+
config
84+
parse_args(int argc, char** argv)
85+
{
86+
config cfg{};
87+
88+
if(argc > 5)
89+
{
90+
print_usage(argv[0]);
91+
exit(EXIT_FAILURE);
92+
}
93+
94+
if(argc > 1) cfg.num_kernels = parse_positive_integer("num_kernels", argv[1]);
95+
if(argc > 2) cfg.num_iterations = parse_positive_integer("num_iterations", argv[2]);
96+
if(argc > 3) cfg.array_size = parse_positive_integer("array_size", argv[3]);
97+
if(argc > 4)
98+
cfg.progress_interval = parse_positive_integer("progress_interval", argv[4]);
99+
100+
if(cfg.array_size < 256)
101+
{
102+
std::cerr << "array_size must be at least 256, got " << cfg.array_size << std::endl;
103+
exit(EXIT_FAILURE);
104+
}
105+
106+
return cfg;
107+
}
108+
} // namespace
109+
110+
int
111+
main(int argc, char** argv)
112+
{
113+
const auto cfg = parse_args(argc, argv);
114+
115+
std::cout << "Creating HIP graph with " << cfg.num_kernels << " kernel launches"
116+
<< std::endl;
117+
std::cout << "Will execute graph " << cfg.num_iterations << " times" << std::endl;
118+
std::cout << "Array size: " << cfg.array_size << std::endl;
119+
std::cout << "Progress interval: " << cfg.progress_interval << std::endl;
59120

60121
// Allocate device memory
61122
int* d_data;
62-
HIP_CHECK(hipMalloc(&d_data, ARRAY_SIZE * sizeof(int)));
123+
HIP_CHECK(hipMalloc(&d_data, cfg.array_size * sizeof(int)));
63124

64125
// Create graph
65126
hipGraph_t graph;
@@ -76,7 +137,7 @@ main()
76137
dim3 blockSize(256);
77138
dim3 gridSize(1);
78139

79-
for(int i = 0; i < NUM_KERNELS; i++)
140+
for(int i = 0; i < cfg.num_kernels; i++)
80141
{
81142
hipLaunchKernelGGL(simpleKernel, gridSize, blockSize, 0, stream, d_data, i);
82143
}
@@ -95,13 +156,13 @@ main()
95156
auto start = std::chrono::high_resolution_clock::now();
96157

97158
// Execute the graph multiple times
98-
for(int iter = 0; iter < NUM_ITERATIONS; iter++)
159+
for(int iter = 0; iter < cfg.num_iterations; iter++)
99160
{
100161
roctxRangePush("graph_launch");
101162
HIP_CHECK(hipGraphLaunch(graphExec, stream));
102163
roctxRangePop();
103164

104-
if((iter + 1) % 50 == 0)
165+
if((iter + 1) % cfg.progress_interval == 0 || (iter + 1) == cfg.num_iterations)
105166
{
106167
std::cout << "Completed " << (iter + 1) << " iterations" << std::endl;
107168
}
@@ -126,9 +187,10 @@ main()
126187
std::cout << std::fixed << std::setprecision(4);
127188
std::cout << "\n=== Timing Results ===" << std::endl;
128189
std::cout << "Total execution time: " << elapsed.count() << " seconds" << std::endl;
129-
std::cout << "Total kernel launches: " << (NUM_KERNELS * NUM_ITERATIONS) << std::endl;
130-
std::cout << "Average time per iteration: " << (elapsed.count() / NUM_ITERATIONS) << " seconds"
190+
std::cout << "Total kernel launches: " << (cfg.num_kernels * cfg.num_iterations)
131191
<< std::endl;
192+
std::cout << "Average time per iteration: " << (elapsed.count() / cfg.num_iterations)
193+
<< " seconds" << std::endl;
132194
std::cout << "======================" << std::endl;
133195

134196
// Cleanup
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#
2+
# Standalone HIP graph bubbles integration test
3+
#
4+
cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
5+
6+
project(
7+
rocprofiler-sdk-tests-hip-graph-bubbles
8+
LANGUAGES CXX
9+
VERSION 0.0.0)
10+
11+
set(HIP_GRAPH_BUBBLES_STANDALONE_ENVIRONMENT)
12+
if(DEFINED ENV{ROCM_PATH} AND EXISTS "$ENV{ROCM_PATH}/lib/rocm_sysdeps/lib")
13+
list(
14+
APPEND HIP_GRAPH_BUBBLES_STANDALONE_ENVIRONMENT
15+
"LD_LIBRARY_PATH=$ENV{ROCM_PATH}/lib/rocm_sysdeps/lib:$ENV{LD_LIBRARY_PATH}")
16+
endif()
17+
18+
function(add_hip_graph_bubbles_standalone_test SUFFIX NUM_KERNELS NUM_ITERATIONS TIMEOUT_SECS)
19+
math(EXPR EXPECTED_DISPATCH_COUNT "${NUM_KERNELS} * ${NUM_ITERATIONS}")
20+
21+
rocprofiler_add_integration_execute_test(
22+
hip-graph-bubbles-standalone-${SUFFIX}
23+
TARGET hip-graph-bubbles
24+
ARGS ${NUM_KERNELS} ${NUM_ITERATIONS} 256 25
25+
TIMEOUT ${TIMEOUT_SECS}
26+
LABELS "integration-tests;standalone"
27+
ENVIRONMENT ${HIP_GRAPH_BUBBLES_STANDALONE_ENVIRONMENT}
28+
PASS_REGULAR_EXPRESSION
29+
"Total kernel launches: ${EXPECTED_DISPATCH_COUNT};Test completed successfully")
30+
endfunction()
31+
32+
add_hip_graph_bubbles_standalone_test(k256-i20 256 20 30)
33+
add_hip_graph_bubbles_standalone_test(k2000-i200 2000 200 60)

projects/rocprofiler-sdk/tests/rocprofv3/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ enable_testing()
2424
include(CTest)
2525

2626
add_subdirectory(tracing)
27+
add_subdirectory(hip-graph-bubbles)
2728
add_subdirectory(tracing-plus-counter-collection)
2829
add_subdirectory(tracing-hip-in-libraries)
2930
add_subdirectory(counter-collection)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#
2+
# rocprofv3 HIP graph bubble regression tests
3+
#
4+
cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
5+
6+
project(
7+
rocprofiler-sdk-tests-rocprofv3-hip-graph-bubbles
8+
LANGUAGES CXX
9+
VERSION 0.0.0)
10+
11+
find_package(rocprofiler-sdk REQUIRED)
12+
13+
set(HIP_GRAPH_BUBBLES_ENVIRONMENT)
14+
if(DEFINED ENV{ROCM_PATH} AND EXISTS "$ENV{ROCM_PATH}/lib/rocm_sysdeps/lib")
15+
list(
16+
APPEND HIP_GRAPH_BUBBLES_ENVIRONMENT
17+
"LD_LIBRARY_PATH=$ENV{ROCM_PATH}/lib/rocm_sysdeps/lib:$ENV{LD_LIBRARY_PATH}")
18+
endif()
19+
20+
function(add_hip_graph_bubbles_kernel_trace_test SUFFIX NUM_KERNELS NUM_ITERATIONS TIMEOUT_SECS)
21+
set(TEST_NAME "rocprofv3-test-hip-graph-bubbles-${SUFFIX}")
22+
set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/hip-graph-bubbles-${SUFFIX}")
23+
math(EXPR EXPECTED_DISPATCH_COUNT "${NUM_KERNELS} * ${NUM_ITERATIONS}")
24+
25+
rocprofiler_add_integration_execute_test(
26+
${TEST_NAME}
27+
COMMAND
28+
$<TARGET_FILE:rocprofiler-sdk::rocprofv3> --kernel-trace -d ${OUTPUT_DIR} -o
29+
out --output-format csv -- $<TARGET_FILE:hip-graph-bubbles> ${NUM_KERNELS}
30+
${NUM_ITERATIONS} 256 25
31+
DEPENDS hip-graph-bubbles
32+
TIMEOUT ${TIMEOUT_SECS}
33+
LABELS "integration-tests"
34+
ENVIRONMENT ${HIP_GRAPH_BUBBLES_ENVIRONMENT}
35+
FIXTURES_SETUP ${TEST_NAME}
36+
FAIL_REGULAR_EXPRESSION "KERNEL_DISPATCH|CODE_OBJECT")
37+
38+
rocprofiler_add_integration_validate_test(
39+
${TEST_NAME}
40+
TEST_PATHS validate.py
41+
COPY conftest.py
42+
CONFIG pytest.ini
43+
ARGS --kernel-input
44+
${CMAKE_CURRENT_BINARY_DIR}/hip-graph-bubbles-${SUFFIX}/out_kernel_trace.csv
45+
--expected-dispatch-count
46+
${EXPECTED_DISPATCH_COUNT}
47+
--expected-kernels
48+
${NUM_KERNELS}
49+
--expected-iterations
50+
${NUM_ITERATIONS}
51+
TIMEOUT ${TIMEOUT_SECS}
52+
LABELS "integration-tests"
53+
FIXTURES_REQUIRED ${TEST_NAME})
54+
endfunction()
55+
56+
add_hip_graph_bubbles_kernel_trace_test(k256-i20 256 20 60)
57+
add_hip_graph_bubbles_kernel_trace_test(k256-i200 256 200 120)
58+
add_hip_graph_bubbles_kernel_trace_test(k2000-i200 2000 200 180)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python3
2+
3+
# MIT License
4+
#
5+
# Copyright (c) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in
15+
# all copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
# THE SOFTWARE.
24+
25+
import csv
26+
import pytest
27+
28+
29+
def pytest_addoption(parser):
30+
parser.addoption(
31+
"--kernel-input",
32+
action="store",
33+
help="Path to kernel tracing CSV file.",
34+
)
35+
parser.addoption(
36+
"--expected-dispatch-count",
37+
action="store",
38+
type=int,
39+
help="Expected number of kernel dispatch records.",
40+
)
41+
parser.addoption(
42+
"--expected-kernels",
43+
action="store",
44+
type=int,
45+
help="Expected kernels per graph launch.",
46+
)
47+
parser.addoption(
48+
"--expected-iterations",
49+
action="store",
50+
type=int,
51+
help="Expected number of graph launches.",
52+
)
53+
54+
55+
@pytest.fixture
56+
def kernel_input_data(request):
57+
filename = request.config.getoption("--kernel-input")
58+
data = []
59+
with open(filename, "r") as inp:
60+
reader = csv.DictReader(inp)
61+
for row in reader:
62+
data.append(row)
63+
64+
return data
65+
66+
67+
@pytest.fixture
68+
def expected_dispatch_count(request):
69+
return request.config.getoption("--expected-dispatch-count")
70+
71+
72+
@pytest.fixture
73+
def expected_kernels(request):
74+
return request.config.getoption("--expected-kernels")
75+
76+
77+
@pytest.fixture
78+
def expected_iterations(request):
79+
return request.config.getoption("--expected-iterations")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[pytest]
2+
addopts = --durations=20 -rA -s
3+
testpaths = validate.py
4+
pythonpath = @ROCPROFILER_SDK_TESTS_BINARY_DIR@/pytest-packages
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/env python3
2+
3+
# MIT License
4+
#
5+
# Copyright (c) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in
15+
# all copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
# THE SOFTWARE.
24+
25+
import sys
26+
import pytest
27+
28+
29+
def test_kernel_trace_row_count(
30+
kernel_input_data,
31+
expected_dispatch_count,
32+
expected_kernels,
33+
expected_iterations,
34+
):
35+
assert expected_dispatch_count == expected_kernels * expected_iterations
36+
assert len(kernel_input_data) == expected_dispatch_count
37+
38+
39+
def test_kernel_trace_dispatch_ids(kernel_input_data, expected_dispatch_count):
40+
dispatch_ids = [int(row["Dispatch_Id"]) for row in kernel_input_data]
41+
42+
assert len(dispatch_ids) == expected_dispatch_count
43+
assert len(set(dispatch_ids)) == expected_dispatch_count
44+
45+
46+
def test_kernel_trace_fields(kernel_input_data, expected_dispatch_count):
47+
assert len(kernel_input_data) == expected_dispatch_count
48+
49+
for row in kernel_input_data:
50+
assert row["Kind"] == "KERNEL_DISPATCH"
51+
assert int(row["Agent_Id"].split(" ")[-1]) >= 0
52+
assert int(row["Queue_Id"]) > 0
53+
assert int(row["Kernel_Id"]) > 0
54+
assert int(row["Correlation_Id"]) > 0
55+
assert int(row["Workgroup_Size_X"]) == 256
56+
assert int(row["Workgroup_Size_Y"]) == 1
57+
assert int(row["Workgroup_Size_Z"]) == 1
58+
assert int(row["Grid_Size_X"]) == 256
59+
assert int(row["Grid_Size_Y"]) == 1
60+
assert int(row["Grid_Size_Z"]) == 1
61+
assert int(row["End_Timestamp"]) >= int(row["Start_Timestamp"])
62+
63+
64+
if __name__ == "__main__":
65+
exit_code = pytest.main(["-x", __file__] + sys.argv[1:])
66+
sys.exit(exit_code)

0 commit comments

Comments
 (0)