qwen38-flash-next / code /models /perf /perf_utils.py
DeAIafdeling's picture
Add files using upload-large-folder tool
ca4edfb verified
Raw History Blame Contribute Delete
10.2 kB
# SPDX-FileCopyrightText: © 2023 Tenstorrent USA, Inc.
# SPDX-License-Identifier: Apache-2.0
import csv
import re
import time
from os import listdir
from os.path import isfile, join
import git
from loguru import logger
from models.perf.benchmarking_utils import BenchmarkData, BenchmarkProfiler
today = time.strftime("%Y_%m_%d")
def merge_perf_files(fname, perf_fname, expected_cols):
mypath = "./"
csvfiles = [
f
for f in listdir(mypath)
if isfile(join(mypath, f)) and re.match(f"{perf_fname}_.*_{today}.csv", f) is not None
]
repo = git.Repo(search_parent_directories=True)
merge_res = open(fname, "w")
if not repo.head.is_detached:
merge_res.write(f"branch: {repo.active_branch} \n")
else:
merge_res.write(f"branch: detached HEAD \n")
merge_res.write(f"hash: {repo.head.object.hexsha} \n")
cols = ", ".join(expected_cols)
merge_res.write(f"{cols} \n")
csvfiles.sort()
for csvfile in csvfiles:
row_name = csvfile.replace("perf_", "")
row_name = row_name.replace(f"{today}", "")
row_name = row_name.replace(".csv", "")
f = open(f"./{csvfile}", "r")
f.readline()
row = f.readline().strip().strip("\n")
merge_res.write(f"{row}\n")
merge_res.close()
def process_perf_results(fname, expected_cols):
with open(fname) as file:
merge_res = csv.reader(file, skipinitialspace=True)
logger.info(next(merge_res)[0].strip())
logger.info(next(merge_res)[0].strip())
cols = next(merge_res)
cols = [c.strip() for c in cols]
assert len(expected_cols) == len(cols), "Mismatch between expected and actual columns in perf CSV"
for expected_c, c in zip(expected_cols, cols):
assert expected_c == c, f"Expected column {expected_c} but instead got {c}"
merge_res = list(merge_res)
return cols, merge_res
def check_perf_results(
fname, expected_cols, check_cols, table_width=110, float_precision=4, lower_threshold=0.80, upper_threshold=1.0
):
red_color_code = "\033[91m"
green_color_code = "\033[92m"
reset_color_code = "\033[0m"
bold_code = "\033[1m"
underline_code = "\033[4m"
fail_label = "[FAIL]"
pass_label = "[PASS]"
cols, merge_res = process_perf_results(fname, expected_cols)
visited_models = []
slow_measured = {col: [] for col in check_cols}
logger.info(f"Checking perf results for {fname}...")
print("=" * table_width)
print(f"{bold_code}PERFORMANCE RESULTS{reset_color_code}")
print("=" * table_width)
for models_info in merge_res:
dict_info = {name: value for name, value in zip(cols, models_info)}
model_name = f"{dict_info['Model']}_{dict_info['Setting']}"
visited_models.append(model_name)
print(f"\n{bold_code}{underline_code}Model: {dict_info['Model']}{reset_color_code}")
print(f"{bold_code}Setting: {dict_info['Setting']}{reset_color_code}")
print("-" * 60)
highlight = False
for col in check_cols:
model_expected_col = float(dict_info[f"Expected {col}"])
model_measured_col = float(dict_info[col])
low_tolerance = (
model_expected_col * lower_threshold
) # fail if model is too fast so we can update the expected values
high_tolerance = model_expected_col * upper_threshold # upper bound for regression
if model_measured_col > high_tolerance:
slow_measured[col].append((model_name, model_measured_col, model_expected_col))
regression_pct = ((model_measured_col - model_expected_col) / model_expected_col) * 100
print(
f" FAIL {col}: {red_color_code}{model_measured_col:.{float_precision}f} > {high_tolerance:.{float_precision}f} ({regression_pct:.1f}% worse than expected - performance regression){reset_color_code}"
)
highlight = True
elif model_measured_col < low_tolerance:
slow_measured[col].append((model_name, model_measured_col, model_expected_col))
improvement_pct = ((model_expected_col - model_measured_col) / model_expected_col) * 100
print(
f" FAIL {col}: {red_color_code}{model_measured_col:.{float_precision}f} < {low_tolerance:.{float_precision}f} ({improvement_pct:.1f}% better than expected - update baseline){reset_color_code}"
)
highlight = True
else:
print(
f" PASS {col}: {model_measured_col:.{float_precision}f} (within tolerance: {low_tolerance:.{float_precision}f} - {high_tolerance:.{float_precision}f})"
)
if highlight:
print(f" {red_color_code}This model has performance issues{reset_color_code}")
else:
print(f" {green_color_code}All performance targets met{reset_color_code}")
print("\n" + "=" * table_width)
print(f"{bold_code}SUMMARY{reset_color_code}")
print("=" * table_width)
all_passed = True
for col in slow_measured:
if slow_measured[col]:
all_passed = False
print(f"{red_color_code}{fail_label} The following models failed '{col}' checks:{reset_color_code}")
for model_name, measured, expected in slow_measured[col]:
tolerance_range = f"[{expected * lower_threshold:.{float_precision}f}, {expected * upper_threshold:.{float_precision}f}]"
if measured > expected * upper_threshold:
regression_pct = ((measured - expected) / expected) * 100
status = f"{regression_pct:.1f}% regression"
else:
improvement_pct = ((expected - measured) / expected) * 100
status = f"{improvement_pct:.1f}% improvement"
print(
f" - {model_name}: measured={measured:.{float_precision}f}, expected={expected:.{float_precision}f}, tolerance={tolerance_range} ({status})"
)
else:
print(f"{green_color_code}{pass_label} All models meet expected '{col}' performance.{reset_color_code}")
print("=" * table_width)
if all_passed:
print(f"{green_color_code}All performance checks passed!{reset_color_code}")
else:
print(f"{red_color_code}Some performance checks failed!{reset_color_code}")
print("=" * table_width)
if any(len(slow) > 0 for slow in slow_measured.values()):
raise Exception(
"Performance checks failed - see above for models with regressions or significant improvements requiring baseline updates"
)
def prep_perf_report(
model_name: str,
batch_size: int,
inference_and_compile_time: float,
inference_time: float,
expected_compile_time: float,
expected_inference_time: float,
comments: str,
inference_time_cpu: float = None,
):
today = time.strftime("%Y_%m_%d")
def write_dict_to_file(csv_path, dict_res):
columns = ", ".join([str(d) for d in dict_res.keys()])
values = ", ".join([d for d in dict_res.values()])
with open(csv_path, "w") as csvfile:
csvfile.write(columns)
csvfile.write("\n")
csvfile.write(values)
compile_time = inference_and_compile_time - inference_time
device_throughput = "{:.4f}".format(batch_size * (1 / inference_time))
cpu_throughput = batch_size * (1 / inference_time_cpu) if inference_time_cpu else "unknown"
cpu_throughput = "{:.4f}".format(cpu_throughput) if not isinstance(cpu_throughput, str) else cpu_throughput
dict_res = {
"Model": model_name,
"Setting": comments,
"Batch": str(batch_size),
"First Run (sec)": "{:.2f}".format(inference_and_compile_time),
"Second Run (sec)": "{:.2f}".format(inference_time),
"Compile Time (sec)": "{:.2f}".format(compile_time),
"Expected Compile Time (sec)": "{:.2f}".format(expected_compile_time),
"Inference Time (sec)": "{:.4f}".format(inference_time),
"Expected Inference Time (sec)": "{:.4f}".format(expected_inference_time),
"Throughput (batch*inf/sec)": device_throughput,
"Inference Time CPU (sec)": "{:.4f}".format(inference_time_cpu) if inference_time_cpu else "unknown",
"Throughput CPU (batch*inf/sec)": cpu_throughput,
}
model_name = model_name.replace("/", "_")
csv_file = f"perf_{model_name}_{comments}_{today}.csv"
write_dict_to_file(csv_file, dict_res)
# Dummy profiler to satisfy BenchmarkData's requirements
profiler = BenchmarkProfiler()
profiler.start("run")
profiler.end("run")
step_name = "end_to_end_perf"
profiler.start(step_name)
profiler.end(step_name)
benchmark_data = BenchmarkData()
# Add measurements for the key performance metrics
# Convert string values back to float for measurements
benchmark_data.add_measurement(profiler, 0, step_name, "inference_time_s", inference_time)
benchmark_data.add_measurement(profiler, 0, step_name, "compile_time_s", compile_time)
benchmark_data.add_measurement(profiler, 0, step_name, "throughput_iter_per_s", float(device_throughput))
benchmark_data.add_measurement(profiler, 0, step_name, "first_run_s", inference_and_compile_time)
benchmark_data.add_measurement(profiler, 0, step_name, "expected_inference_time_s", expected_inference_time)
benchmark_data.add_measurement(profiler, 0, step_name, "expected_compile_time_s", expected_compile_time)
if inference_time_cpu is not None:
benchmark_data.add_measurement(profiler, 0, step_name, "inference_time_cpu_s", inference_time_cpu)
benchmark_data.add_measurement(
profiler,
0,
step_name,
"throughput_cpu_iter_per_s",
float(cpu_throughput) if cpu_throughput != "unknown" else 0.0,
)
benchmark_data.save_partial_run_json(
profiler,
run_type="end_to_end_perf",
ml_model_name=model_name,
batch_size=batch_size,
)