Remove rocprofv1/v2 in favour of rocprofiler-sdk (#673)
* Set default rocprof interface as rocprofiler-sdk * Remove rocrprofv1 and rocprofv2 interfaces * Remove deprecation notice for rocprof v1/v2/v3 interfaces * Make rocprofiler-sdk the default interface and make rocprofv3 interface opt-in using ROCPROF=rocprofv3 * Add deprecation notice for rocprofv3
This commit is contained in:
committed by
GitHub
orang tua
7df02745eb
melakukan
bd7a1de879
@@ -108,7 +108,6 @@ ALL_CSVS_MI200 = sorted([
|
||||
"pmc_perf_4.csv",
|
||||
"pmc_perf_5.csv",
|
||||
"sysinfo.csv",
|
||||
"timestamps.csv",
|
||||
])
|
||||
ALL_CSVS_MI300 = sorted([
|
||||
"SQC_DCACHE_INFLIGHT_LEVEL.csv",
|
||||
@@ -126,7 +125,6 @@ ALL_CSVS_MI300 = sorted([
|
||||
"pmc_perf_4.csv",
|
||||
"pmc_perf_5.csv",
|
||||
"sysinfo.csv",
|
||||
"timestamps.csv",
|
||||
])
|
||||
ALL_CSVS_MI350 = sorted([
|
||||
"SQC_DCACHE_INFLIGHT_LEVEL.csv",
|
||||
@@ -155,13 +153,13 @@ ALL_CSVS_MI350 = sorted([
|
||||
|
||||
ROOF_ONLY_FILES = sorted([
|
||||
"empirRoof_gpu-0_FP32.pdf",
|
||||
"kernelName_legend.pdf",
|
||||
"pmc_perf.csv",
|
||||
"pmc_perf_0.csv",
|
||||
"pmc_perf_1.csv",
|
||||
"pmc_perf_2.csv",
|
||||
"roofline.csv",
|
||||
"sysinfo.csv",
|
||||
"timestamps.csv",
|
||||
])
|
||||
|
||||
PC_SAMPLING_HOST_TRAP_FILES = sorted([
|
||||
@@ -364,18 +362,7 @@ def gpu_soc():
|
||||
|
||||
soc = gpu_soc()
|
||||
|
||||
os.environ["ROCPROF"] = "rocprofv3"
|
||||
|
||||
|
||||
def using_v3():
|
||||
return "ROCPROF" not in os.environ.keys() or (
|
||||
"ROCPROF" in os.environ.keys()
|
||||
and (
|
||||
os.environ["ROCPROF"].endswith("rocprofv3")
|
||||
or os.environ["ROCPROF"] == "rocprofiler-sdk"
|
||||
)
|
||||
)
|
||||
|
||||
os.environ["ROCPROF"] = "rocprofiler-sdk"
|
||||
|
||||
Baseline_dir = str(Path("tests/workloads/vcopy/" + soc).resolve())
|
||||
|
||||
@@ -568,19 +555,11 @@ def test_path(binary_handler_profile_rocprof_compute):
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
elif soc == "MI200":
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI200 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI200
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI200
|
||||
elif "MI300" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI300 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI300
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI300
|
||||
elif "MI350" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(ALL_CSVS_MI350)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI350
|
||||
else:
|
||||
print(f"This test is not supported for {soc}")
|
||||
assert 0
|
||||
@@ -628,15 +607,7 @@ def test_roof_kernel_names(binary_handler_profile_rocprof_compute):
|
||||
assert returncode == 0
|
||||
file_dict = test_utils.check_csv_files(workload_dir, 1, num_kernels)
|
||||
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
else:
|
||||
expected_files = (
|
||||
[f for f in ROOF_ONLY_FILES if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ROOF_ONLY_FILES
|
||||
) + ["kernelName_legend.pdf"]
|
||||
assert sorted(list(file_dict.keys())) == sorted(expected_files)
|
||||
assert sorted(list(file_dict.keys())) == ROOF_ONLY_FILES
|
||||
|
||||
validate(
|
||||
inspect.stack()[0][3],
|
||||
@@ -678,12 +649,7 @@ def test_roof_multiple_data_types(binary_handler_profile_rocprof_compute):
|
||||
assert os.path.exists(f"{workload_dir}/pmc_perf.csv")
|
||||
|
||||
file_dict = test_utils.check_csv_files(workload_dir, 1, num_kernels)
|
||||
expected_files = (
|
||||
[f for f in ROOF_ONLY_FILES if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ROOF_ONLY_FILES
|
||||
) + ["kernelName_legend.pdf"]
|
||||
assert sorted(list(file_dict.keys())) == sorted(expected_files)
|
||||
assert sorted(list(file_dict.keys())) == ROOF_ONLY_FILES
|
||||
else:
|
||||
pass
|
||||
finally:
|
||||
@@ -1200,19 +1166,11 @@ def test_device_filter(binary_handler_profile_rocprof_compute):
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
elif soc == "MI200":
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI200 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI200
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI200
|
||||
elif "MI300" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI300 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI300
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI300
|
||||
elif "MI350" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(ALL_CSVS_MI350)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI350
|
||||
else:
|
||||
print(f"Testing isn't supported yet for {soc}")
|
||||
assert 0
|
||||
@@ -1238,19 +1196,11 @@ def test_kernel(binary_handler_profile_rocprof_compute):
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
elif soc == "MI200":
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI200 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI200
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI200
|
||||
elif "MI300" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI300 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI300
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI300
|
||||
elif "MI350" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(ALL_CSVS_MI350)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI350
|
||||
else:
|
||||
print(f"Testing isn't supported yet for {soc}")
|
||||
assert 0
|
||||
@@ -1274,19 +1224,11 @@ def test_dispatch_0(binary_handler_profile_rocprof_compute):
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
elif soc == "MI200":
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI200 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI200
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI200
|
||||
elif "MI300" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI300 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI300
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI300
|
||||
elif "MI350" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(ALL_CSVS_MI350)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI350
|
||||
else:
|
||||
print(f"Testing isn't supported yet for {soc}")
|
||||
assert 0
|
||||
@@ -1314,19 +1256,11 @@ def test_dispatch_0_1(binary_handler_profile_rocprof_compute):
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
elif soc == "MI200":
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI200 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI200
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI200
|
||||
elif "MI300" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI300 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI300
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI300
|
||||
elif "MI350" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(ALL_CSVS_MI350)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI350
|
||||
else:
|
||||
print(f"Testing isn't supported yet for {soc}")
|
||||
assert 0
|
||||
@@ -1351,19 +1285,11 @@ def test_dispatch_2(binary_handler_profile_rocprof_compute):
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
elif soc == "MI200":
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI200 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI200
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI200
|
||||
elif "MI300" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI300 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI300
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI300
|
||||
elif "MI350" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(ALL_CSVS_MI350)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI350
|
||||
else:
|
||||
print(f"Testing isn't supported yet for {soc}")
|
||||
assert 0
|
||||
@@ -1391,19 +1317,11 @@ def test_join_type_grid(binary_handler_profile_rocprof_compute):
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
elif soc == "MI200":
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI200 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI200
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI200
|
||||
elif "MI300" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI300 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI300
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI300
|
||||
elif "MI350" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(ALL_CSVS_MI350)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI350
|
||||
else:
|
||||
print(f"Testing isn't supported yet for {soc}")
|
||||
assert 0
|
||||
@@ -1428,19 +1346,11 @@ def test_join_type_kernel(binary_handler_profile_rocprof_compute):
|
||||
if soc == "MI100":
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI100
|
||||
elif soc == "MI200":
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI200 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI200
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI200
|
||||
elif "MI300" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(
|
||||
[f for f in ALL_CSVS_MI300 if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ALL_CSVS_MI300
|
||||
)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI300
|
||||
elif "MI350" in soc:
|
||||
assert sorted(list(file_dict.keys())) == sorted(ALL_CSVS_MI350)
|
||||
assert sorted(list(file_dict.keys())) == ALL_CSVS_MI350
|
||||
else:
|
||||
print(f"Testing isn't supported yet for {soc}")
|
||||
assert 0
|
||||
@@ -1473,12 +1383,11 @@ def test_roof_sort_dispatches(binary_handler_profile_rocprof_compute):
|
||||
assert returncode == 0
|
||||
|
||||
file_dict = test_utils.check_csv_files(workload_dir, 1, num_kernels)
|
||||
assert (
|
||||
sorted(list(file_dict.keys()))
|
||||
== [f for f in ROOF_ONLY_FILES if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ROOF_ONLY_FILES
|
||||
)
|
||||
|
||||
expected_files = ROOF_ONLY_FILES.copy()
|
||||
expected_files.remove("kernelName_legend.pdf")
|
||||
expected_files = sorted(expected_files)
|
||||
assert sorted(list(file_dict.keys())) == expected_files
|
||||
|
||||
validate(
|
||||
inspect.stack()[0][3],
|
||||
@@ -1508,12 +1417,10 @@ def test_roof_sort_kernels(binary_handler_profile_rocprof_compute):
|
||||
assert returncode == 0
|
||||
file_dict = test_utils.check_csv_files(workload_dir, 1, num_kernels)
|
||||
|
||||
assert (
|
||||
sorted(list(file_dict.keys()))
|
||||
== [f for f in ROOF_ONLY_FILES if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ROOF_ONLY_FILES
|
||||
)
|
||||
expected_files = ROOF_ONLY_FILES.copy()
|
||||
expected_files.remove("kernelName_legend.pdf")
|
||||
expected_files = sorted(expected_files)
|
||||
assert sorted(list(file_dict.keys())) == expected_files
|
||||
|
||||
validate(
|
||||
inspect.stack()[0][3],
|
||||
@@ -1543,12 +1450,10 @@ def test_roof_mem_levels_vL1D(binary_handler_profile_rocprof_compute):
|
||||
assert returncode == 0
|
||||
file_dict = test_utils.check_csv_files(workload_dir, 1, num_kernels)
|
||||
|
||||
assert (
|
||||
sorted(list(file_dict.keys()))
|
||||
== [f for f in ROOF_ONLY_FILES if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ROOF_ONLY_FILES
|
||||
)
|
||||
expected_files = ROOF_ONLY_FILES.copy()
|
||||
expected_files.remove("kernelName_legend.pdf")
|
||||
expected_files = sorted(expected_files)
|
||||
assert sorted(list(file_dict.keys())) == expected_files
|
||||
|
||||
validate(
|
||||
inspect.stack()[0][3],
|
||||
@@ -1578,12 +1483,10 @@ def test_roof_mem_levels_LDS(binary_handler_profile_rocprof_compute):
|
||||
assert returncode == 0
|
||||
file_dict = test_utils.check_csv_files(workload_dir, 1, num_kernels)
|
||||
|
||||
assert (
|
||||
sorted(list(file_dict.keys()))
|
||||
== [f for f in ROOF_ONLY_FILES if f != "timestamps.csv"]
|
||||
if using_v3()
|
||||
else ROOF_ONLY_FILES
|
||||
)
|
||||
expected_files = ROOF_ONLY_FILES.copy()
|
||||
expected_files.remove("kernelName_legend.pdf")
|
||||
expected_files = sorted(expected_files)
|
||||
assert sorted(list(file_dict.keys())) == expected_files
|
||||
|
||||
validate(
|
||||
inspect.stack()[0][3],
|
||||
@@ -1873,10 +1776,6 @@ def test_pc_sampling_stochastic(binary_handler_profile_rocprof_compute):
|
||||
|
||||
@pytest.mark.live_attach_detach
|
||||
def test_live_attach_detach_block(binary_handler_profile_rocprof_compute):
|
||||
if not using_v3():
|
||||
assert True
|
||||
return
|
||||
|
||||
options = ["--block", "3.1.1", "4.1.1", "5.1.1"]
|
||||
workload_dir = test_utils.get_output_dir()
|
||||
process_workload = subprocess.Popen(config["app_hip_dynamic_shared"])
|
||||
@@ -1930,10 +1829,6 @@ def test_live_attach_detach_block(binary_handler_profile_rocprof_compute):
|
||||
def test_live_attach_detach_singlepath_launch_stats(
|
||||
binary_handler_profile_rocprof_compute,
|
||||
):
|
||||
if not using_v3():
|
||||
assert True
|
||||
return
|
||||
|
||||
options = ["--set", "launch_stats"]
|
||||
workload_dir = test_utils.get_output_dir()
|
||||
process_workload = subprocess.Popen(config["app_hip_dynamic_shared"])
|
||||
|
||||
@@ -384,7 +384,7 @@ def test_detect_rocprof_env_rocprof_not_found(monkeypatch):
|
||||
rocprofiler_sdk_library_path = "/fake/path"
|
||||
|
||||
# Set ROCPROF to 'rocprof'
|
||||
monkeypatch.setenv("ROCPROF", "rocprof")
|
||||
monkeypatch.setenv("ROCPROF", "rocprofv3")
|
||||
# shutil.which returns None for 'rocprof'
|
||||
monkeypatch.setattr("shutil.which", lambda cmd: None)
|
||||
# Track calls to console_warning and console_error
|
||||
@@ -403,7 +403,6 @@ def test_detect_rocprof_env_rocprof_not_found(monkeypatch):
|
||||
|
||||
with pytest.raises(RuntimeError, match="console_error called"):
|
||||
utils_mod.detect_rocprof(DummyArgs())
|
||||
assert any("Unable to resolve path to rocprofv3 binary" in w for w in warnings)
|
||||
assert any(
|
||||
"Please verify installation or set ROCPROF environment variable" in e
|
||||
for e in errors
|
||||
@@ -452,10 +451,7 @@ def test_detect_rocprof_env_not_set(monkeypatch):
|
||||
rocprofiler_sdk_library_path = "/fake/path"
|
||||
|
||||
monkeypatch.delenv("ROCPROF", raising=False)
|
||||
monkeypatch.setattr(
|
||||
"shutil.which", lambda cmd: "/usr/bin/rocprofv3" if cmd == "rocprofv3" else None
|
||||
)
|
||||
monkeypatch.setattr("pathlib.Path.resolve", lambda self: self)
|
||||
monkeypatch.setattr("pathlib.Path.exists", lambda _: True)
|
||||
logs = []
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.console_debug", lambda msg, *a, **k: logs.append(str(msg))
|
||||
@@ -463,10 +459,10 @@ def test_detect_rocprof_env_not_set(monkeypatch):
|
||||
import utils.utils as utils_mod
|
||||
|
||||
result = utils_mod.detect_rocprof(DummyArgs())
|
||||
assert result == "rocprofv3"
|
||||
assert result == "rocprofiler-sdk"
|
||||
assert any(
|
||||
"ROC Profiler: /usr/bin/rocprofv3" in log_entry
|
||||
or "rocprof_cmd is rocprofv3" in log_entry
|
||||
"rocprofiler_sdk_path is /fake/path" in log_entry
|
||||
or "rocprof_cmd is rocprofiler-sdk" in log_entry
|
||||
for log_entry in logs
|
||||
)
|
||||
|
||||
@@ -2379,9 +2375,9 @@ def test_parse_text_file_not_found():
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def test_run_prof_success_v2(tmp_path, monkeypatch):
|
||||
def test_run_prof_success_v3(tmp_path, monkeypatch):
|
||||
"""
|
||||
Test run_prof with rocprofv2 successful execution.
|
||||
Test run_prof with rocprofv3 successful execution.
|
||||
|
||||
Args:
|
||||
tmp_path (Path): Temporary directory for test files.
|
||||
@@ -2395,7 +2391,13 @@ def test_run_prof_success_v2(tmp_path, monkeypatch):
|
||||
workload_dir = str(tmp_path / "workload")
|
||||
os.makedirs(workload_dir + "/out/pmc_1", exist_ok=True)
|
||||
|
||||
csv_content = "Dispatch_ID,GPU_ID,Kernel_Name\n0,0,test_kernel"
|
||||
csv_content = (
|
||||
"Agent_Type,Node_Id,Wave_Front_Size,Correlation_Id,Dispatch_Id,Agent_Id,Queue_Id,Process_Id,Thread_Id,"
|
||||
"Grid_Size,Kernel_Id,Kernel_Name,Workgroup_Size,LDS_Block_Size,"
|
||||
"Scratch_Size,VGPR_Count,Accum_VGPR_Count,SGPR_Count,Start_Timestamp,"
|
||||
"End_Timestamp,Counter_Name,Counter_Value\n"
|
||||
"GPU,0,0,0,0,0,0,0,0,0,0,test_kernel,0,0,0,0,0,0,0,1,SQ_WAVES,100"
|
||||
)
|
||||
with open(workload_dir + "/out/pmc_1/results_0.csv", "w") as f:
|
||||
f.write(csv_content)
|
||||
|
||||
@@ -2408,12 +2410,10 @@ def test_run_prof_success_v2(tmp_path, monkeypatch):
|
||||
|
||||
mspec = MockSpec()
|
||||
|
||||
monkeypatch.setattr("utils.utils.rocprof_cmd", "rocprofv2")
|
||||
monkeypatch.setattr("utils.utils.rocprof_cmd", "rocprofv3")
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (True, "success")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.console_debug", lambda *a, **k: None)
|
||||
monkeypatch.setattr("utils.utils.console_log", lambda *a, **k: None)
|
||||
monkeypatch.setattr(
|
||||
@@ -2458,8 +2458,6 @@ def test_run_prof_success_v3_csv(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (True, "success")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: True)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.console_debug", lambda *a, **k: None)
|
||||
monkeypatch.setattr("utils.utils.console_log", lambda *a, **k: None)
|
||||
monkeypatch.setattr(
|
||||
@@ -2510,7 +2508,6 @@ def test_run_prof_success_rocprofiler_sdk(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (True, "success")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: True)
|
||||
monkeypatch.setattr("utils.utils.parse_text", lambda f: ["SQ_WAVES"])
|
||||
monkeypatch.setattr("utils.utils.process_rocprofv3_output", lambda *a, **k: [])
|
||||
monkeypatch.setattr("utils.utils.console_debug", lambda *a, **k: None)
|
||||
@@ -2554,8 +2551,6 @@ def test_run_prof_with_yaml_config(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (True, "success")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: True)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.process_rocprofv3_output", lambda *a, **k: [])
|
||||
monkeypatch.setattr("utils.utils.console_debug", lambda *a, **k: None)
|
||||
monkeypatch.setattr("utils.utils.console_log", lambda *a, **k: None)
|
||||
@@ -2597,8 +2592,6 @@ def test_run_prof_failure_subprocess(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (False, "error output")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: True)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.console_debug", lambda *a, **k: None)
|
||||
monkeypatch.setattr("utils.utils.console_log", lambda *a, **k: None)
|
||||
|
||||
@@ -2651,8 +2644,6 @@ def test_run_prof_mi300_environment_setup(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", mock_capture_subprocess_output
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: True)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.process_rocprofv3_output", lambda *a, **k: [])
|
||||
monkeypatch.setattr("utils.utils.console_debug", lambda *a, **k: None)
|
||||
monkeypatch.setattr("utils.utils.console_log", lambda *a, **k: None)
|
||||
@@ -2692,7 +2683,13 @@ def test_run_prof_timestamps_special_case(tmp_path, monkeypatch):
|
||||
|
||||
mspec = MockSpec()
|
||||
|
||||
csv_content = "Dispatch_ID,Start_Timestamp,End_Timestamp\n0,100,200"
|
||||
csv_content = (
|
||||
"Agent_Type,Node_Id,Wave_Front_Size,Correlation_Id,Dispatch_Id,Agent_Id,Queue_Id,Process_Id,Thread_Id,"
|
||||
"Grid_Size,Kernel_Id,Kernel_Name,Workgroup_Size,LDS_Block_Size,"
|
||||
"Scratch_Size,VGPR_Count,Accum_VGPR_Count,SGPR_Count,Start_Timestamp,"
|
||||
"End_Timestamp,Counter_Name,Counter_Value\n"
|
||||
"GPU,0,0,0,0,0,0,0,0,0,0,test_kernel,0,0,0,0,0,0,0,1,SQ_WAVES,100"
|
||||
)
|
||||
with open(workload_dir + "/kernel_trace.csv", "w") as f:
|
||||
f.write(csv_content)
|
||||
|
||||
@@ -2702,8 +2699,6 @@ def test_run_prof_timestamps_special_case(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (True, "success")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: True)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.process_rocprofv3_output", lambda *a, **k: csv_files
|
||||
)
|
||||
@@ -2752,8 +2747,6 @@ def test_run_prof_no_results_files(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (True, "success")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr("glob.glob", lambda pattern: []) # No files found
|
||||
monkeypatch.setattr("utils.utils.console_debug", lambda *a, **k: None)
|
||||
monkeypatch.setattr("utils.utils.console_log", lambda *a, **k: None)
|
||||
@@ -2790,46 +2783,31 @@ def test_run_prof_header_standardization(tmp_path, monkeypatch):
|
||||
mspec = MockSpec()
|
||||
|
||||
csv_content = (
|
||||
"KernelName,Index,grd,gpu-id,BeginNs,EndNs\ntest_kernel,0,64,0,100,200"
|
||||
"Agent_Type,Node_Id,Wave_Front_Size,Correlation_Id,Dispatch_Id,Agent_Id,Queue_Id,Process_Id,Thread_Id,"
|
||||
"Grid_Size,Kernel_Id,Kernel_Name,Workgroup_Size,LDS_Block_Size,"
|
||||
"Scratch_Size,VGPR_Count,Accum_VGPR_Count,SGPR_Count,Start_Timestamp,"
|
||||
"End_Timestamp,Counter_Name,Counter_Value\n"
|
||||
"GPU,0,0,0,0,0,0,0,0,0,0,test_kernel,0,0,0,0,0,0,0,1,SQ_WAVES,100"
|
||||
)
|
||||
with open(workload_dir + "/out/pmc_1/results_test.csv", "w") as f:
|
||||
f.write(csv_content)
|
||||
|
||||
old_headers_df = pd.DataFrame({
|
||||
"KernelName": ["test_kernel"],
|
||||
"Index": [0],
|
||||
"grd": [64],
|
||||
"gpu-id": [0],
|
||||
"BeginNs": [100],
|
||||
"EndNs": [200],
|
||||
})
|
||||
|
||||
monkeypatch.setattr("utils.utils.rocprof_cmd", "rocprofv2")
|
||||
monkeypatch.setattr("utils.utils.rocprof_cmd", "rocprofv3")
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (True, "success")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr(
|
||||
"glob.glob", lambda pattern: [workload_dir + "/out/pmc_1/results_test.csv"]
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.console_debug", lambda *a, **k: None)
|
||||
monkeypatch.setattr("utils.utils.console_log", lambda *a, **k: None)
|
||||
|
||||
read_calls = []
|
||||
|
||||
def mock_read_csv(path, **kwargs):
|
||||
read_calls.append(path)
|
||||
return old_headers_df.copy()
|
||||
|
||||
write_calls = []
|
||||
|
||||
def mock_to_csv(self, path, **kwargs):
|
||||
write_calls.append((path, self.columns.tolist()))
|
||||
|
||||
monkeypatch.setattr("pandas.read_csv", mock_read_csv)
|
||||
monkeypatch.setattr("pandas.DataFrame.to_csv", mock_to_csv)
|
||||
monkeypatch.setattr("pandas.concat", lambda dfs, **k: old_headers_df.copy())
|
||||
|
||||
import utils.utils as utils_mod
|
||||
|
||||
@@ -2837,9 +2815,8 @@ def test_run_prof_header_standardization(tmp_path, monkeypatch):
|
||||
|
||||
final_headers = write_calls[-1][1] if write_calls else []
|
||||
assert "Kernel_Name" in final_headers
|
||||
assert "Dispatch_ID" in final_headers
|
||||
assert "Dispatch_Id" in final_headers
|
||||
assert "Grid_Size" in final_headers
|
||||
assert "GPU_ID" in final_headers
|
||||
assert "Start_Timestamp" in final_headers
|
||||
assert "End_Timestamp" in final_headers
|
||||
|
||||
@@ -2868,28 +2845,12 @@ def test_run_prof_tcc_flattening_mi300(tmp_path, monkeypatch):
|
||||
|
||||
mspec = MockSpec()
|
||||
|
||||
flatten_called = False
|
||||
|
||||
def mock_flatten_tcc_info_across_xcds(file, xcds, l2_banks):
|
||||
nonlocal flatten_called
|
||||
flatten_called = True
|
||||
return pd.DataFrame({
|
||||
"Dispatch_ID": [0],
|
||||
"TCC_HIT[0]": [100],
|
||||
"TCC_HIT[16]": [200],
|
||||
})
|
||||
|
||||
# Mock functions
|
||||
monkeypatch.setattr("utils.utils.rocprof_cmd", "rocprofv2")
|
||||
monkeypatch.setattr("utils.utils.rocprof_cmd", "rocprofv3")
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.capture_subprocess_output", lambda *a, **k: (True, "success")
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.using_v1", lambda: False)
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.flatten_tcc_info_across_xcds", mock_flatten_tcc_info_across_xcds
|
||||
)
|
||||
monkeypatch.setattr("utils.utils.mi_gpu_specs.get_num_xcds", lambda *a: 2)
|
||||
monkeypatch.setattr("utils.mi_gpu_spec.mi_gpu_specs.get_num_xcds", lambda *a: 2)
|
||||
monkeypatch.setattr(
|
||||
"glob.glob", lambda pattern: [workload_dir + "/results_test.csv"]
|
||||
)
|
||||
@@ -2907,8 +2868,6 @@ def test_run_prof_tcc_flattening_mi300(tmp_path, monkeypatch):
|
||||
# Execute function
|
||||
utils_mod.run_prof(str(fname), ["--arg"], workload_dir, mspec, logging.INFO, "csv")
|
||||
|
||||
assert flatten_called
|
||||
|
||||
|
||||
import utils.utils as utils_mod # noqa
|
||||
|
||||
@@ -2934,7 +2893,6 @@ def test_run_prof_sdk_creates_new_env_copy(tmp_path, monkeypatch):
|
||||
workload_dir_str = str(tmp_path)
|
||||
|
||||
monkeypatch.setattr("utils.utils.rocprof_cmd", "rocprofiler-sdk")
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: False)
|
||||
monkeypatch.setattr("utils.utils.process_rocprofv3_output", lambda *a, **k: [])
|
||||
|
||||
capture_subprocess_called_with_env = None
|
||||
@@ -2957,10 +2915,12 @@ def test_run_prof_sdk_creates_new_env_copy(tmp_path, monkeypatch):
|
||||
"utils.utils.parse_text", lambda *a, **k: ["COUNTER1", "COUNTER2"]
|
||||
)
|
||||
|
||||
mock_fname_path_obj = mock.Mock(spec=Path)
|
||||
mock_fname_path_obj = mock.MagicMock(spec=Path)
|
||||
mock_fname_path_obj.stem = "counters"
|
||||
mock_fname_path_obj.name = "counters.txt"
|
||||
mock_fname_path_obj.with_suffix.return_value.exists.return_value = False
|
||||
mock_fname_path_obj.__truediv__.return_value = mock.Mock(spec=Path)
|
||||
|
||||
mock_out_path_obj = mock.Mock(spec=Path)
|
||||
mock_out_path_obj.exists.return_value = False
|
||||
|
||||
@@ -2999,6 +2959,7 @@ def test_run_prof_sdk_creates_new_env_copy(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr("shutil.copyfile", lambda *a, **k: None)
|
||||
monkeypatch.setattr("shutil.rmtree", lambda *a, **k: None)
|
||||
monkeypatch.setattr("utils.utils.console_warning", lambda *a, **k: None)
|
||||
monkeypatch.setattr("builtins.open", lambda *a, **k: io.StringIO(""))
|
||||
|
||||
utils_mod.run_prof(
|
||||
fname_str,
|
||||
@@ -3030,7 +2991,7 @@ def test_run_prof_v3_sdk_and_cli_calls_trace_processing(tmp_path, monkeypatch):
|
||||
Line 5 (CLI): elif "--hip-trace" in options:
|
||||
process_hip_trace_output(...)
|
||||
"""
|
||||
fname_str = str(tmp_path / "counters.txt")
|
||||
fname_str = str(tmp_path) + "/counters.txt"
|
||||
Path(fname_str).touch()
|
||||
fbase_str = "counters"
|
||||
workload_dir_str = str(tmp_path)
|
||||
@@ -3041,7 +3002,7 @@ def test_run_prof_v3_sdk_and_cli_calls_trace_processing(tmp_path, monkeypatch):
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"utils.utils.process_rocprofv3_output",
|
||||
lambda *a, **k: [str(tmp_path / "results1.csv")],
|
||||
lambda *a, **k: [str(tmp_path) + "/results1.csv"],
|
||||
)
|
||||
|
||||
hip_trace_called_with = None
|
||||
@@ -3096,15 +3057,13 @@ def test_run_prof_v3_sdk_and_cli_calls_trace_processing(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr("shutil.copyfile", lambda *a, **k: None)
|
||||
monkeypatch.setattr("shutil.rmtree", lambda *a, **k: None)
|
||||
monkeypatch.setattr("builtins.open", lambda *a, **k: io.StringIO(""))
|
||||
monkeypatch.setattr("utils.utils.flatten_tcc_info_across_xcds", lambda df, *a: df)
|
||||
monkeypatch.setattr("utils.utils.mi_gpu_specs.get_num_xcds", lambda *a: 1)
|
||||
monkeypatch.setattr("utils.mi_gpu_spec.mi_gpu_specs.get_num_xcds", lambda *a: 1)
|
||||
|
||||
mspec = MockMSpec()
|
||||
loglevel = logging.INFO
|
||||
format_rocprof_output = True
|
||||
|
||||
monkeypatch.setattr("utils.utils.rocprof_cmd", "rocprofiler-sdk")
|
||||
monkeypatch.setattr("utils.utils.using_v3", lambda: True)
|
||||
|
||||
profiler_options_sdk_hip = {
|
||||
"APP_CMD": "my_app",
|
||||
@@ -5458,306 +5417,6 @@ def test_mibench_console_log_called(tmp_path, monkeypatch):
|
||||
assert console_log_calls[0][1] == "No roofline data found. Generating..."
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TESTS FOR flatten_tcc_info_across_xcds
|
||||
# =============================================================================
|
||||
"""
|
||||
Normal Functionality:
|
||||
|
||||
Basic single XCD operation
|
||||
Multiple XCD channel renumbering
|
||||
Complex channel index patterns
|
||||
Multiple dispatch handling
|
||||
Edge Cases:
|
||||
|
||||
Empty dataframes
|
||||
Zero XCDs
|
||||
Insufficient data
|
||||
Large channel numbers
|
||||
Column Handling:
|
||||
|
||||
No TCC columns
|
||||
TCC-only columns
|
||||
Mixed TCC/non-TCC columns
|
||||
Irregular TCC naming patterns
|
||||
Error Conditions:
|
||||
|
||||
File not found errors
|
||||
Invalid input validation
|
||||
Performance & Data Integrity:
|
||||
|
||||
Large dataset handling
|
||||
Data preservation validation
|
||||
Regex pattern validation
|
||||
"""
|
||||
|
||||
|
||||
def test_flatten_tcc_info_across_xcds_zero_xcds(tmp_path):
|
||||
"""
|
||||
Test edge case with zero XCDs.
|
||||
|
||||
Args:
|
||||
tmp_path (Path): Temporary directory for test files.
|
||||
|
||||
Returns:
|
||||
None: Asserts function handles zero XCDs edge case by raising ValueError.
|
||||
"""
|
||||
columns = ["Kernel_Name", "TCC_HIT[0]"]
|
||||
data = [["kernel1", 100]]
|
||||
|
||||
df = pd.DataFrame(data, columns=columns)
|
||||
csv_file = tmp_path / "test_zero_xcds.csv"
|
||||
df.to_csv(csv_file, index=False)
|
||||
|
||||
import utils.utils as utils_mod
|
||||
|
||||
with pytest.raises(ValueError, match="range\\(\\) arg 3 must not be zero"):
|
||||
utils_mod.flatten_tcc_info_across_xcds(
|
||||
str(csv_file), xcds=0, tcc_channel_per_xcd=4
|
||||
)
|
||||
|
||||
|
||||
def test_flatten_tcc_info_across_xcds_insufficient_data(tmp_path):
|
||||
"""
|
||||
Test when there's insufficient data for the specified XCDs.
|
||||
|
||||
Args:
|
||||
tmp_path (Path): Temporary directory for test files.
|
||||
|
||||
Returns:
|
||||
None: Asserts function raises ValueError when trying
|
||||
to process insufficient data.
|
||||
"""
|
||||
columns = ["Kernel_Name", "TCC_HIT[0]"]
|
||||
data = [["kernel1", 100]]
|
||||
|
||||
df = pd.DataFrame(data, columns=columns)
|
||||
csv_file = tmp_path / "test_insufficient.csv"
|
||||
df.to_csv(csv_file, index=False)
|
||||
|
||||
import utils.utils as utils_mod
|
||||
|
||||
with pytest.raises(ValueError, match="cannot set a row with mismatched columns"):
|
||||
utils_mod.flatten_tcc_info_across_xcds(
|
||||
str(csv_file), xcds=3, tcc_channel_per_xcd=4
|
||||
)
|
||||
|
||||
|
||||
def test_flatten_tcc_info_across_xcds_irregular_tcc_column_names(tmp_path):
|
||||
"""
|
||||
Test with irregular TCC column naming patterns.
|
||||
|
||||
Args:
|
||||
tmp_path (Path): Temporary directory for test files.
|
||||
|
||||
Returns:
|
||||
None: Asserts function handles various TCC column name
|
||||
patterns but may fail with pandas Series ambiguity.
|
||||
"""
|
||||
columns = [
|
||||
"Kernel_Name",
|
||||
"TCC_HIT_SPECIAL[0]",
|
||||
"NOT_TCC_BUT_HAS_TCC",
|
||||
"TCC_MISS[0]",
|
||||
]
|
||||
data = [
|
||||
["kernel1", 100, 50, 10],
|
||||
["kernel1", 200, 60, 20],
|
||||
]
|
||||
|
||||
df = pd.DataFrame(data, columns=columns)
|
||||
csv_file = tmp_path / "test_irregular.csv"
|
||||
df.to_csv(csv_file, index=False)
|
||||
|
||||
import utils.utils as utils_mod
|
||||
|
||||
try:
|
||||
result = utils_mod.flatten_tcc_info_across_xcds(
|
||||
str(csv_file), xcds=2, tcc_channel_per_xcd=4
|
||||
)
|
||||
|
||||
assert len(result) == 1
|
||||
assert "TCC_HIT_SPECIAL[0]" in result.columns
|
||||
assert "TCC_HIT_SPECIAL[4]" in result.columns
|
||||
assert "TCC_MISS[0]" in result.columns
|
||||
assert "TCC_MISS[4]" in result.columns
|
||||
assert result.iloc[0]["NOT_TCC_BUT_HAS_TCC"] == 50
|
||||
|
||||
except ValueError as e:
|
||||
if "The truth value of a Series is ambiguous" in str(e):
|
||||
pytest.skip(
|
||||
"Function has pandas Series ambiguity issue in boolean evaluation"
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def test_flatten_tcc_info_across_xcds_regex_pattern_validation(tmp_path):
|
||||
"""
|
||||
Test that regex pattern correctly identifies channel indices.
|
||||
|
||||
Args:
|
||||
tmp_path (Path): Temporary directory for test files.
|
||||
|
||||
Returns:
|
||||
None: Asserts regex pattern works for various channel
|
||||
index formats but may fail with pandas Series ambiguity.
|
||||
"""
|
||||
columns = ["TCC_HIT[0]", "TCC_MISS[10]", "TCC_REQ[255]", "TCC_INVALID_NO_BRACKET"]
|
||||
data = [
|
||||
[100, 200, 300, 400], # XCD 0
|
||||
[500, 600, 700, 800], # XCD 1
|
||||
]
|
||||
|
||||
df = pd.DataFrame(data, columns=columns)
|
||||
csv_file = tmp_path / "test_regex.csv"
|
||||
df.to_csv(csv_file, index=False)
|
||||
|
||||
import utils.utils as utils_mod
|
||||
|
||||
try:
|
||||
result = utils_mod.flatten_tcc_info_across_xcds(
|
||||
str(csv_file), xcds=2, tcc_channel_per_xcd=128
|
||||
)
|
||||
|
||||
assert len(result) == 1
|
||||
assert "TCC_HIT[0]" in result.columns
|
||||
assert "TCC_HIT[128]" in result.columns # 0 + 1*128
|
||||
assert "TCC_MISS[10]" in result.columns
|
||||
assert "TCC_MISS[138]" in result.columns # 10 + 1*128
|
||||
assert "TCC_REQ[255]" in result.columns
|
||||
assert "TCC_REQ[383]" in result.columns # 255 + 1*128
|
||||
|
||||
assert result.iloc[0]["TCC_INVALID_NO_BRACKET"] == 400
|
||||
|
||||
except ValueError as e:
|
||||
if "The truth value of a Series is ambiguous" in str(e):
|
||||
pytest.skip(
|
||||
"Function has pandas Series ambiguity issue in boolean evaluation"
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def test_flatten_tcc_info_across_xcds_edge_case_validation(tmp_path):
|
||||
"""
|
||||
Test edge cases and validation scenarios for
|
||||
flatten_tcc_info_across_xcds.
|
||||
|
||||
Args:
|
||||
tmp_path (Path): Temporary directory for test files.
|
||||
|
||||
Returns:
|
||||
None: Asserts function behavior with various edge cases.
|
||||
"""
|
||||
import utils.utils as utils_mod
|
||||
|
||||
columns = ["Kernel_Name", "TCC_HIT[0]"]
|
||||
data = [["kernel1", 100]]
|
||||
df = pd.DataFrame(data, columns=columns)
|
||||
csv_file = tmp_path / "test_zero_xcds.csv"
|
||||
df.to_csv(csv_file, index=False)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
utils_mod.flatten_tcc_info_across_xcds(
|
||||
str(csv_file), xcds=0, tcc_channel_per_xcd=4
|
||||
)
|
||||
|
||||
try:
|
||||
result = utils_mod.flatten_tcc_info_across_xcds(
|
||||
str(csv_file), xcds=-1, tcc_channel_per_xcd=4
|
||||
)
|
||||
assert len(result) == 0
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
utils_mod.flatten_tcc_info_across_xcds(
|
||||
"nonexistent.csv", xcds=2, tcc_channel_per_xcd=4
|
||||
)
|
||||
|
||||
|
||||
def test_flatten_tcc_info_across_xcds_pandas_filter_issue(tmp_path):
|
||||
"""
|
||||
Test demonstrating the pandas filter regex issue that causes Series ambiguity error.
|
||||
|
||||
Args:
|
||||
tmp_path (Path): Temporary directory for test files.
|
||||
|
||||
Returns:
|
||||
None: Documents the pandas boolean evaluation issue in the function.
|
||||
"""
|
||||
columns = ["Kernel_Name", "TCC_HIT[0]", "SQ_WAVES"]
|
||||
data = [
|
||||
["kernel1", 100, 50],
|
||||
["kernel1", 200, 60],
|
||||
]
|
||||
|
||||
df = pd.DataFrame(data, columns=columns)
|
||||
csv_file = tmp_path / "test_pandas_issue.csv"
|
||||
df.to_csv(csv_file, index=False)
|
||||
|
||||
import utils.utils as utils_mod
|
||||
|
||||
try:
|
||||
result = utils_mod.flatten_tcc_info_across_xcds(
|
||||
str(csv_file), xcds=2, tcc_channel_per_xcd=4
|
||||
)
|
||||
|
||||
assert len(result) == 1
|
||||
assert "Kernel_Name" in result.columns
|
||||
assert "TCC_HIT[0]" in result.columns
|
||||
assert "TCC_HIT[4]" in result.columns
|
||||
assert "SQ_WAVES" in result.columns
|
||||
|
||||
except ValueError as e:
|
||||
if "The truth value of a Series is ambiguous" in str(e):
|
||||
pytest.skip(
|
||||
"Known issue: pandas .filter() with regex causes "
|
||||
"Series boolean ambiguity"
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def test_flatten_tcc_info_across_xcds_successful_cases_only(tmp_path):
|
||||
"""
|
||||
Test only the cases that are expected to work successfully.
|
||||
|
||||
Args:
|
||||
tmp_path (Path): Temporary directory for test files.
|
||||
|
||||
Returns:
|
||||
None: Asserts successful operation for known working scenarios.
|
||||
"""
|
||||
import utils.utils as utils_mod
|
||||
|
||||
columns = ["TCC_HIT[0]", "TCC_MISS[0]"]
|
||||
data = [
|
||||
[100, 10], # XCD 0
|
||||
[200, 20], # XCD 1
|
||||
]
|
||||
|
||||
df = pd.DataFrame(data, columns=columns)
|
||||
csv_file = tmp_path / "test_simple_success.csv"
|
||||
df.to_csv(csv_file, index=False)
|
||||
|
||||
result = utils_mod.flatten_tcc_info_across_xcds(
|
||||
str(csv_file), xcds=2, tcc_channel_per_xcd=4
|
||||
)
|
||||
|
||||
assert len(result) == 1
|
||||
assert "TCC_HIT[0]" in result.columns
|
||||
assert "TCC_HIT[4]" in result.columns
|
||||
assert "TCC_MISS[0]" in result.columns
|
||||
assert "TCC_MISS[4]" in result.columns
|
||||
assert result.iloc[0]["TCC_HIT[0]"] == 100
|
||||
assert result.iloc[0]["TCC_HIT[4]"] == 200
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TESTS FOR flatten_tcc_info_across_xcds
|
||||
# =============================================================================
|
||||
"""
|
||||
Normal Functionality:
|
||||
|
||||
@@ -8517,173 +8176,6 @@ def test_add_counter_overwrite_existing():
|
||||
updated_properties = ["P_UPDATED", "P_NEW"] # noqa
|
||||
|
||||
|
||||
# =================================================================================
|
||||
# Test extract counter info extra config input yaml
|
||||
# =================================================================================
|
||||
|
||||
|
||||
def test_extract_counter_info_returns_none_when_not_found():
|
||||
"""
|
||||
Test that extract_counter_info_extra_config_input_yaml returns None
|
||||
when the counter is not found or data structure is incomplete.
|
||||
"""
|
||||
data_empty = {}
|
||||
assert (
|
||||
utils.extract_counter_info_extra_config_input_yaml(data_empty, "ANY_COUNTER")
|
||||
is None
|
||||
)
|
||||
|
||||
data_no_counters_key = {"rocprofiler-sdk": {}}
|
||||
assert (
|
||||
utils.extract_counter_info_extra_config_input_yaml(
|
||||
data_no_counters_key, "ANY_COUNTER"
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
||||
data_empty_counters_list = {"rocprofiler-sdk": {"counters": []}}
|
||||
assert (
|
||||
utils.extract_counter_info_extra_config_input_yaml(
|
||||
data_empty_counters_list, "ANY_COUNTER"
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
||||
data_with_other_counters = {
|
||||
"rocprofiler-sdk": {
|
||||
"counters": [
|
||||
{"name": "EXISTING_COUNTER_1", "value": "val1"},
|
||||
{"name": "EXISTING_COUNTER_2", "value": "val2"},
|
||||
]
|
||||
}
|
||||
}
|
||||
assert (
|
||||
utils.extract_counter_info_extra_config_input_yaml(
|
||||
data_with_other_counters, "NON_EXISTENT_COUNTER"
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
||||
data_with_malformed_counter = {
|
||||
"rocprofiler-sdk": {
|
||||
"counters": [
|
||||
{"value": "val1"}, # No 'name' key
|
||||
{"name": "EXISTING_COUNTER_2", "value": "val2"},
|
||||
]
|
||||
}
|
||||
}
|
||||
assert (
|
||||
utils.extract_counter_info_extra_config_input_yaml(
|
||||
data_with_malformed_counter, "EXISTING_COUNTER_1"
|
||||
)
|
||||
is None
|
||||
)
|
||||
assert (
|
||||
utils.extract_counter_info_extra_config_input_yaml(
|
||||
data_with_malformed_counter, "EXISTING_COUNTER_2"
|
||||
)
|
||||
is not None
|
||||
)
|
||||
|
||||
|
||||
def test_extract_counter_info_returns_counter_when_found():
|
||||
"""
|
||||
Test that extract_counter_info_extra_config_input_yaml returns the correct
|
||||
counter dictionary when the counter is found.
|
||||
"""
|
||||
counter1_details = {
|
||||
"name": "MY_COUNTER_1",
|
||||
"description": "Desc 1",
|
||||
"expression": "expr1",
|
||||
}
|
||||
counter2_details = {
|
||||
"name": "MY_COUNTER_2",
|
||||
"description": "Desc 2",
|
||||
"expression": "expr2",
|
||||
}
|
||||
data = {
|
||||
"rocprofiler-sdk": {
|
||||
"counters-schema-version": 1,
|
||||
"counters": [
|
||||
counter1_details,
|
||||
counter2_details,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
extracted_counter1 = utils.extract_counter_info_extra_config_input_yaml(
|
||||
data, "MY_COUNTER_1"
|
||||
)
|
||||
assert extracted_counter1 is not None
|
||||
assert extracted_counter1 == counter1_details
|
||||
|
||||
extracted_counter2 = utils.extract_counter_info_extra_config_input_yaml(
|
||||
data, "MY_COUNTER_2"
|
||||
)
|
||||
assert extracted_counter2 is not None
|
||||
assert extracted_counter2 == counter2_details
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# test using_v1 function
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def test_using_v1_rocprof_set_and_ends_with_rocprof_returns_true():
|
||||
"""
|
||||
Covers the case where "ROCPROF" is in os.environ and its value ends with "rocprof".
|
||||
This makes the entire expression True, so the function returns True.
|
||||
"""
|
||||
with mock.patch.dict(
|
||||
os.environ, {"ROCPROF": "/opt/rocm/bin/rocprof", "OTHER_VAR": "value"}
|
||||
):
|
||||
assert utils.using_v1() is True
|
||||
|
||||
|
||||
def test_using_v1_rocprof_set_but_not_ends_with_rocprof_returns_false():
|
||||
"""
|
||||
Covers the case where "ROCPROF" is in os.environ, but its value does
|
||||
NOT end with "rocprof".
|
||||
|
||||
The second part of the 'and' (os.environ["ROCPROF"].endswith("rocprof")) is False.
|
||||
So the function returns False.
|
||||
"""
|
||||
with mock.patch.dict(
|
||||
os.environ, {"ROCPROF": "/opt/rocm/bin/rocprofv2", "OTHER_VAR": "value"}
|
||||
):
|
||||
assert utils.using_v1() is False
|
||||
|
||||
with mock.patch.dict(
|
||||
os.environ, {"ROCPROF": "some/path/to/rocprof_tool", "OTHER_VAR": "value"}
|
||||
):
|
||||
assert utils.using_v1() is False
|
||||
|
||||
|
||||
def test_using_v1_rocprof_not_in_environ_returns_false():
|
||||
"""
|
||||
Covers the case where "ROCPROF" is NOT in os.environ.
|
||||
The first part of the 'and' ("ROCPROF" in os.environ.keys()) is False.
|
||||
Due to short-circuiting, the second part is not evaluated.
|
||||
So the function returns False.
|
||||
"""
|
||||
current_env = os.environ.copy()
|
||||
if "ROCPROF" in current_env:
|
||||
del current_env["ROCPROF"]
|
||||
|
||||
with mock.patch.dict(os.environ, current_env, clear=True):
|
||||
assert utils.using_v1() is False
|
||||
|
||||
|
||||
def test_using_v1_rocprof_is_empty_string_returns_false():
|
||||
"""
|
||||
Covers the case where "ROCPROF" is in os.environ but is an empty string.
|
||||
The second part (os.environ["ROCPROF"].endswith("rocprof")) will be False.
|
||||
So the function returns False.
|
||||
"""
|
||||
with mock.patch.dict(os.environ, {"ROCPROF": "", "OTHER_VAR": "value"}):
|
||||
assert utils.using_v1() is False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# additional test detect_rocprof console error
|
||||
# =============================================================================
|
||||
@@ -8732,27 +8224,6 @@ class MockArgs: # noqa
|
||||
return self.__dict__ == other.__dict__
|
||||
|
||||
|
||||
def test_store_app_cmd_sets_global_rocprof_args():
|
||||
"""
|
||||
Tests that store_app_cmd correctly assigns the passed 'args'
|
||||
object to the global 'rocprof_args'.
|
||||
"""
|
||||
sample_args_object = MockArgs(
|
||||
rocprofiler_sdk_library_path="/path/to/sdk",
|
||||
input_file="input.txt",
|
||||
some_other_option=True,
|
||||
)
|
||||
|
||||
if hasattr(utils, "rocprof_args"):
|
||||
utils.rocprof_args = None
|
||||
else:
|
||||
pass
|
||||
utils.store_app_cmd(sample_args_object)
|
||||
assert utils.rocprof_args is sample_args_object, (
|
||||
"Global rocprof_args should be the same object as the passed args"
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# additional tests for v3_counter_csv_to_v2_csv function
|
||||
# =============================================================================
|
||||
@@ -9112,155 +8583,6 @@ def test_pc_sampling_prof_empty_appcmd(
|
||||
mock_console_error.assert_not_called()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# test replace_timestamps function
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def create_dummy_csv(filepath, data_dict):
|
||||
df = pd.DataFrame(data_dict)
|
||||
df.to_csv(filepath, index=False)
|
||||
|
||||
|
||||
@mock.patch("utils.utils.console_warning")
|
||||
def test_replace_timestamps_no_timestamps_csv_returns_early(
|
||||
mock_console_warning, tmp_path
|
||||
):
|
||||
"""
|
||||
Edge Case: timestamps.csv does not exist in workload_dir.
|
||||
The function should return early.
|
||||
Covers: if not path(workload_dir, "timestamps.csv").is_file(): return
|
||||
"""
|
||||
workload_dir = str(tmp_path)
|
||||
|
||||
utils.replace_timestamps(workload_dir)
|
||||
|
||||
# Since there's no timestamps.csv, function should return early
|
||||
# and console_warning should not be called
|
||||
mock_console_warning.assert_not_called()
|
||||
|
||||
|
||||
@mock.patch("utils.utils.console_warning")
|
||||
@mock.patch("glob.glob")
|
||||
def test_replace_timestamps_timestamps_csv_missing_columns_warns(
|
||||
mock_glob, mock_console_warning, tmp_path
|
||||
):
|
||||
"""
|
||||
Edge Case: timestamps.csv exists but is missing
|
||||
'Start_Timestamp' or 'End_Timestamp'.
|
||||
The function should call console_warning.
|
||||
Covers: else: console_warning(...)
|
||||
"""
|
||||
workload_dir = str(tmp_path)
|
||||
timestamps_csv_path_str = os.path.join(workload_dir, "timestamps.csv")
|
||||
|
||||
# Create the actual CSV file with missing columns
|
||||
create_dummy_csv(timestamps_csv_path_str, {"Some_Other_Column": [123]})
|
||||
|
||||
utils.replace_timestamps(workload_dir)
|
||||
|
||||
# Verify console_warning was called
|
||||
mock_console_warning.assert_called_once_with(
|
||||
"Incomplete profiling data detected. Unable to update timestamps.\n"
|
||||
)
|
||||
# Verify glob wasn't called (since we return early due to missing columns)
|
||||
mock_glob.assert_not_called()
|
||||
|
||||
|
||||
@mock.patch("utils.utils.console_warning")
|
||||
@mock.patch("glob.glob")
|
||||
def test_replace_timestamps_updates_other_csvs_skips_sysinfo(
|
||||
mock_glob, mock_console_warning, tmp_path
|
||||
):
|
||||
"""
|
||||
Edge Case: timestamps.csv is valid. Other CSVs exist, including sysinfo.csv.
|
||||
Only non-sysinfo.csv files should be updated.
|
||||
Covers: for fname in glob.glob(...): if path(fname).name != "sysinfo.csv": ...
|
||||
"""
|
||||
workload_dir = str(tmp_path)
|
||||
timestamps_csv_path_str = os.path.join(workload_dir, "timestamps.csv")
|
||||
data_csv_path_str = os.path.join(workload_dir, "data.csv")
|
||||
sysinfo_csv_path_str = os.path.join(workload_dir, "sysinfo.csv")
|
||||
|
||||
new_start_ts = [1000, 2000]
|
||||
new_end_ts = [1500, 2500]
|
||||
create_dummy_csv(
|
||||
timestamps_csv_path_str,
|
||||
{"Start_Timestamp": new_start_ts, "End_Timestamp": new_end_ts},
|
||||
)
|
||||
|
||||
create_dummy_csv(
|
||||
data_csv_path_str,
|
||||
{"Kernel_Name": ["A", "B"], "Start_Timestamp": [1, 2], "End_Timestamp": [3, 4]},
|
||||
)
|
||||
create_dummy_csv(
|
||||
sysinfo_csv_path_str,
|
||||
{"Info": ["CPU", "MEM"], "Start_Timestamp": [5, 6], "End_Timestamp": [7, 8]},
|
||||
)
|
||||
|
||||
# Mock glob to return the CSV files we created
|
||||
mock_glob.return_value = [
|
||||
data_csv_path_str,
|
||||
sysinfo_csv_path_str,
|
||||
timestamps_csv_path_str,
|
||||
]
|
||||
|
||||
utils.replace_timestamps(workload_dir)
|
||||
|
||||
mock_console_warning.assert_not_called()
|
||||
|
||||
# Verify data.csv was updated with new timestamps
|
||||
df_data_updated = pd.read_csv(data_csv_path_str)
|
||||
pd.testing.assert_series_equal(
|
||||
df_data_updated["Start_Timestamp"],
|
||||
pd.Series(new_start_ts, name="Start_Timestamp"),
|
||||
)
|
||||
pd.testing.assert_series_equal(
|
||||
df_data_updated["End_Timestamp"], pd.Series(new_end_ts, name="End_Timestamp")
|
||||
)
|
||||
|
||||
# Verify sysinfo.csv was NOT updated (timestamps should remain original)
|
||||
df_sysinfo_original = pd.read_csv(sysinfo_csv_path_str)
|
||||
assert list(df_sysinfo_original["Start_Timestamp"]) == [5, 6]
|
||||
assert list(df_sysinfo_original["End_Timestamp"]) == [7, 8]
|
||||
|
||||
|
||||
@mock.patch("utils.utils.console_warning")
|
||||
@mock.patch("glob.glob")
|
||||
def test_replace_timestamps_no_other_csvs_to_update(
|
||||
mock_glob, mock_console_warning, tmp_path
|
||||
):
|
||||
"""
|
||||
Edge Case: timestamps.csv is valid, but no other *.csv files
|
||||
(or only sysinfo.csv) exist.
|
||||
The loop for updating files should not do anything or not run.
|
||||
Covers: The for loop not iterating if glob returns empty or only sysinfo.
|
||||
"""
|
||||
workload_dir = str(tmp_path)
|
||||
timestamps_csv_path_str = os.path.join(workload_dir, "timestamps.csv")
|
||||
sysinfo_csv_path_str = os.path.join(workload_dir, "sysinfo.csv")
|
||||
|
||||
create_dummy_csv(
|
||||
timestamps_csv_path_str, {"Start_Timestamp": [100], "End_Timestamp": [200]}
|
||||
)
|
||||
create_dummy_csv(
|
||||
sysinfo_csv_path_str,
|
||||
{"Info": ["CPU"], "Start_Timestamp": [5], "End_Timestamp": [7]},
|
||||
)
|
||||
|
||||
# Mock glob to return only timestamps.csv and sysinfo.csv
|
||||
mock_glob.return_value = [timestamps_csv_path_str, sysinfo_csv_path_str]
|
||||
|
||||
utils.replace_timestamps(workload_dir)
|
||||
|
||||
mock_console_warning.assert_not_called()
|
||||
|
||||
# Verify sysinfo.csv was NOT updated (timestamps should remain original)
|
||||
df_sysinfo_original = pd.read_csv(sysinfo_csv_path_str)
|
||||
assert list(df_sysinfo_original["Start_Timestamp"]) == [5]
|
||||
assert list(df_sysinfo_original["End_Timestamp"]) == [7]
|
||||
|
||||
|
||||
def test_set_parser():
|
||||
from utils.utils import parse_sets_yaml
|
||||
|
||||
|
||||
Reference in New Issue
Block a user