[SDK][rocprofv3] MI300 Stochastic PC sampling (#92)
* MI300 Stochastic PC sampling SDK API implementation * ROCProfV3: Stochastic PC sampling Support (#94) * ROCProfV3: MI300 Stochastic PC sampling initial draft * ROCProfV3: Initial Stochastic PC sampling Tests (#95) ROCProfV3: Initial Stochastic PC sampling tests * Update rocprofiler_pc_sampling_record_stochastic_v0_t - update doxygen docs for members - replace rocprofiler_correlation_id_t with rocprofiler_async_correlation_id_t * Relax the check in JSON tests * drain PC sampling buffer during finalize_rocprofv3 * Increase timeout for "Test Install Build" step - 10 minutes -> 20 minutes - "Test Installed Packages" has 20 minutes so "Test Install Build" should also --------- Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling)
|
||||
|
||||
file(
|
||||
WRITE "${PACKAGE_OUTPUT_DIR}/__init__.py"
|
||||
"#
|
||||
from __future__ import absolute_import
|
||||
|
||||
from . import exec_mask_manipulation
|
||||
")
|
||||
|
||||
add_subdirectory(exec_mask_manipulation)
|
||||
add_subdirectory(stochastic)
|
||||
add_subdirectory(transpose_multiple_agents)
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling/exec_mask_manipulation
|
||||
)
|
||||
|
||||
set(PC_SAMPLING_PYTHON_SOURCES __init__.py csv.py json.py)
|
||||
|
||||
foreach(_FILE ${PC_SAMPLING_PYTHON_SOURCES})
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/${_FILE} ${PACKAGE_OUTPUT_DIR}/${_FILE}
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
@@ -0,0 +1,23 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
from __future__ import absolute_import
|
||||
@@ -0,0 +1,210 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def stochastic_assert(df, df_condition_selection, max_failing_samples=10):
|
||||
# TODO: When asserting certain conditions related to exec_masks for all samples,
|
||||
# we observe some failures.
|
||||
# This usually happens because some small number of samples (e.g., 1-10 out of 100k)
|
||||
# do not satisfy the condition. This is either a regression in the ROCr 2nd level trap
|
||||
# handler (as sometimes execution mask or correlation ID mismatches), or
|
||||
# just stochastic nature of the sampling (meaning our checks are too strict).
|
||||
# To relax checks, we introduce an assertion that will allow some small number
|
||||
# of samples to disobey the condition.
|
||||
# This is a temporary solution until we find the root cause of the issue.
|
||||
|
||||
# extract the failing samples
|
||||
failing_samples = df[~df_condition_selection]
|
||||
assert len(failing_samples) <= max_failing_samples, "Too many failing samples"
|
||||
|
||||
|
||||
# Keep this in case we decide to revert workgroup_id information
|
||||
def validate_workgoup_id_x_y_z(df, max_x, max_y, max_z):
|
||||
assert (df["Workgroup_Size_X"].astype(int) >= 0).all()
|
||||
assert (df["Workgroup_Size_X"].astype(int) <= max_x).all()
|
||||
|
||||
assert (df["Workgroup_Size_Y"].astype(int) >= 0).all()
|
||||
assert (df["Workgroup_Size_Y"].astype(int) <= max_y).all()
|
||||
|
||||
assert (df["Workgroup_Size_Z"].astype(int) >= 0).all()
|
||||
assert (df["Workgroup_Size_Z"].astype(int) <= max_z).all()
|
||||
|
||||
|
||||
# Keep this in case we decide to revert wave_id information
|
||||
def validate_wave_id(df, max_wave_id):
|
||||
assert (df["Wave_Id"].astype(int) <= max_wave_id).all()
|
||||
|
||||
|
||||
# Keep this in case we decide to revert wave_id information
|
||||
def validate_chiplet(df, max_chiplet):
|
||||
assert (df["Chiplet"].astype(int) <= max_chiplet).all()
|
||||
|
||||
|
||||
def validate_instruction_decoding(
|
||||
df,
|
||||
inst_str,
|
||||
exec_mask_uint64: np.uint64 = None,
|
||||
source_code_lines_range: (int, int) = None,
|
||||
all_source_lines_samples=False,
|
||||
):
|
||||
# Make a copy, so that we don't work (modify) a view.
|
||||
df_inst = df[df["Instruction"].apply(lambda inst: inst.startswith(inst_str))].copy()
|
||||
|
||||
assert not df_inst.empty
|
||||
# assert the exec mask if requested
|
||||
if exec_mask_uint64 is not None:
|
||||
stochastic_assert(
|
||||
df_inst, df_inst["Exec_Mask"].astype(np.uint64) == exec_mask_uint64
|
||||
)
|
||||
|
||||
# assert whether the samples source code lines belongs to the provided range
|
||||
if source_code_lines_range is not None:
|
||||
start_range, end_range = source_code_lines_range
|
||||
# The instruction comment is isually in the following format: /path/to/source/file.cpp:line_num
|
||||
df_inst["source_line_num"] = df_inst["Instruction_Comment"].apply(
|
||||
lambda source_line: int(source_line.split(":")[-1])
|
||||
)
|
||||
assert (df_inst["source_line_num"] >= start_range).all()
|
||||
assert (df_inst["source_line_num"] <= end_range).all()
|
||||
# if requested, check if all lines from the range are sampled
|
||||
if all_source_lines_samples:
|
||||
assert len(df_inst["source_line_num"].unique()) == (
|
||||
end_range - start_range + 1
|
||||
)
|
||||
|
||||
|
||||
def validate_instruction_comment(df):
|
||||
# Instruction comment must always be present, since the testing application
|
||||
# is built with debug symbols.
|
||||
assert (
|
||||
(df["Instruction_Comment"] != "") & (df["Instruction_Comment"] != "nullptr")
|
||||
).all()
|
||||
|
||||
|
||||
def validate_instruction_correlation_id_relation(df):
|
||||
# Samples with no decoded instructions originates from either
|
||||
# blit kernels or self modifying code. The correlation id for this
|
||||
# type of samples should alway be zero.
|
||||
# Thus, Correlation_Id is 0 `iff`` instruction is not decoded.
|
||||
|
||||
# The previous statement has two implications.
|
||||
# Implication 1: If the instruction is not decoded, then correlation id is 0.
|
||||
samples_no_instruction_df = df[
|
||||
(df["Instruction"] == "") | (df["Instruction"] == "nullptr")
|
||||
]
|
||||
assert (samples_no_instruction_df["Correlation_Id"] == 0).all()
|
||||
|
||||
# Implication 2: If the correlation id is 0, then the instruction is not decoded.
|
||||
samples_cid_zero_df = df[df["Correlation_Id"] == 0]
|
||||
assert (
|
||||
(samples_cid_zero_df["Instruction"] == "")
|
||||
| (samples_cid_zero_df["Instruction"] == "nullptr")
|
||||
).all()
|
||||
|
||||
assert len(samples_no_instruction_df) == len(samples_cid_zero_df)
|
||||
|
||||
# Since we're not enabling any kind of API tracing,
|
||||
# internal correlation id should match the dispatch id
|
||||
assert all(df["Correlation_Id"] == df["Dispatch_Id"])
|
||||
|
||||
|
||||
def validate_exec_mask_based_on_correlation_id(df):
|
||||
# The function assumes that each kernel launches 1024 blocks.
|
||||
# Each block contains number of threads that matches correlation ID of the kernel.
|
||||
# The exec mask of a sample should contain number of ones equal to
|
||||
# the correlation ID of the kernel during which execution the sample was generated.
|
||||
df["active_SIMD_threads"] = df["Exec_Mask"].apply(
|
||||
lambda exec_mask: bin(exec_mask).count("1")
|
||||
)
|
||||
stochastic_assert(df, df["active_SIMD_threads"] == df["Correlation_Id"])
|
||||
|
||||
# TODO: Comment out the following code if it causes spurious fails.
|
||||
# The more conservative constraint based on the experience follows.
|
||||
# The exec mask of sampled instructions of the kernels respect the following pattern:
|
||||
# cid -> exec
|
||||
# 1 -> 0b1
|
||||
# 2 -> 0b11
|
||||
# 3 -> 0b111
|
||||
# ...
|
||||
# 64 -> 0xffffffffffffffff
|
||||
|
||||
df["Exec_Mask2"] = (
|
||||
df["Correlation_Id"].astype(int).apply(lambda x: int("0b" + (x * "1"), 2))
|
||||
)
|
||||
|
||||
# TODO: exec should be in hex and that will ease the comparison
|
||||
stochastic_assert(
|
||||
df, df["Exec_Mask"].astype(np.uint64) == df["Exec_Mask2"].astype(np.uint64)
|
||||
)
|
||||
|
||||
|
||||
def exec_mask_manipulation_validate_csv(df, all_sampled=False):
|
||||
assert not df.empty
|
||||
|
||||
validate_instruction_comment(df)
|
||||
validate_instruction_correlation_id_relation(df)
|
||||
|
||||
# Validate samples with non-zero correlation IDs (and with decoded instructions)
|
||||
samples_cid_non_zero_df = df[df["Correlation_Id"] != 0]
|
||||
|
||||
# exactly 65 kernels and 65 correlation id
|
||||
assert (samples_cid_non_zero_df["Correlation_Id"].astype(int) >= 1).all()
|
||||
assert (samples_cid_non_zero_df["Correlation_Id"].astype(int) <= 65).all()
|
||||
if all_sampled:
|
||||
# all correlation IDs must be sampled
|
||||
assert len(samples_cid_non_zero_df["Correlation_Id"].astype(int).unique()) == 65
|
||||
|
||||
first_64_kernels_df = samples_cid_non_zero_df[
|
||||
samples_cid_non_zero_df["Correlation_Id"] <= 64
|
||||
]
|
||||
|
||||
# Make a copy, so that we don't work (modify) a view.
|
||||
validate_exec_mask_based_on_correlation_id(first_64_kernels_df.copy())
|
||||
|
||||
# validate the last kernel
|
||||
kernel_65_df = df[df["Correlation_Id"] == 65]
|
||||
|
||||
# assert that v_rcp instructions are properly decoded
|
||||
# the v_rcp is executed by even SIMD threads
|
||||
validate_instruction_decoding(
|
||||
kernel_65_df,
|
||||
"v_rcp_f64",
|
||||
exec_mask_uint64=np.uint64(int("5555555555555555", 16)),
|
||||
source_code_lines_range=(288, 387),
|
||||
all_source_lines_samples=all_sampled,
|
||||
)
|
||||
|
||||
# assert that v_rcp_f32 instructions are properly decoded
|
||||
# the v_rcp_f32 is executed by odd SIMD threads
|
||||
validate_instruction_decoding(
|
||||
kernel_65_df,
|
||||
"v_rcp_f32",
|
||||
exec_mask_uint64=np.uint64(int("AAAAAAAAAAAAAAAA", 16)),
|
||||
source_code_lines_range=(391, 490),
|
||||
all_source_lines_samples=all_sampled,
|
||||
)
|
||||
@@ -0,0 +1,244 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def validate_json_exec_mask_manipulation(
|
||||
data_json, pc_sampling_method="host_trap", all_sampled=False
|
||||
):
|
||||
# Although functional programming might look more elegant,
|
||||
# I was trying to avoid multiple iteration over the list of samples.
|
||||
# Thus, I decided to use procedural programming instead.
|
||||
# Although, it would be more elegant to wrap some of the checks in dedicated functions,
|
||||
# I noticed that it can introduce significant overhead, so I decided to inline those checks.
|
||||
|
||||
# the function assume homogenous system
|
||||
agents = data_json["agents"]
|
||||
gpu_agents = list(filter(lambda agent: agent["type"] == 2, agents))
|
||||
# There should be at least one GPU agent
|
||||
assert len(gpu_agents) > 0
|
||||
first_gpu_agent = gpu_agents[0]
|
||||
num_xcc = first_gpu_agent["num_xcc"]
|
||||
max_waves_per_simd = first_gpu_agent["max_waves_per_simd"]
|
||||
simd_per_cu = first_gpu_agent["simd_per_cu"]
|
||||
|
||||
instructions = data_json["strings"]["pc_sample_instructions"]
|
||||
comments = data_json["strings"]["pc_sample_comments"]
|
||||
|
||||
# execution mask where even SIMD lanes are active
|
||||
# correspond to the v_rcp_f64 instructions of the last kernel
|
||||
even_simds_active_exec_mask = np.uint64(int("5555555555555555", 16))
|
||||
# start and end source code lines of the v_rcp_f64 instructions of the last kernel
|
||||
v_rcp_f64_start_line_num, v_rcp_f64_end_line_num = 288, 387
|
||||
# execution mask where even SIMD lanes are active
|
||||
# correspond to the v_rcp_f64 instructions of the last kernel
|
||||
odd_simds_active_exec_mask = np.uint64(int("AAAAAAAAAAAAAAAA", 16))
|
||||
# start and end source code lines of the v_rcp_f32 0 instructions of the last kernel
|
||||
v_rcp_f32_start_line_num, v_rcp_f32_end_line_num = 391, 490
|
||||
|
||||
# sampled wave_ids of the last kernel
|
||||
kernel65_sampled_wave_in_grp = set()
|
||||
# sampled source lines of the last kernel matching v_rcp_f64 instructions
|
||||
kernel65_v_rcp_64_sampled_source_line_set = set()
|
||||
# sampled source lines of the last kernel matching v_rcp_f64 instructions
|
||||
kernel65_v_rcp_f32_sampled_source_line_set = set()
|
||||
# sampled correlation IDs
|
||||
sampled_cids_set = set()
|
||||
# pairs of sampled SIMD ids and waveslot IDs
|
||||
sampled_simd_waveslots_pairs = set()
|
||||
# sampled chiplets
|
||||
sampled_chiplets = set()
|
||||
# sample VMIDs
|
||||
sampled_vmids = set()
|
||||
# TODO: Similar reason for introducing stochastic_assert inside the csv.py.
|
||||
# When asserting certain conditions related to exec_masks for all samples,
|
||||
# we observe some failures.
|
||||
# This usually happens because some small number of samples (e.g., 1-10 out of 100k)
|
||||
# do not satisfy the condition. This is either a regression in the ROCr 2nd level trap
|
||||
# handler (as sometimes execution mask or correlation ID mismatches), or
|
||||
# just stochastic nature of the sampling (meaning our checks are too strict).
|
||||
# To relax checks, we introduce an assertion that will allow some small number
|
||||
# of samples to disobey the condition.
|
||||
# This is a temporary solution until we find the root cause of the issue.
|
||||
|
||||
failing_exec_mask_checks_samples_num = 0
|
||||
# We noticed failing samples in:
|
||||
# 1. kernels 1-64
|
||||
# 2. kernel 65 even SIMD lanes
|
||||
# 3. kernel 64 odd SIMD lanes
|
||||
# The number of failing samples is less than 10 per category.
|
||||
max_number_of_failing_records = 30
|
||||
|
||||
for sample in data_json["buffer_records"][f"pc_sample_{pc_sampling_method}"]:
|
||||
record = sample["record"]
|
||||
cid = record["corr_id"]["internal"]
|
||||
|
||||
# pull information from hw_id
|
||||
hw_id = record["hw_id"]
|
||||
sampled_chiplets.add(hw_id["chiplet"])
|
||||
sampled_simd_waveslots_pairs.add((hw_id["simd_id"], hw_id["wave_id"]))
|
||||
sampled_vmids.add(hw_id["vm_id"])
|
||||
|
||||
# Checks specific for all samples
|
||||
|
||||
# cids must be non-negative numbers
|
||||
assert cid >= 0
|
||||
|
||||
inst_index = sample["inst_index"]
|
||||
|
||||
# Since we're not enabling any kind of API tracing, the internal correlation id should
|
||||
# be equal to the dispatch_id
|
||||
assert cid == record["dispatch_id"]
|
||||
|
||||
if cid == 0:
|
||||
# Samples originates either from a blit kernel or self-modifying code.
|
||||
# Thus, code object is uknown, as well as the instruction.
|
||||
assert record["pc"]["code_object_id"] == 0
|
||||
assert inst_index == -1
|
||||
else:
|
||||
# Update set of sampled cids
|
||||
sampled_cids_set.add(cid)
|
||||
|
||||
# All samples with non-zero correlation ID should pass the following checks
|
||||
# code object is know, so as the instruction
|
||||
assert record["pc"]["code_object_id"] != 0
|
||||
assert inst_index != -1
|
||||
|
||||
wgid = record["wrkgrp_id"]
|
||||
# check corrdinates of the workgroup
|
||||
assert wgid["x"] >= 0 and wgid["x"] <= 1023
|
||||
assert wgid["y"] == 0
|
||||
assert wgid["z"] == 0
|
||||
|
||||
wave_in_grp = record["wave_in_grp"]
|
||||
exec_mask = record["exec_mask"]
|
||||
|
||||
if cid < 65:
|
||||
# checks specific for samples from first 64 kernels
|
||||
assert wave_in_grp == 0
|
||||
# inline if possible
|
||||
# validate_json_exec_mask_based_on_cid(sample.record)
|
||||
|
||||
# The function assumes that each kernel launches 1024 blocks.
|
||||
# Each block contains number of threads that matches correlation ID of the kernel.
|
||||
# The exec mask of a sample should contain number of ones equal to
|
||||
# the correlation ID of the kernel during which execution the sample was generated.
|
||||
# assert bin(exec_mask).count("1") == cid
|
||||
if bin(exec_mask).count("1") != cid:
|
||||
failing_exec_mask_checks_samples_num += 1
|
||||
|
||||
# TODO: Comment out the following code if it causes spurious fails.
|
||||
# The more conservative constraint based on the experience follows.
|
||||
# The exec mask of sampled instructions of the kernels respect the following pattern:
|
||||
# cid -> exec
|
||||
# 1 -> 0b1
|
||||
# 2 -> 0b11
|
||||
# 3 -> 0b111
|
||||
# ...
|
||||
# 64 -> 0xffffffffffffffff
|
||||
exec_mask_str = "0b" + "1" * cid
|
||||
# assert np.uint64(exec_mask) == np.uint64(int(exec_mask_str, 2))
|
||||
if np.uint64(exec_mask) != np.uint64(int(exec_mask_str, 2)):
|
||||
failing_exec_mask_checks_samples_num += 1
|
||||
else:
|
||||
# No more that 65 cids
|
||||
assert cid == 65
|
||||
# Monitor wave_in_group being sampled
|
||||
kernel65_sampled_wave_in_grp.add(wave_in_grp)
|
||||
# chekcs specific for samples from the last kernel
|
||||
assert wave_in_grp >= 0 and wave_in_grp <= 3
|
||||
|
||||
# validate instruction decoding
|
||||
inst = instructions[inst_index]
|
||||
comm = comments[inst_index]
|
||||
# The instruction comment is isually in the following format:
|
||||
# /path/to/source/file.cpp:line_num
|
||||
line_num = int(comm.split(":")[-1])
|
||||
if inst.startswith("v_rcp_f64"):
|
||||
# even SIMD lanes active
|
||||
# assert np.uint64(exec_mask) == even_simds_active_exec_mask
|
||||
if np.uint64(exec_mask) != even_simds_active_exec_mask:
|
||||
failing_exec_mask_checks_samples_num += 1
|
||||
|
||||
assert (
|
||||
line_num >= v_rcp_f64_start_line_num
|
||||
and line_num <= v_rcp_f64_end_line_num
|
||||
)
|
||||
kernel65_v_rcp_64_sampled_source_line_set.add(line_num)
|
||||
elif inst.startswith("v_rcp_f32"):
|
||||
# odd SIMD lanes active
|
||||
# assert np.uint64(exec_mask) == odd_simds_active_exec_mask
|
||||
if np.uint64(exec_mask) != odd_simds_active_exec_mask:
|
||||
failing_exec_mask_checks_samples_num += 1
|
||||
|
||||
assert (
|
||||
line_num >= v_rcp_f32_start_line_num
|
||||
and line_num <= v_rcp_f32_end_line_num
|
||||
)
|
||||
kernel65_v_rcp_f32_sampled_source_line_set.add(line_num)
|
||||
|
||||
if all_sampled:
|
||||
# All cids that belongs to the range [1, 65] should be samples
|
||||
assert len(sampled_cids_set) == 65
|
||||
|
||||
# all wave_ids that belongs to the range [0, 3] should be sampled for the last kernel
|
||||
assert len(kernel65_sampled_wave_in_grp) == 4
|
||||
|
||||
# all source lines matches v_rcp_f64 instructions of the last kernel should be sampled
|
||||
assert len(kernel65_v_rcp_64_sampled_source_line_set) == (
|
||||
v_rcp_f64_end_line_num - v_rcp_f64_start_line_num + 1
|
||||
)
|
||||
# all source lines matches v_rcp_f32 instructions of the last kernel should be sampled
|
||||
assert len(kernel65_v_rcp_f32_sampled_source_line_set) == (
|
||||
v_rcp_f32_end_line_num - v_rcp_f32_start_line_num + 1
|
||||
)
|
||||
|
||||
# all chiplets must be sampled
|
||||
assert len(sampled_chiplets) == num_xcc
|
||||
# all (simd ID, waveslot ID) pairs must be samples
|
||||
assert len(sampled_simd_waveslots_pairs) == simd_per_cu * max_waves_per_simd
|
||||
|
||||
# assert chiplet index
|
||||
assert all(map(lambda chiplet: 0 <= chiplet < num_xcc, sampled_chiplets))
|
||||
# assert (SIMD ID, waveslot ID) combinations
|
||||
assert all(
|
||||
map(
|
||||
lambda simd_waveslot: (0 <= simd_waveslot[0] < simd_per_cu)
|
||||
and (0 <= simd_waveslot[1] < max_waves_per_simd),
|
||||
sampled_simd_waveslots_pairs,
|
||||
)
|
||||
)
|
||||
|
||||
# Apparently, not all dispatches must belong to the same VMID,
|
||||
# so I'm temporarily disabling the following check.
|
||||
# # all samples should belong to the same VMID
|
||||
# assert len(sampled_vmids) == 1
|
||||
|
||||
# assert that the number of failing samples is acceptable
|
||||
assert (
|
||||
failing_exec_mask_checks_samples_num <= max_number_of_failing_records
|
||||
), "Number of failing samples failing exec_mask check is too high"
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling/stochastic
|
||||
)
|
||||
|
||||
set(PC_SAMPLING_PYTHON_SOURCES __init__.py)
|
||||
|
||||
foreach(_FILE ${PC_SAMPLING_PYTHON_SOURCES})
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/${_FILE} ${PACKAGE_OUTPUT_DIR}/${_FILE}
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(csv)
|
||||
add_subdirectory(json)
|
||||
@@ -0,0 +1,24 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
@@ -0,0 +1,16 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling/stochastic/csv
|
||||
)
|
||||
|
||||
set(PC_SAMPLING_PYTHON_SOURCES __init__.py)
|
||||
|
||||
foreach(_FILE ${PC_SAMPLING_PYTHON_SOURCES})
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/${_FILE} ${PACKAGE_OUTPUT_DIR}/${_FILE}
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(gfx9)
|
||||
@@ -0,0 +1,24 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling/stochastic/csv/gfx9
|
||||
)
|
||||
|
||||
set(PC_SAMPLING_PYTHON_SOURCES
|
||||
__init__.py valu_instructions.py matrix_instructions.py texture_instructions.py
|
||||
flat_instructions.py lds_instructions.py)
|
||||
|
||||
foreach(_FILE ${PC_SAMPLING_PYTHON_SOURCES})
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/${_FILE} ${PACKAGE_OUTPUT_DIR}/${_FILE}
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(s_instructions)
|
||||
@@ -0,0 +1,110 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from .s_instructions import validate_s_instructions
|
||||
from .valu_instructions import validate_valu_instructions
|
||||
from .texture_instructions import validate_texture_instructions
|
||||
from .matrix_instructions import validate_matrix_instructions
|
||||
from .lds_instructions import validate_lds_instructions
|
||||
from .flat_instructions import validate_flat_instructions
|
||||
|
||||
|
||||
def validate_wave_count(df):
|
||||
# Validating number of actives waves on a cu
|
||||
assert (
|
||||
(df["Wave_Count"] >= 1) & (df["Wave_Count"] <= 32)
|
||||
).all(), "Invalid Wave_Count"
|
||||
|
||||
|
||||
def validate_issued_instruction_type_no_inst(samples):
|
||||
# NO_INST type of instructions means instruction is not issued
|
||||
issued_type_no_inst = samples[samples["Instruction_Type"] == "NO_INST"]
|
||||
assert len(issued_type_no_inst) == 0, "NO_INST implies no instruction is issued"
|
||||
|
||||
|
||||
def validate_issued_instruction_type_other(samples):
|
||||
# OTHER type of instructions still to be determined
|
||||
issued_type_other = samples[samples["Instruction_Type"] == "OTHER"]
|
||||
assert len(issued_type_other) == 0, "OTHER type of instruction observed first time"
|
||||
|
||||
|
||||
def validate_issued_instruction_type_lds_direct(samples):
|
||||
# LDS_DIRECT type of instructions do not exist on gfx9
|
||||
issued_type_lds_direct = samples[samples["Instruction_Type"] == "LDS_DIRECT"]
|
||||
assert (
|
||||
len(issued_type_lds_direct) == 0
|
||||
), "LDS direct type of instruction observed on GFX9"
|
||||
|
||||
|
||||
def validate_issued_instruction_type_dual_valu(samples):
|
||||
# LDS_DIRECT type of instructions do not exist on gfx9
|
||||
issued_type_dual_valu = samples[samples["Instruction_Type"] == "DUAL_VALU"]
|
||||
assert (
|
||||
len(issued_type_dual_valu) == 0
|
||||
), "DUAL_VALU type of instruction observed on GFX9"
|
||||
|
||||
|
||||
# TODO: add checks for missing instruction types
|
||||
# - export
|
||||
|
||||
|
||||
def validate_stochastic_samples_csv(df: pd.DataFrame):
|
||||
# We expect mode valid than invalid samples
|
||||
# TODO: use stats for comparing valid vs invalid samples
|
||||
# invalid_samples = df[df["Valid"] == False]
|
||||
# valid_samples = df[df["Valid"]].copy()
|
||||
# assert len(valid_samples) > len(invalid_samples)
|
||||
|
||||
# only valid samples reside in df
|
||||
valid_samples = df.copy()
|
||||
|
||||
validate_wave_count(valid_samples)
|
||||
|
||||
# The following checks assumes that we were able to decode
|
||||
# the instruction, meaning a code object and dispatch must be known.
|
||||
valid_samples = valid_samples[valid_samples["Dispatch_Id"] > 0]
|
||||
|
||||
# scalar, barrier, waitcnt, jump, message, branches (taken and not taken)
|
||||
# are handled inside `validate_s_instructions` function
|
||||
validate_s_instructions(valid_samples)
|
||||
validate_valu_instructions(valid_samples)
|
||||
validate_texture_instructions(valid_samples)
|
||||
validate_matrix_instructions(valid_samples)
|
||||
validate_lds_instructions(valid_samples)
|
||||
validate_flat_instructions(valid_samples)
|
||||
|
||||
# validating issued instructions for uncovered types
|
||||
valid_samples_issued = valid_samples[
|
||||
valid_samples["Wave_Issued_Instruction"] == True
|
||||
].copy()
|
||||
validate_issued_instruction_type_no_inst(valid_samples_issued)
|
||||
validate_issued_instruction_type_other(valid_samples_issued)
|
||||
|
||||
# The following two types of instructions should not be observed on gfx9
|
||||
validate_issued_instruction_type_lds_direct(valid_samples_issued)
|
||||
validate_issued_instruction_type_dual_valu(valid_samples_issued)
|
||||
@@ -0,0 +1,74 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_flat_instructions_issued(samples_issued):
|
||||
# issued instruction with type == FLAT -> instruction starts with either flat_ or global_
|
||||
issued_type_flat = samples_issued[
|
||||
samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_FLAT"
|
||||
]
|
||||
assert (
|
||||
issued_type_flat["Instruction"]
|
||||
.apply(lambda x: x.startswith("flat_") or x.startswith("global_"))
|
||||
.all()
|
||||
)
|
||||
|
||||
# if issued instruction starts with global_ or flat_ -> its type must be FLAT
|
||||
issued_flat_or_global = samples_issued[
|
||||
samples_issued["Instruction"].apply(
|
||||
lambda x: x.startswith("flat_") or x.startswith("global_")
|
||||
)
|
||||
]
|
||||
assert (
|
||||
issued_flat_or_global["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_FLAT"
|
||||
).all()
|
||||
|
||||
|
||||
def validate_flat_instructions_stalled(samples):
|
||||
global_flat_regex = r"^(global|flat)_"
|
||||
flat_samples = samples[samples["Instruction"].str.match(global_flat_regex)]
|
||||
flat_stalled = flat_samples[flat_samples["Wave_Issued_Instruction"] == False]
|
||||
|
||||
assert (
|
||||
flat_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
or x == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_flat_instructions(samples):
|
||||
samples_issued = samples[samples["Wave_Issued_Instruction"]]
|
||||
validate_flat_instructions_issued(samples_issued)
|
||||
validate_flat_instructions_stalled(samples)
|
||||
@@ -0,0 +1,67 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_lds_instructions_issued(samples_issued):
|
||||
# issued instruction with type == LDS -> instruction starts with ds_
|
||||
issued_type_lds = samples_issued[
|
||||
samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_LDS"
|
||||
]
|
||||
assert issued_type_lds["Instruction"].apply(lambda x: x.startswith("ds_")).all()
|
||||
|
||||
# issued instruction starts with ds_ -> it must be LDS
|
||||
issued_ds = samples_issued[
|
||||
samples_issued["Instruction"].apply(lambda x: x.startswith("ds_"))
|
||||
]
|
||||
assert (
|
||||
issued_ds["Instruction_Type"] == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_LDS"
|
||||
).all()
|
||||
|
||||
|
||||
def validate_lds_instructions_stalled(samples):
|
||||
lds_samples = samples[samples["Instruction"].apply(lambda x: x.startswith("ds_"))]
|
||||
lds_stalled = lds_samples[lds_samples["Wave_Issued_Instruction"] == False]
|
||||
|
||||
# TODO: question - why we observed alu_dependency on matrix_multiply_tile kernel
|
||||
assert (
|
||||
lds_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
or x == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_lds_instructions(samples):
|
||||
samples_issued = samples[samples["Wave_Issued_Instruction"]]
|
||||
validate_lds_instructions_issued(samples_issued)
|
||||
validate_lds_instructions_stalled(samples)
|
||||
@@ -0,0 +1,107 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_matrix_instructions_issued(samples_issued):
|
||||
# issued instruction with type == MATRIX -> instruction starts with v_mfma
|
||||
issued_type_matrix = samples_issued[
|
||||
samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_MATRIX"
|
||||
]
|
||||
assert issued_type_matrix["Instruction"].apply(lambda x: x.startswith("v_mfma")).all()
|
||||
# v_mfma_f32 goes through Matrix (MAI) arbiter, while v_mfma_f64 goes through the VALU arbiter
|
||||
|
||||
# SGEMM goes through Matrix (MAI arbiter)
|
||||
v_mfma_f32_issued = samples_issued[
|
||||
samples_issued["Instruction"].apply(lambda x: x.startswith("v_mfma_f32"))
|
||||
]
|
||||
assert (
|
||||
v_mfma_f32_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_MATRIX"
|
||||
).all()
|
||||
|
||||
# DGEMM goes through VALU arbiter
|
||||
v_mfma_f64_issued = samples_issued[
|
||||
samples_issued["Instruction"].apply(lambda x: x.startswith("v_mfma_f64"))
|
||||
]
|
||||
assert (v_mfma_f64_issued["Instruction_Type"] == "MATRIX").all()
|
||||
assert len(issued_type_matrix) == len(v_mfma_f32_issued) + len(v_mfma_f64_issued)
|
||||
|
||||
# TODO: find an example with MAI instructions
|
||||
|
||||
|
||||
def validate_dgemm_matrix_instructions_stalled(samples):
|
||||
v_mfma_f64_samples = samples[
|
||||
samples["Instruction"].apply(lambda x: x.startswith("v_mfma_f64"))
|
||||
]
|
||||
v_mfma_f64_stalled = v_mfma_f64_samples[
|
||||
v_mfma_f64_samples["Wave_Issued_Instruction"] == False
|
||||
]
|
||||
|
||||
assert (
|
||||
v_mfma_f64_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_sgemm_matrix_instructions_stalled(samples):
|
||||
v_mfma_f32_samples = samples[
|
||||
samples["Instruction"].apply(lambda x: x.startswith("v_mfma_f32"))
|
||||
]
|
||||
v_mfma_f32_stalled = v_mfma_f32_samples[
|
||||
v_mfma_f32_samples["Wave_Issued_Instruction"] == False
|
||||
]
|
||||
assert (
|
||||
v_mfma_f32_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_matrix_instructions_stalled(samples):
|
||||
validate_dgemm_matrix_instructions_stalled(samples)
|
||||
validate_sgemm_matrix_instructions_stalled(samples)
|
||||
# TODO" find an example to test this
|
||||
|
||||
|
||||
def validate_matrix_instructions(samples):
|
||||
samples_issued = samples[samples["Wave_Issued_Instruction"]]
|
||||
validate_matrix_instructions_issued(samples_issued)
|
||||
validate_matrix_instructions_stalled(samples)
|
||||
@@ -0,0 +1,23 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling/stochastic/csv/gfx9/s_instructions
|
||||
)
|
||||
|
||||
set(PC_SAMPLING_PYTHON_SOURCES
|
||||
__init__.py
|
||||
branch_instructions.py
|
||||
waitcnt.py
|
||||
other_instructions.py
|
||||
scalar_instructions.py
|
||||
internal_instructions.py
|
||||
jump_instructions.py
|
||||
message_instructions.py
|
||||
barrier_instructions.py)
|
||||
|
||||
foreach(_FILE ${PC_SAMPLING_PYTHON_SOURCES})
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/${_FILE} ${PACKAGE_OUTPUT_DIR}/${_FILE}
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
@@ -0,0 +1,151 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from functools import partial
|
||||
|
||||
from .branch_instructions import validate_branch_instructions
|
||||
from .waitcnt import validate_waitcnt
|
||||
from .other_instructions import validate_other_instructions
|
||||
from .scalar_instructions import validate_scalar_instructions
|
||||
from .internal_instructions import validate_internal_instructions
|
||||
from .jump_instructions import validate_jump_instructions
|
||||
from .message_instructions import validate_message_instructions
|
||||
from .barrier_instructions import validate_barrier_instructions
|
||||
|
||||
|
||||
# Using Prefix Tree to classify the instruction type
|
||||
# I did this instead of the regex becuase I wanted to try if we could
|
||||
# generalize this approach for other types of instructions.
|
||||
# The dream scenario: We have a giant list of all instructions and their
|
||||
# types. Then we parse the list and dynamically determine the checks
|
||||
# based on the instruction types.
|
||||
|
||||
|
||||
# TODO: extract this outside of the file
|
||||
class TrieNode:
|
||||
def __init__(self):
|
||||
self.children = {}
|
||||
self.instruction_type = None # Store the instruction type at the leaf node
|
||||
|
||||
|
||||
class PrefixTree:
|
||||
def __init__(self):
|
||||
self.root = TrieNode()
|
||||
|
||||
def insert(self, full_prefix, instruction_type):
|
||||
"""Insert a prefix and its associated instruction type into the Trie."""
|
||||
node = self.root
|
||||
for char in full_prefix:
|
||||
if char not in node.children:
|
||||
node.children[char] = TrieNode()
|
||||
node = node.children[char]
|
||||
node.instruction_type = (
|
||||
instruction_type # Assign the instruction type at the leaf
|
||||
)
|
||||
|
||||
def get_instruction_type(self, instruction):
|
||||
"""Get the list of instruction types based on the longest matching prefix."""
|
||||
node = self.root
|
||||
matched_types = [] # List to store matched types
|
||||
|
||||
# Traverse the instruction one character at a time
|
||||
for char in instruction:
|
||||
if char not in node.children:
|
||||
break # Stop if no match is found
|
||||
|
||||
node = node.children[char]
|
||||
|
||||
# If we reach a node that has an instruction type, store it
|
||||
if node.instruction_type:
|
||||
matched_types.append(node.instruction_type)
|
||||
|
||||
return matched_types
|
||||
|
||||
|
||||
instructions_with_types = [
|
||||
("s_", "SCALAR"), # Scalar instructions (general category)
|
||||
("s_waitcnt", "WAITCNT"), # WAITCNT (specific)
|
||||
("s_sendmsg", "MESSAGE"), # MESSAGE (specific)
|
||||
("s_barrier", "BARRIER"), # BARRIER (specifix)
|
||||
("s_swappc", "JUMP"), # JUMP (specific)
|
||||
("s_setpc", "JUMP"), # JUMP
|
||||
("s_setpc", "JUMP"), # JUMP
|
||||
("s_sleep", "JUMP"), # JUMP
|
||||
("s_branch", "BRANCH"), # BRANCH
|
||||
("s_cbranch", "BRANCH"), # BRANCH (conditional)
|
||||
("s_wakeup", "OTHER"), # OHTER
|
||||
("s_nop", "INTERNAL"), # INTERNAL
|
||||
("s_sleep", "INTERNAL"), # INTERNAL
|
||||
]
|
||||
|
||||
|
||||
inst_type_verify_functions = {
|
||||
"BRANCH": validate_branch_instructions,
|
||||
"WAITCNT": validate_waitcnt,
|
||||
"OTHER": validate_other_instructions,
|
||||
"SCALAR": validate_scalar_instructions,
|
||||
"INTERNAL": validate_internal_instructions,
|
||||
"JUMP": validate_jump_instructions,
|
||||
"MESSAGE": validate_message_instructions,
|
||||
"BARRIER": validate_barrier_instructions,
|
||||
}
|
||||
|
||||
|
||||
# Function to classify instructions based on the Trie
|
||||
def classify_instruction_by_prefix(prefix_tree, instruction):
|
||||
# extracting the base of the instruction (e.g., s_mov_*, v_mov_*, s_setpc_*, ...)
|
||||
base_instruction = instruction.split()[0]
|
||||
|
||||
# Classify based on the Trie (general classification)
|
||||
instruction_types = prefix_tree.get_instruction_type(base_instruction)
|
||||
|
||||
# aways use the specific type
|
||||
return instruction_types[-1]
|
||||
|
||||
|
||||
def enforce_type_inheritance(sub_df, parent_df):
|
||||
for col in parent_df.columns:
|
||||
sub_df[col] = sub_df[col].astype(parent_df[col].dtype)
|
||||
return sub_df
|
||||
|
||||
|
||||
def validate_s_instructions(df):
|
||||
s_instructions = df[df["Instruction"].apply(lambda x: x.startswith("s_"))].copy()
|
||||
|
||||
# fill in the Prefi Tree
|
||||
prefix_tree = PrefixTree()
|
||||
for prefix, instruction_type in instructions_with_types:
|
||||
prefix_tree.insert(prefix, instruction_type)
|
||||
|
||||
_classify_instruction_by_prefix = partial(classify_instruction_by_prefix, prefix_tree)
|
||||
s_instructions["Instruction_Type_From_Name"] = s_instructions["Instruction"].apply(
|
||||
_classify_instruction_by_prefix
|
||||
)
|
||||
|
||||
for inst_type, subframe in s_instructions.groupby("Instruction_Type_From_Name"):
|
||||
# subframe = enforce_type_inheritance(subframe, s_instructions)
|
||||
if inst_type in inst_type_verify_functions:
|
||||
# Pass all samples and filtered samples to the verification function.
|
||||
inst_type_verify_functions[inst_type](df, subframe)
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_barrier_instructions_issued(all_samples, barrier_samples):
|
||||
barrier_type_samples_issued = all_samples[
|
||||
all_samples["Wave_Issued_Instruction"]
|
||||
& (
|
||||
all_samples["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BARRIER"
|
||||
)
|
||||
]
|
||||
|
||||
barrier_samples_issued = barrier_samples[barrier_samples["Wave_Issued_Instruction"]]
|
||||
# sanity check
|
||||
assert len(barrier_type_samples_issued) == len(barrier_samples_issued)
|
||||
# repeat checks from above
|
||||
assert (
|
||||
barrier_samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BARRIER"
|
||||
).all()
|
||||
|
||||
|
||||
def validate_barrier_instructions_stalled(barrier_samples):
|
||||
barrier_samples_stalled = barrier_samples[
|
||||
barrier_samples["Wave_Issued_Instruction"] == False
|
||||
]
|
||||
assert (
|
||||
barrier_samples_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
or x == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_BARRIER_WAIT"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_barrier_instructions(all_samples, barrier_samples):
|
||||
validate_barrier_instructions_issued(all_samples, barrier_samples)
|
||||
validate_barrier_instructions_stalled(barrier_samples)
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_issued_instruction_type_branch_taken(samples):
|
||||
# issued instruction with type BRANCH_TAKEN -> instruction starts with either s_cbranch or s_branch
|
||||
issued_type_branch_taken = samples[
|
||||
(
|
||||
samples["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_TAKEN"
|
||||
)
|
||||
& samples["Wave_Issued_Instruction"]
|
||||
]
|
||||
assert (
|
||||
issued_type_branch_taken["Instruction"]
|
||||
.apply(lambda x: x.startswith("s_branch") or x.startswith("s_cbranch"))
|
||||
.all()
|
||||
)
|
||||
assert issued_type_branch_taken["Wave_Issued_Instruction"].all()
|
||||
|
||||
# if issued instruction starts with s_branch (unconditional branch) -> its type must be BRANCH_TAKEN
|
||||
issued_s_branch = samples[
|
||||
samples["Instruction"].apply(lambda x: x.startswith("s_branch"))
|
||||
& samples["Wave_Issued_Instruction"]
|
||||
]
|
||||
assert (
|
||||
issued_s_branch["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_TAKEN"
|
||||
).all()
|
||||
|
||||
# see `validate_issued_instruction_type_branch_not_taken` for more info about s_cbranch checks
|
||||
|
||||
|
||||
def validate_issued_instruction_type_branch_not_taken(samples):
|
||||
# issued instruction with type BRANCH_NOT_TAKEN -> instruction is conditional branch (starts s_cbranch)
|
||||
issued_type_branch_not_taken = samples[
|
||||
(
|
||||
samples["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_NOT_TAKEN"
|
||||
)
|
||||
& samples["Wave_Issued_Instruction"]
|
||||
]
|
||||
assert (
|
||||
issued_type_branch_not_taken["Instruction"]
|
||||
.apply(lambda x: x.startswith("s_cbranch"))
|
||||
.all()
|
||||
)
|
||||
assert issued_type_branch_not_taken["Wave_Issued_Instruction"].all()
|
||||
|
||||
# if issued instruction starts with s_cbranch -> its type is either BRANCH_TAKEN on BRANCH_NOT_TAKEN
|
||||
issued_s_cbranch = samples[
|
||||
samples["Instruction"].apply(lambda x: x.startswith("s_cbranch"))
|
||||
& samples["Wave_Issued_Instruction"]
|
||||
]
|
||||
assert (
|
||||
(
|
||||
issued_s_cbranch["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_TAKEN"
|
||||
)
|
||||
| (
|
||||
issued_s_cbranch["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_NOT_TAKEN"
|
||||
)
|
||||
).all()
|
||||
|
||||
|
||||
def s_branch_not_issued(stalled_samples):
|
||||
s_branch_stalled = stalled_samples[
|
||||
stalled_samples["Instruction"].apply(lambda x: x.startswith("s_branch"))
|
||||
]
|
||||
|
||||
if len(s_branch_stalled) > 0:
|
||||
# No ALUDEP nor ARBWINEXSTALL observed so far for unconditional branches
|
||||
assert (
|
||||
s_branch_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
!= "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY"
|
||||
and x
|
||||
!= "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_stalled_branches(samples):
|
||||
stalled_samples = samples[samples["Wave_Issued_Instruction"] == False]
|
||||
|
||||
assert (
|
||||
stalled_samples["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
# Further constraints for unconditional branches
|
||||
s_branch_not_issued(stalled_samples)
|
||||
|
||||
|
||||
def validate_branch_instructions(all_samples, branch_samples):
|
||||
"""
|
||||
Use all_samples to verify the ROCProfV3 determines `Instruction_Type` field properly.
|
||||
|
||||
Use filtered_samples to verify both issued and stalled branch instructions.
|
||||
"""
|
||||
# For the issued branches, use all samples, as the called functions will do
|
||||
# separation based on branch type (conditional or unconditional)
|
||||
validate_issued_instruction_type_branch_taken(all_samples)
|
||||
validate_issued_instruction_type_branch_not_taken(all_samples)
|
||||
|
||||
# stalled branches
|
||||
validate_stalled_branches(branch_samples)
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_internal_instructions(all_samples, internal_samples):
|
||||
assert (internal_samples["Wave_Issued_Instruction"] == False).all()
|
||||
assert (
|
||||
internal_samples["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_INTERNAL_INSTRUCTION"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_jump_instructions_issued(all_samples, jump_samples):
|
||||
jump_type_samples_issued = all_samples[
|
||||
all_samples["Wave_Issued_Instruction"]
|
||||
& (
|
||||
all_samples["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_JUMP"
|
||||
)
|
||||
]
|
||||
|
||||
jump_samples_issued = jump_samples[jump_samples["Wave_Issued_Instruction"]]
|
||||
# sanity check
|
||||
assert len(jump_type_samples_issued) == len(jump_samples_issued)
|
||||
# repeat checks from above
|
||||
assert (
|
||||
jump_samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_JUMP"
|
||||
).all()
|
||||
|
||||
|
||||
def validate_jump_instructions_stalled(jump_samples):
|
||||
jump_samples_stalled = jump_samples[jump_samples["Wave_Issued_Instruction"] == False]
|
||||
assert (
|
||||
jump_samples_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_jump_instructions(all_samples, jump_samples):
|
||||
validate_jump_instructions_issued(all_samples, jump_samples)
|
||||
validate_jump_instructions_stalled(jump_samples)
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_message_instructions_issued(all_samples, message_samples):
|
||||
message_type_samples_issued = all_samples[
|
||||
all_samples["Wave_Issued_Instruction"]
|
||||
& (
|
||||
all_samples["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_MESSAGE"
|
||||
)
|
||||
]
|
||||
|
||||
message_samples_issued = message_samples[message_samples["Wave_Issued_Instruction"]]
|
||||
# sanity check
|
||||
assert len(message_type_samples_issued) == len(message_samples_issued)
|
||||
# repeat checks from above
|
||||
assert (
|
||||
message_samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_MESSAGE"
|
||||
).all()
|
||||
# TODO: find an example with messages
|
||||
|
||||
|
||||
def validate_message_instructions_stalled(message_samples):
|
||||
message_samples_stalled = message_samples[
|
||||
message_samples["Wave_Issued_Instruction"] == False
|
||||
]
|
||||
assert (
|
||||
message_samples_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_message_instructions(all_samples, message_samples):
|
||||
validate_message_instructions_issued(all_samples, message_samples)
|
||||
validate_message_instructions_stalled(message_samples)
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_other_instructions_issued(all_samples, other_samples):
|
||||
other_type_samples_issued = all_samples[
|
||||
all_samples["Wave_Issued_Instruction"]
|
||||
& (
|
||||
all_samples["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_OTHER"
|
||||
)
|
||||
]
|
||||
|
||||
other_samples_issued = other_samples[other_samples["Wave_Issued_Instruction"]]
|
||||
assert (
|
||||
other_samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_OTHER"
|
||||
).all()
|
||||
|
||||
assert len(other_type_samples_issued) == len(other_samples_issued)
|
||||
|
||||
|
||||
def validate_other_instructions_stalled(other_samples):
|
||||
other_samples_stalled = other_samples[
|
||||
other_samples["Wave_Issued_Instruction"] == False
|
||||
]
|
||||
|
||||
assert (
|
||||
other_samples_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_other_instructions(all_samples, filtered_samples):
|
||||
validate_other_instructions_issued(all_samples, filtered_samples)
|
||||
validate_other_instructions_stalled(filtered_samples)
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_scalar_instructions_issued(all_samples, scalar_samples):
|
||||
# From all samples, extract samples with SCALAR type
|
||||
scalar_type_samples_issued = all_samples[
|
||||
(
|
||||
all_samples["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_SCALAR"
|
||||
)
|
||||
& all_samples["Wave_Issued_Instruction"]
|
||||
]
|
||||
|
||||
# scalar_samples contains instructions starting with `s_`
|
||||
scalar_samples_issued = scalar_samples[scalar_samples["Wave_Issued_Instruction"]]
|
||||
# sanity check
|
||||
assert len(scalar_type_samples_issued) == len(scalar_samples_issued)
|
||||
# same checks as above
|
||||
assert (
|
||||
scalar_samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_SCALAR"
|
||||
).all()
|
||||
|
||||
|
||||
def validate_scalar_instructions_stalled(scalar_samples):
|
||||
scalar_samples_stalled = scalar_samples[
|
||||
scalar_samples["Wave_Issued_Instruction"] == False
|
||||
]
|
||||
|
||||
assert (
|
||||
scalar_samples_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
or x == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_scalar_instructions(all_samples, scalar_samples):
|
||||
validate_scalar_instructions_issued(all_samples, scalar_samples)
|
||||
validate_scalar_instructions_stalled(scalar_samples)
|
||||
@@ -0,0 +1,45 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_waitcnt(all_samples, waitcnt_samples):
|
||||
s_waitcnt_samples = all_samples[
|
||||
all_samples["Instruction"].apply(lambda x: x.startswith("s_waitcnt"))
|
||||
]
|
||||
# sanity check
|
||||
assert len(s_waitcnt_samples) == len(waitcnt_samples)
|
||||
|
||||
# `s_waitcnt` instructions are never issued on GFX9
|
||||
assert (waitcnt_samples["Wave_Issued_Instruction"] == False).all()
|
||||
# accepted stall reasons are
|
||||
assert (
|
||||
waitcnt_samples["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_WAITCNT"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
@@ -0,0 +1,74 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_texture_instructions_issued(samples_issued):
|
||||
# issued instruction with type == TEX -> instruction starts with buffer_
|
||||
issued_type_texture = samples_issued[
|
||||
samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_TEX"
|
||||
]
|
||||
assert (
|
||||
issued_type_texture["Instruction"].apply(lambda x: x.startswith("buffer_")).all()
|
||||
)
|
||||
|
||||
# issued instruction starts with buffer_ -> it must be TEX
|
||||
issued_buffer = samples_issued[
|
||||
samples_issued["Instruction"].apply(lambda x: x.startswith("buffer_"))
|
||||
]
|
||||
assert (
|
||||
issued_buffer["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_TEX"
|
||||
).all()
|
||||
# TODO: find an example with TEX instructions
|
||||
|
||||
|
||||
def validate_texture_instructions_stalled(samples):
|
||||
texture_samples = samples[
|
||||
samples["Instruction"].apply(lambda x: x.startswith("buffer"))
|
||||
]
|
||||
texture_stalled = texture_samples[texture_samples["Wave_Issued_Instruction"] == False]
|
||||
|
||||
assert (
|
||||
texture_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
or x == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
# TODO: find an example with texture instructions
|
||||
|
||||
|
||||
def validate_texture_instructions(samples):
|
||||
samples_issued = samples[samples["Wave_Issued_Instruction"]]
|
||||
validate_texture_instructions_issued(samples_issued)
|
||||
validate_texture_instructions_stalled(samples)
|
||||
@@ -0,0 +1,69 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_valu_instructions_issued(samples_issued):
|
||||
# issued instruction with type == VALU -> instruction starts with v_
|
||||
issued_type_valu = samples_issued[
|
||||
samples_issued["Instruction_Type"]
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_VALU"
|
||||
]
|
||||
assert issued_type_valu["Instruction"].apply(lambda x: x.startswith("v_")).all()
|
||||
|
||||
# issued instruction starts with v_ and is not matrix instruction -> it must be VALU
|
||||
issued_v = samples_issued[
|
||||
samples_issued["Instruction"].apply(
|
||||
lambda x: x.startswith("v_") and ("mfma" not in x)
|
||||
)
|
||||
]
|
||||
assert (
|
||||
issued_v["Instruction_Type"] == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_VALU"
|
||||
).all()
|
||||
|
||||
|
||||
def validate_valu_instructions_stalled(samples):
|
||||
valu_samples = samples[
|
||||
samples["Instruction"].apply(lambda x: x.startswith("v_") and ("mfma" not in x))
|
||||
]
|
||||
valu_stalled = valu_samples[valu_samples["Wave_Issued_Instruction"] == False]
|
||||
|
||||
assert (
|
||||
valu_stalled["Stall_Reason"]
|
||||
.apply(
|
||||
lambda x: x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE"
|
||||
or x
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def validate_valu_instructions(samples):
|
||||
samples_issued = samples[samples["Wave_Issued_Instruction"]]
|
||||
validate_valu_instructions_issued(samples_issued)
|
||||
validate_valu_instructions_stalled(samples)
|
||||
@@ -0,0 +1,16 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling/stochastic/json
|
||||
)
|
||||
|
||||
set(PC_SAMPLING_PYTHON_SOURCES __init__.py)
|
||||
|
||||
foreach(_FILE ${PC_SAMPLING_PYTHON_SOURCES})
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/${_FILE} ${PACKAGE_OUTPUT_DIR}/${_FILE}
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(gfx9)
|
||||
@@ -0,0 +1,24 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling/stochastic/json/gfx9
|
||||
)
|
||||
|
||||
set(PC_SAMPLING_PYTHON_SOURCES __init__.py arbiter_state.py s_instructions.py
|
||||
other_instructions.py)
|
||||
|
||||
foreach(_FILE ${PC_SAMPLING_PYTHON_SOURCES})
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/${_FILE} ${PACKAGE_OUTPUT_DIR}/${_FILE}
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
|
||||
# add_subdirectory(s_instructions)
|
||||
@@ -0,0 +1,176 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from collections import defaultdict
|
||||
from .arbiter_state import validate_arbiter_state
|
||||
from .other_instructions import (
|
||||
validate_valu_instructions,
|
||||
validate_flat_instructions,
|
||||
validate_lds_instructions,
|
||||
)
|
||||
from .s_instructions import (
|
||||
validate_internal_instructions,
|
||||
validate_barrier_instructions,
|
||||
validate_waitcnt,
|
||||
validate_branch_instructions,
|
||||
validate_scalar_instructions,
|
||||
)
|
||||
|
||||
# Using Prefix Tree to classify the instruction type
|
||||
# I did this instead of the regex becuase I wanted to try if we could
|
||||
# generalize this approach for other types of instructions.
|
||||
# The dream scenario: We have a giant list of all instructions and their
|
||||
# types. Then we parse the list and dynamically determine the checks
|
||||
# based on the instruction types.
|
||||
|
||||
|
||||
# TODO: extract this outside of the file
|
||||
class TrieNode:
|
||||
def __init__(self):
|
||||
self.children = {}
|
||||
self.instruction_type = None # Store the instruction type at the leaf node
|
||||
|
||||
|
||||
class PrefixTree:
|
||||
def __init__(self):
|
||||
self.root = TrieNode()
|
||||
|
||||
def insert(self, full_prefix, instruction_type):
|
||||
"""Insert a prefix and its associated instruction type into the Trie."""
|
||||
node = self.root
|
||||
for char in full_prefix:
|
||||
if char not in node.children:
|
||||
node.children[char] = TrieNode()
|
||||
node = node.children[char]
|
||||
node.instruction_type = (
|
||||
instruction_type # Assign the instruction type at the leaf
|
||||
)
|
||||
|
||||
def get_instruction_type(self, instruction):
|
||||
"""Get the list of instruction types based on the longest matching prefix."""
|
||||
node = self.root
|
||||
matched_types = [] # List to store matched types
|
||||
|
||||
# Traverse the instruction one character at a time
|
||||
for char in instruction:
|
||||
if char not in node.children:
|
||||
break # Stop if no match is found
|
||||
|
||||
node = node.children[char]
|
||||
|
||||
# If we reach a node that has an instruction type, store it
|
||||
if node.instruction_type:
|
||||
matched_types.append(node.instruction_type)
|
||||
|
||||
return matched_types
|
||||
|
||||
|
||||
instructions_with_types = [
|
||||
("s_", "SCALAR"), # Scalar instructions (general category)
|
||||
("s_waitcnt", "WAITCNT"), # WAITCNT (specific)
|
||||
("s_sendmsg", "MESSAGE"), # MESSAGE (specific)
|
||||
("s_barrier", "BARRIER"), # BARRIER (specifix)
|
||||
("s_swappc", "JUMP"), # JUMP (specific)
|
||||
("s_setpc", "JUMP"), # JUMP
|
||||
("s_setpc", "JUMP"), # JUMP
|
||||
("s_sleep", "JUMP"), # JUMP
|
||||
("s_branch", "BRANCH"), # BRANCH
|
||||
("s_cbranch", "BRANCH"), # BRANCH (conditional)
|
||||
("s_wakeup", "OTHER"), # OHTER
|
||||
("s_nop", "INTERNAL"), # INTERNAL
|
||||
("s_sleep", "INTERNAL"), # INTERNAL
|
||||
("v_", "VALU"), # VALU
|
||||
("v_mfma", "MATRIX"), # MATRIX
|
||||
("flat_", "FLAT"), # FLAT
|
||||
("global_", "FLAT"), # FLAT
|
||||
("ds_", "LDS"), # LDS
|
||||
("buffer_", "TEX"), # TEX
|
||||
]
|
||||
|
||||
|
||||
inst_type_verify_functions = {
|
||||
"BRANCH": validate_branch_instructions,
|
||||
"WAITCNT": validate_waitcnt,
|
||||
# "OTHER": validate_other_instructions,
|
||||
"SCALAR": validate_scalar_instructions,
|
||||
"INTERNAL": validate_internal_instructions,
|
||||
# "JUMP": validate_jump_instructions,
|
||||
# "MESSAGE": validate_message_instructions,
|
||||
"BARRIER": validate_barrier_instructions,
|
||||
"VALU": validate_valu_instructions,
|
||||
"FLAT": validate_flat_instructions,
|
||||
"LDS": validate_lds_instructions,
|
||||
}
|
||||
|
||||
|
||||
def validate_stochastic_samples_json(data_json):
|
||||
# fill in the Prefix Tree
|
||||
prefix_tree = PrefixTree()
|
||||
for prefix, instruction_type in instructions_with_types:
|
||||
prefix_tree.insert(prefix, instruction_type)
|
||||
|
||||
instructions = data_json["strings"]["pc_sample_instructions"]
|
||||
comments = data_json["strings"]["pc_sample_comments"]
|
||||
|
||||
insts_per_prefix_type = defaultdict(list)
|
||||
|
||||
for sample in data_json["buffer_records"]["pc_sample_stochastic"]:
|
||||
inst_index = sample["inst_index"]
|
||||
if inst_index == -1:
|
||||
# Ignoring samples from blit kernels
|
||||
continue
|
||||
record = sample["record"]
|
||||
# extend the record with the instruction
|
||||
record["inst"] = instructions[inst_index]
|
||||
|
||||
# get the instruction type from prefix tree
|
||||
inst_prefix_types = prefix_tree.get_instruction_type(record["inst"])
|
||||
# each type must have a type
|
||||
assert len(inst_prefix_types) > 0
|
||||
# As more then one type can be matched, we take the last one as the most specific.
|
||||
inst_prefix_type = inst_prefix_types[-1]
|
||||
insts_per_prefix_type[inst_prefix_type].append(record)
|
||||
|
||||
# For each sample, we need to validate wave_cnt and arbiter state
|
||||
wave_cnt = record["wave_cnt"]
|
||||
assert wave_cnt >= 0 and wave_cnt <= 32, "Invalid wave count"
|
||||
|
||||
# arbiter state check
|
||||
snapshot = record["snapshot"]
|
||||
validate_arbiter_state(snapshot)
|
||||
|
||||
# Check now the instruction type and arb state correlation.
|
||||
# We do that for all samples of a single instruction type all at once
|
||||
# to minimize the number of functions calls (one call for all samples, instead of a function
|
||||
# call per sample).
|
||||
# Please note that each sample is iterated at most twice.
|
||||
# The first time to group samples per instruction type, and the second time to validate samples.
|
||||
for inst_prefix_type, sample_records in insts_per_prefix_type.items():
|
||||
if inst_prefix_type in inst_type_verify_functions:
|
||||
inst_type_verify_functions[inst_prefix_type](sample_records)
|
||||
else:
|
||||
assert False, f"Unhandle instruction type: {inst_prefix_type}"
|
||||
@@ -0,0 +1,104 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_arbiter_state(snapshot):
|
||||
# VALU pipe checks
|
||||
if snapshot["dual_issue_valu"]:
|
||||
# (valu_issue = 1 & valu_stall = 0) is the only allowed
|
||||
assert (
|
||||
snapshot["arb_state_issue_valu"] == 1
|
||||
and snapshot["arb_state_stall_valu"] == 0
|
||||
), "Dual issue VALU arbiter state check failed"
|
||||
else:
|
||||
# (valu_issue = 0 & value_stall = 1) is not allowed
|
||||
assert not (
|
||||
snapshot["arb_state_issue_valu"] == 0
|
||||
and snapshot["arb_state_stall_valu"] == 1
|
||||
), "VALU arbiter state check failed"
|
||||
|
||||
# Matrix pipe checks
|
||||
# matrix_issue = 0 & matrix_stall = 1 is not allowed
|
||||
assert not (
|
||||
snapshot["arb_state_issue_matrix"] == 0
|
||||
and snapshot["arb_state_stall_matrix"] == 1
|
||||
), "Matrix arbiter state check failed"
|
||||
|
||||
# scalar pipe checks
|
||||
# scalar_issue = 0 & scalar_stall = 1 is not allowed
|
||||
assert not (
|
||||
snapshot["arb_state_issue_scalar"] == 0
|
||||
and snapshot["arb_state_stall_scalar"] == 1
|
||||
), "Scalar arbiter state check failed"
|
||||
|
||||
# texture pipe checks
|
||||
# tex_issue = 0 & tex_stall = 1 is not allowed
|
||||
assert not (
|
||||
snapshot["arb_state_issue_vmem_tex"] == 0
|
||||
and snapshot["arb_state_stall_vmem_tex"] == 1
|
||||
), "Texture arbiter state check failed"
|
||||
|
||||
# LDS pipe checks
|
||||
# lds_issue = 0 & lds_stall = 1 is not allowed
|
||||
assert not (
|
||||
snapshot["arb_state_issue_lds"] == 0 and snapshot["arb_state_stall_lds"] == 1
|
||||
), "LDS arbiter state check failed"
|
||||
|
||||
# flat pipe checks
|
||||
# flat_issue = 0 & flat_stall = 1 is not allowed
|
||||
assert not (
|
||||
snapshot["arb_state_issue_flat"] == 0 and snapshot["arb_state_stall_flat"] == 1
|
||||
), "Flat arbiter state check failed"
|
||||
|
||||
# misc pipe checks
|
||||
# TODO: verify this
|
||||
# According to Joe's slides, the misc_stall cannot be 0.
|
||||
# However, the condition representing this case fails for `transpose` application
|
||||
# assert((samples['Arbiter_State_Stall_Misc'] == 0).all())
|
||||
# Instead, I had to replace is with the condition belowe
|
||||
# misc_issue = 0 & misc_stall = 1 is not allowed
|
||||
assert not (
|
||||
snapshot["arb_state_issue_misc"] == 0 and snapshot["arb_state_stall_misc"] == 1
|
||||
), "Misc arbiter state check failed"
|
||||
|
||||
# export pipe checks
|
||||
# We assume same conditions for Export pipe as for Misc (Joe's original),
|
||||
# so we should TODO: verify
|
||||
# exp_issue can take both 1 and 0, so no need to check it
|
||||
# exp_stall must be 0
|
||||
assert snapshot["arb_state_stall_exp"] == 0, "Export arbiter state check failed"
|
||||
|
||||
# lds_direct pipe checks
|
||||
# This pipe doesn't exist on GFX9 so both issue and stall must be 0
|
||||
assert (
|
||||
snapshot["arb_state_issue_lds_direct"] == 0
|
||||
), "LDS Direct arbiter state check failed"
|
||||
assert (
|
||||
snapshot["arb_state_stall_lds_direct"] == 0
|
||||
), "LDS Direct arbiter state check failed"
|
||||
|
||||
# brmsg pipe doesn't exist on GFX9 so both issue and stall must be 0
|
||||
assert snapshot["arb_state_issue_brmsg"] == 0, "BRMSG arbiter state check failed"
|
||||
assert snapshot["arb_state_stall_brmsg"] == 0, "BRMSG arbiter state check failed"
|
||||
@@ -0,0 +1,160 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_valu_instructions(sample_records):
|
||||
allowed_stall_reasons = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN",
|
||||
]
|
||||
)
|
||||
for record in sample_records:
|
||||
assert record["inst"].startswith("v_"), "VALU instruction must start with 'v_'"
|
||||
|
||||
snapshot = record["snapshot"]
|
||||
if record["wave_issued"] == 1:
|
||||
# wave issued a VALU instruction
|
||||
assert record["inst_type"] == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_VALU"
|
||||
assert snapshot["arb_state_issue_valu"] == 1
|
||||
assert snapshot["arb_state_stall_valu"] == 0
|
||||
else:
|
||||
# wave did not issue a VALU instruction
|
||||
# inst_type is not relevant
|
||||
stall_reason = snapshot["stall_reason"]
|
||||
assert (
|
||||
stall_reason in allowed_stall_reasons
|
||||
), "Invalid stall reason for VALU instruction"
|
||||
|
||||
if (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
):
|
||||
assert snapshot["arb_state_issue_valu"] == 1
|
||||
# Expectation would be that the `arb_state_stall_valu` is 1, but in some examples,
|
||||
# I've observed different behavior.
|
||||
|
||||
if (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
):
|
||||
assert (
|
||||
snapshot["arb_state_issue_valu"] == 1
|
||||
or snapshot["arb_state_stall_matrix"] == 1
|
||||
), "VALU or Matrix instruction should be issued"
|
||||
|
||||
|
||||
def validate_flat_instructions(sample_records):
|
||||
allowed_stall_reasons = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY",
|
||||
]
|
||||
)
|
||||
for record in sample_records:
|
||||
assert record["inst"].startswith("flat_") or record["inst"].startswith(
|
||||
"global_"
|
||||
), "Invalid name of FLAT instruction"
|
||||
|
||||
snapshot = record["snapshot"]
|
||||
if record["wave_issued"] == 1:
|
||||
# wave issued a flat memory instruction
|
||||
assert (
|
||||
record["inst_type"] == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_FLAT"
|
||||
), "Invalid instruction type for FLAT instruction"
|
||||
assert snapshot["arb_state_issue_flat"] == 1, "Arbiter issued flat"
|
||||
assert (
|
||||
snapshot["arb_state_stall_flat"] == 0
|
||||
), "Arbiter should not stalled flat"
|
||||
|
||||
# TODO: add checks when flat stalls LDS, and vice versa
|
||||
# If global_ inst, check ISSUE_FLAT=1, STALL_FLAT=0, ISSUE_LDS=1 -> STALL_LDS = 1
|
||||
else:
|
||||
# wave did not issue a flat instruction
|
||||
# inst_type is not relevant
|
||||
stall_reason = snapshot["stall_reason"]
|
||||
assert (
|
||||
stall_reason in allowed_stall_reasons
|
||||
), "Invalid stall reason for flat instruction"
|
||||
|
||||
if (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
):
|
||||
assert snapshot["arb_state_issue_flat"] == 1, "Arbiter issued flat"
|
||||
assert snapshot["arb_state_stall_flat"] == 1, "EX stalled flat"
|
||||
|
||||
# In case of flat instructions, ARBITER_NOT_WIN might mean that
|
||||
# the FLAT/VMEM pipe was idle, so the flat instruction is issued to the arbiter
|
||||
# to wake up the clock in FLAT/VMEM, but cannot be issued to the execution pipeline.
|
||||
# Afterwards, the same instruction is reissued to the arbiter that sends it to the execution pipeline.
|
||||
# That's why `Arbiter_State_Issue_Flat` is not always true as in some other cases.
|
||||
|
||||
|
||||
def validate_lds_instructions(sample_records):
|
||||
allowed_stall_reasons = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY",
|
||||
]
|
||||
)
|
||||
for record in sample_records:
|
||||
assert record["inst"].startswith("ds_"), "Invalid name of LDS instruction"
|
||||
|
||||
snapshot = record["snapshot"]
|
||||
if record["wave_issued"] == 1:
|
||||
# wave issued an LDS memory instruction
|
||||
assert (
|
||||
record["inst_type"] == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_LDS"
|
||||
), "Invalid instruction type for LDS instruction"
|
||||
assert snapshot["arb_state_issue_lds"] == 1, "Arbiter issued lds"
|
||||
assert snapshot["arb_state_stall_lds"] == 0, "EX should not stalled lds"
|
||||
|
||||
# TODO: add checks when LDS stalls flat, and vice versa
|
||||
# ISSUE_LDS=1, STALL_LDS=0, ISSUE_FLAT=1 -> STALL_FLAT = 1
|
||||
else:
|
||||
# wave did not issue an LDS instruction
|
||||
# inst_type is not relevant
|
||||
stall_reason = snapshot["stall_reason"]
|
||||
assert (
|
||||
stall_reason in allowed_stall_reasons
|
||||
), "Invalid stall reason for LDS instruction"
|
||||
|
||||
if (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
):
|
||||
assert snapshot["arb_state_issue_lds"] == 1, "Arbiter issued flat"
|
||||
assert snapshot["arb_state_stall_lds"] == 1, "EX stalled flat"
|
||||
elif (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
):
|
||||
assert snapshot["arb_state_issue_lds"] == 1, "Arbiter issued flat"
|
||||
@@ -0,0 +1,222 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def validate_internal_instructions(sample_records):
|
||||
allowed_stall_reasons = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_INTERNAL_INSTRUCTION",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
]
|
||||
)
|
||||
for record in sample_records:
|
||||
assert record["inst"].startswith("s_nop"), "New internal instruction observed"
|
||||
assert (
|
||||
record["wave_issued"] == 0
|
||||
), "Internal instruction should not be issued to EX"
|
||||
assert (
|
||||
record["snapshot"]["stall_reason"] in allowed_stall_reasons
|
||||
), "Invalid stall reason for internal instruction"
|
||||
|
||||
|
||||
def validate_waitcnt(sample_records):
|
||||
allowed_stall_reasons = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_WAITCNT",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
]
|
||||
)
|
||||
for record in sample_records:
|
||||
assert record["inst"].startswith("s_waitcnt"), "Waitcnt must start with s_waitcn"
|
||||
assert record["wave_issued"] == 0, "Waitcnt should not be issued to EX"
|
||||
assert (
|
||||
record["snapshot"]["stall_reason"] in allowed_stall_reasons
|
||||
), "Invalid stall reason for waitcnt"
|
||||
|
||||
|
||||
def validate_branch_instructions(sample_records):
|
||||
allowed_stall_reasons = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL",
|
||||
]
|
||||
)
|
||||
allowed_stall_reasons_uncoditional_branches = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN",
|
||||
]
|
||||
)
|
||||
for record in sample_records:
|
||||
inst = record["inst"]
|
||||
inst_type = record["inst_type"]
|
||||
snapshot = record["snapshot"]
|
||||
stall_reason = snapshot["stall_reason"]
|
||||
assert inst.startswith("s_cbranch") or inst.startswith(
|
||||
"s_branch"
|
||||
), "Branch must start with s_cbranch or s_branch"
|
||||
|
||||
if record["wave_issued"] == 1:
|
||||
if inst.startswith("s_branch"):
|
||||
# Uncoditional issued branch can only be branch taken
|
||||
assert (
|
||||
inst_type == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_TAKEN"
|
||||
), "Unconditional branch must be taken"
|
||||
else:
|
||||
# Verifying issued branch instructions
|
||||
assert (
|
||||
inst_type == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_TAKEN"
|
||||
or inst_type
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_NOT_TAKEN"
|
||||
), "Invalid branch type for conditional branch instruction"
|
||||
|
||||
assert (
|
||||
snapshot["arb_state_issue_misc"] == 1
|
||||
and snapshot["arb_state_stall_misc"] == 0
|
||||
), "Invalid arb state for issued branch instruction"
|
||||
|
||||
else:
|
||||
# verifying not issued branch instructions
|
||||
assert (
|
||||
stall_reason in allowed_stall_reasons
|
||||
), "Invalid stall reason for branch instruction"
|
||||
|
||||
if (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
):
|
||||
assert (
|
||||
snapshot["arb_state_issue_misc"] == 1
|
||||
), "Arbiter must have issued MISC instruction"
|
||||
|
||||
elif (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
):
|
||||
assert (
|
||||
snapshot["arb_state_issue_misc"] == 1
|
||||
), "Arbiter must have issued MISC instruction"
|
||||
|
||||
assert (
|
||||
snapshot["arb_state_stall_misc"] == 1
|
||||
), "Arbiter must have stalled MISC instruction"
|
||||
|
||||
# more specific checks for unconditional branches
|
||||
if inst.startswith("s_branch"):
|
||||
assert (
|
||||
stall_reason in allowed_stall_reasons_uncoditional_branches
|
||||
), "Invalid stall reason for unconditional branch instruction"
|
||||
|
||||
|
||||
def validate_scalar_instructions(sample_records):
|
||||
allowed_stall_reasons = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL",
|
||||
]
|
||||
)
|
||||
|
||||
for record in sample_records:
|
||||
snapshot = record["snapshot"]
|
||||
if record["wave_issued"] == 1:
|
||||
assert (
|
||||
record["inst_type"] == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_SCALAR"
|
||||
), "Invalid scalar instruction type"
|
||||
assert (
|
||||
snapshot["arb_state_issue_scalar"] == 1
|
||||
), "Arbiter must have issued scalar instruction"
|
||||
assert (
|
||||
snapshot["arb_state_stall_scalar"] == 0
|
||||
), "Arbiter must have stalled scalar instruction"
|
||||
else:
|
||||
stall_reason = snapshot["stall_reason"]
|
||||
assert (
|
||||
stall_reason in allowed_stall_reasons
|
||||
), "Invalid stall reason for scalar instruction"
|
||||
|
||||
if (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
):
|
||||
assert (
|
||||
snapshot["arb_state_issue_scalar"] == 1
|
||||
), "Arbiter must have issued scalar instruction"
|
||||
|
||||
elif (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL"
|
||||
):
|
||||
assert (
|
||||
snapshot["arb_state_issue_scalar"] == 1
|
||||
), "Arbiter must have issued scalar instruction"
|
||||
|
||||
assert (
|
||||
snapshot["arb_state_stall_scalar"] == 1
|
||||
), "Arbiter must have stalled scalar instruction"
|
||||
|
||||
|
||||
def validate_barrier_instructions(sample_records):
|
||||
allowed_stall_reasons = set(
|
||||
[
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN",
|
||||
"ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_BARRIER_WAIT",
|
||||
]
|
||||
)
|
||||
for record in sample_records:
|
||||
assert record["inst"].startswith(
|
||||
"s_barrier"
|
||||
), "Barrier instruction must start with s_barrier"
|
||||
snapshot = record["snapshot"]
|
||||
if record["wave_issued"] == 1:
|
||||
assert (
|
||||
record["inst_type"] == "ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BARRIER"
|
||||
), "Invalid barrier instruction type"
|
||||
assert (
|
||||
snapshot["arb_state_issue_misc"] == 1
|
||||
), "Arbiter must have issued barrier instruction"
|
||||
assert (
|
||||
snapshot["arb_state_stall_misc"] == 0
|
||||
), "Arbiter must have stalled barrier instruction"
|
||||
else:
|
||||
stall_reason = snapshot["stall_reason"]
|
||||
assert (
|
||||
stall_reason in allowed_stall_reasons
|
||||
), "Invalid stall reason for barrier instruction"
|
||||
|
||||
if (
|
||||
stall_reason
|
||||
== "ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN"
|
||||
):
|
||||
assert (
|
||||
snapshot["arb_state_issue_misc"] == 1
|
||||
), "Arbiter must have issued misc instruction"
|
||||
|
||||
|
||||
# TODO: cover other types of instructions
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
set(PACKAGE_OUTPUT_DIR
|
||||
${ROCPROFILER_SDK_TESTS_BINARY_DIR}/pytest-packages/rocprofiler_sdk/pc_sampling/transpose_multiple_agents
|
||||
)
|
||||
|
||||
set(PC_SAMPLING_PYTHON_SOURCES __init__.py csv.py)
|
||||
|
||||
foreach(_FILE ${PC_SAMPLING_PYTHON_SOURCES})
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/${_FILE} ${PACKAGE_OUTPUT_DIR}/${_FILE}
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
@@ -0,0 +1,23 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
from __future__ import absolute_import
|
||||
@@ -0,0 +1,93 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import itertools
|
||||
import sys
|
||||
import pytest
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def validate_all_agents_are_sampled(
|
||||
input_samples_csv: pd.DataFrame,
|
||||
input_kernel_trace_csv: pd.DataFrame,
|
||||
input_agent_info_csv: pd.DataFrame,
|
||||
):
|
||||
transpose_kernel_source_line_start = 137
|
||||
transpose_kernel_source_line_end = 145
|
||||
|
||||
mi2xx_mi3xx_agents_df = input_agent_info_csv[
|
||||
input_agent_info_csv["Name"].apply(
|
||||
lambda name: name == "gfx90a"
|
||||
or name.startswith("gfx94")
|
||||
or name.startswith("gfx95")
|
||||
)
|
||||
]
|
||||
|
||||
# Extract samples that originates from know code object it
|
||||
samples_df = input_samples_csv[input_samples_csv["Dispatch_Id"] != 0].copy()
|
||||
|
||||
# Determine the agent on which sample was generated
|
||||
# Note: Agent_Id is in the following format e.g., "Agent 3",
|
||||
# that's why we need a log for extracting integer value of the id.
|
||||
# Determine the agent on which sample was generated
|
||||
samples_df["Agent_Id"] = (
|
||||
samples_df["Dispatch_Id"]
|
||||
.map(
|
||||
input_kernel_trace_csv.set_index("Dispatch_Id")["Agent_Id"]
|
||||
.str.split(" ")
|
||||
.str[1]
|
||||
)
|
||||
.astype(np.uint64)
|
||||
)
|
||||
sampled_agents = samples_df["Agent_Id"].unique()
|
||||
sampled_agents_num = len(sampled_agents)
|
||||
# all agents must be sampled
|
||||
assert sampled_agents_num == len(mi2xx_mi3xx_agents_df)
|
||||
|
||||
# separate samples per agents
|
||||
grouped_samples_per_agent = samples_df.groupby("Agent_Id")
|
||||
for agent_id, agent_samples_df in grouped_samples_per_agent:
|
||||
sampled_dispatches = agent_samples_df["Dispatch_Id"].unique()
|
||||
# at least 1 sampled dispatch per agent
|
||||
assert len(sampled_dispatches) >= 1
|
||||
|
||||
# extract decoded samples that are mapped to the transpose.cpp file
|
||||
transpose_samples_df = samples_df[
|
||||
samples_df["Instruction_Comment"].apply(
|
||||
lambda comment: "transpose-all-agents.cpp" in comment
|
||||
)
|
||||
].copy()
|
||||
# determine the line number for each sample
|
||||
transpose_samples_df["Source_Line_Num"] = transpose_samples_df[
|
||||
"Instruction_Comment"
|
||||
].apply(lambda source_line: int(source_line.split(":")[-1]))
|
||||
# assert that line belongs to a kernel range
|
||||
assert (
|
||||
(transpose_samples_df["Source_Line_Num"] >= transpose_kernel_source_line_start)
|
||||
& (transpose_samples_df["Source_Line_Num"] <= transpose_kernel_source_line_end)
|
||||
).all()
|
||||
Reference in New Issue
Block a user