geak_eval / TB-eval /tb_eval /perf /efficiency.py
llmll's picture
Upload folder using huggingface_hub
02c783d verified
# Copyright(C) [2025] Advanced Micro Devices, Inc. All rights reserved.
import os
import shutil
import json
from .base import BasePerfEval
from ..helpers.helper import run_shell
from ..constants import TBG_PERF_GOLD_DATA_ROOT, ROCM_PERF_GOLD_DATA_ROOT
class PerformanceEvalTBG(BasePerfEval):
"""
Performance evaluation for the TBG model.
This class inherits from BasePerfEval and implements the evaluate method.
"""
ref_folder = TBG_PERF_GOLD_DATA_ROOT
def __init__(self, name :str='PerformanceEvalTBG'):
"""
Initialize the PerformanceEvalTBG instance.
Args:
name (str): The name of the performance evaluation instance.
"""
super().__init__(name=name)
def evaluate(self, exec_folder: str, gen_perf_folder: str=None, golden_metrics_folder:str=None) -> dict:
"""
Evaluate the performance of the TBG model on the given data.
Args:
folder: Root location with kernels to evaluate.
Returns:
A dictionary containing the evaluation results.
"""
ref_folder = self.ref_folder
print(f"Running performance analysis for {exec_folder}")
assert os.path.exists(exec_folder), f"Execution folder {exec_folder} does not exist."
gen_perf_folder = os.path.join(exec_folder, 'gen_perf') if gen_perf_folder is None else gen_perf_folder
## if gen_perf_folder exists, remove it
if os.path.exists(gen_perf_folder):
print(f"Removing existing performance folder: {gen_perf_folder}")
shutil.rmtree(gen_perf_folder)
os.makedirs( gen_perf_folder, exist_ok=True)
exec_folder = os.path.abspath(exec_folder)
gen_perf_folder = os.path.abspath(gen_perf_folder)
curr_dir = os.path.dirname(os.path.abspath(__file__))
print("Writing files to the performance folder...")
cmd = [f'python3 {curr_dir}/run_bench/write_file.py --input_folder_path {exec_folder} --result_folder_path {gen_perf_folder}']
if golden_metrics_folder:
cmd[-1] += f' --golden_metrics_folder {golden_metrics_folder}'
write_status, write_stdout, write_stderr = run_shell(cmd)
print(f"Write status: {write_status}, stdout: {write_stdout}, stderr: {write_stderr}")
perf_stdout = None
if write_status:
print("Files written successfully to the performance folder. Running them...")
cmd = [f"python3 {curr_dir}/run_bench/multiprocess_gpu_run.py --root_dir {gen_perf_folder}"]
mp_run_status, mp_run_stdout, mp_run_stderr = run_shell(cmd)
print(f"Multiprocess GPU run status: {mp_run_status}, stdout: {mp_run_stdout}, stderr: {mp_run_stderr}")
if mp_run_status:
print("Multiprocess GPU run completed successfully. Running performance analysis...")
cmd = [f"python3 {curr_dir}/2_efficiency.py --gen_folder {gen_perf_folder} --ref_folder {ref_folder}"]
perf_status, perf_stdout, perf_stderr = run_shell(cmd)
print(f"Performance analysis status: {perf_status}, stdout: {perf_stdout}, stderr: {perf_stderr}")
if perf_status:
print(f"Performance analysis completed successfully for {exec_folder}.")
with open(os.path.join(exec_folder, 'performance_analysis.txt'), 'w') as f:
f.write(f"Performance analysis for {exec_folder}:\n")
f.write(perf_stdout)
else:
assert False, f"Failed to run 2_efficiency.py: {perf_stderr}"
else:
assert False, f"Failed to run multiprocess_gpu_run.py: {mp_run_stderr}"
else:
assert False, f"Failed to write files: {write_stderr}"
print(f"DONE with performance analysis for {exec_folder}")
parser_perf_data = self.parse(gen_perf_folder)
return parser_perf_data
def parse(self, perf_data_path:str) -> dict:
eff_fname = os.path.join(perf_data_path, 'efficiency.json')
parsed_perf_data = {}
if os.path.exists(eff_fname):
with open(eff_fname, 'r') as f:
perf_data = json.load(f)
parsed_perf_data = perf_data
return parsed_perf_data
class PerformanceEvalROCm(BasePerfEval):
"""
Performance evaluation for the ROCm kernels.
This class inherits from BaseEval and implements the evaluate method.
"""
ref_folder = ROCM_PERF_GOLD_DATA_ROOT
def __init__(self, name: str = 'PerformanceEvalROCm', ref_folder: str = None):
"""
Initialize the PerformanceEvalROCm instance.
Args:
name (str): The name of the performance evaluation instance.
"""
super().__init__(name=name)
if ref_folder is not None:
self.ref_folder = ref_folder
else:
self.ref_folder = ROCM_PERF_GOLD_DATA_ROOT
def evaluate(self, exec_folder: str, gen_perf_folder: str = None, golden_metrics_folder: str = None) -> dict:
"""
Evaluate the performance of ROCm kernels.
Args:
exec_folder: Root location with kernels (py files with pytest functions) to evaluate.
gen_perf_folder: Folder where performance JSONs will be stored. Defaults to exec_folder/perf.
golden_metrics_folder: Not used in this evaluation.
Returns:
A dictionary containing the evaluation results (ms and efficiency for each file).
"""
print(f"Running ROCm performance analysis for {exec_folder}")
assert os.path.exists(exec_folder), f"Execution folder {exec_folder} does not exist."
if gen_perf_folder is None:
gen_perf_folder = os.path.join(exec_folder, 'perf')
if os.path.exists(gen_perf_folder):
print(f"Removing existing performance folder: {gen_perf_folder}")
shutil.rmtree(gen_perf_folder)
os.makedirs(gen_perf_folder, exist_ok=True)
print(f"Ensured gen_perf_folder exists at: {gen_perf_folder}")
exec_folder_abs = os.path.abspath(exec_folder)
gen_perf_folder_abs = os.path.abspath(gen_perf_folder)
curr_dir = os.path.dirname(os.path.abspath(__file__))
py_files = [f for f in os.listdir(exec_folder_abs) if os.path.isfile(os.path.join(exec_folder_abs, f)) and f.endswith('.py')]
if not py_files:
print(f"No .py files found in {exec_folder_abs}. Skipping pytest execution.")
else:
print(f"Found .py files to test: {py_files}")
for py_file_name in py_files:
py_file_path = os.path.join(exec_folder_abs, py_file_name)
# Define the specific tests to run in order: test_performance then test_save_performance_results
tests_to_run_specifiers = f"{py_file_path}::test_performance {py_file_path}::test_save_performance_results"
print(f"Running pytest for {py_file_path} (test_performance then test_save_performance_results)...")
cmd_pytest = [f"pytest {tests_to_run_specifiers}"]
# Pass gen_perf_folder_abs as an environment variable so tests can use it
test_env = os.environ.copy()
test_env["PERF_OUTPUT_DIR"] = gen_perf_folder_abs
global_timeout = 30*60
try:
pytest_status, pytest_stdout, pytest_stderr = run_shell(cmd_pytest, env=test_env, timeout=global_timeout)
except TimeoutError as e:
pytest_status = False
pytest_stdout = None
pytest_stderr = str(e)
print(f"Pytest execution timed out for {py_file_path} (test_performance & test_save_performance_results): {pytest_stderr}")
print(f"Pytest run for {py_file_path} (test_performance & test_save_performance_results) status: {pytest_status}")
if pytest_stdout:
print(f"Stdout: {pytest_stdout}")
if pytest_stderr:
print(f"Stderr: {pytest_stderr}")
if not pytest_status:
assert False, f"Pytest execution failed for {py_file_path} (test_performance & test_save_performance_results): {pytest_stderr}"
print("All pytest runs completed.")
efficiency_script_path = os.path.join(curr_dir, "ROCm", "efficiency.py")
# Attempt to find ROCm folder if it's a sibling to the 'perf' directory (where this script might be)
if not os.path.exists(efficiency_script_path):
# curr_dir is .../perf, so os.path.dirname(curr_dir) is the parent of 'perf'
alt_efficiency_script_path = os.path.join(os.path.dirname(curr_dir), "ROCm", "efficiency.py")
if os.path.exists(alt_efficiency_script_path):
efficiency_script_path = alt_efficiency_script_path
else:
# Check if ROCm is a direct subdirectory of the current script's location
potential_path = os.path.join(curr_dir, "ROCm", "efficiency.py")
if os.path.exists(potential_path):
efficiency_script_path = potential_path
else:
assert False, f"Efficiency script not found. Checked: {os.path.join(curr_dir, 'ROCm', 'efficiency.py')} and {alt_efficiency_script_path}"
cmd_efficiency = [f"python3 {efficiency_script_path} --gen_folder {gen_perf_folder_abs} --ref_folder {self.ref_folder}"]
print(f"Running efficiency script: {' '.join(cmd_efficiency)}")
eff_status, eff_stdout, eff_stderr = run_shell(cmd_efficiency)
print(f"Efficiency script status: {eff_status}")
if eff_stdout:
print(f"Stdout: {eff_stdout}")
if eff_stderr:
print(f"Stderr: {eff_stderr}")
if not eff_status:
assert False, f"Failed to run efficiency script {efficiency_script_path}: {eff_stderr}"
print(f"ROCm performance analysis script completed for {exec_folder}.")
try:
with open(os.path.join(exec_folder_abs, 'rocm_performance_analysis.txt'), 'w') as f:
f.write(f"ROCm Performance analysis for {exec_folder_abs}:\n")
f.write(f"Pytest phase produced outputs in {gen_perf_folder_abs}\n\n")
f.write("Efficiency script stdout:\n")
f.write(eff_stdout or "N/A")
if eff_stderr:
f.write("\n\nEfficiency script stderr:\n")
f.write(eff_stderr)
except Exception as e:
print(f"Failed to write rocm_performance_analysis.txt: {e}")
parsed_perf_data = self.parse(gen_perf_folder_abs)
return parsed_perf_data
def parse(self, perf_data_path: str) -> dict:
"""
Parse the all_perf_results.json file generated by the ROCm efficiency script.
Args:
perf_data_path: Path to the folder containing all_perf_results.json (this is gen_perf_folder).
Returns:
A dictionary containing the parsed performance data (ms and efficiency).
"""
eff_fname = os.path.join(perf_data_path, 'all_perf_results.json')
parsed_perf_data = {}
if os.path.exists(eff_fname):
print(f"Parsing performance data from {eff_fname}")
try:
with open(eff_fname, 'r') as f:
perf_data = json.load(f)
parsed_perf_data = perf_data
except json.JSONDecodeError as e:
print(f"Error decoding JSON from {eff_fname}: {e}. Returning empty data.")
except Exception as e:
print(f"An unexpected error occurred while parsing {eff_fname}: {e}. Returning empty data.")
else:
print(f"Performance results file not found: {eff_fname}. Returning empty data.")
return parsed_perf_data
get_perf_evaluators = {
'tbg': PerformanceEvalTBG,
'rocm': PerformanceEvalROCm
}