[INFRA] Import NVIDIA/CCCL upstream as optimization reference library
CCCL (CUDA C++ Core Libraries) provides: - CUB: device/block/warp-level GPU primitives (reduce, scan, sort, topk) - Thrust: high-level parallel algorithms (transform_reduce, sort, scan) - libcudacxx: CUDA C++ standard library (atomics, barriers, memory) - cudax: experimental features (memory resources, allocators) - Tuning policies: per-SM hardware-specific algorithm parameters Competition optimization vectors mapped to CCCL: - Output TPS (83% weight): warp_reduce, block_reduce, device_topk - Input TPS (14% weight): device_scan, block_load, prefetch - Cache TPS (3% weight): prefix caching strategy patterns - Memory (0.9 util): pooled/cached/buddy allocators Source: https://github.com/NVIDIA/cccl (shallow clone, HEAD only) License: Apache-2.0
This commit is contained in:
158
cccl_upstream/benchmarks/scripts/compare.py
Executable file
158
cccl_upstream/benchmarks/scripts/compare.py
Executable file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import cccl
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from colorama import Fore
|
||||
|
||||
|
||||
def get_filenames_map(arr):
|
||||
if not arr:
|
||||
return []
|
||||
|
||||
prefix = arr[0]
|
||||
for string in arr:
|
||||
while not string.startswith(prefix):
|
||||
prefix = prefix[:-1]
|
||||
if not prefix:
|
||||
break
|
||||
|
||||
return {string: string[len(prefix) :] for string in arr}
|
||||
|
||||
|
||||
def is_finite(x):
|
||||
if isinstance(x, float):
|
||||
return x != np.inf and x != -np.inf
|
||||
return True
|
||||
|
||||
|
||||
def filter_by_problem_size(df):
|
||||
min_elements_pow2 = 28
|
||||
if "Elements{io}[pow2]" in df.columns:
|
||||
df["Elements{io}[pow2]"] = df["Elements{io}[pow2]"].astype(int)
|
||||
df = df[df["Elements{io}[pow2]"] >= min_elements_pow2]
|
||||
return df
|
||||
|
||||
|
||||
def filter_by_offset_type(df):
|
||||
if "OffsetT{ct}" in df.columns:
|
||||
df = df[(df["OffsetT{ct}"] == "I32") | (df["OffsetT{ct}"] == "U32")]
|
||||
return df
|
||||
|
||||
|
||||
def filter_by_type(df):
|
||||
if "T{ct}" in df:
|
||||
# df = df[df['T{ct}'].str.contains('64')]
|
||||
df = df[~df["T{ct}"].str.contains("C")]
|
||||
elif "KeyT{ct}" in df:
|
||||
# df = df[df['KeyT{ct}'].str.contains('64')]
|
||||
df = df[~df["KeyT{ct}"].str.contains("C")]
|
||||
return df
|
||||
|
||||
|
||||
def alg_dfs(file):
|
||||
result = {}
|
||||
storage = cccl.bench.SQLiteStorage(file)
|
||||
for algname in storage.algnames():
|
||||
for subbench in storage.subbenches(algname):
|
||||
df = storage.alg_to_df(algname, subbench)
|
||||
df = df.map(lambda x: x if is_finite(x) else np.nan)
|
||||
df = df.dropna(subset=["center"], how="all")
|
||||
# TODO(bgruber): maybe expose the filters under a -p0, or --short flag
|
||||
# df = filter_by_type(filter_by_offset_type(filter_by_problem_size(df)))
|
||||
df["Noise"] = df["samples"].apply(lambda x: np.std(x) / np.mean(x)) * 100
|
||||
df["Mean"] = df["samples"].apply(lambda x: np.mean(x))
|
||||
df = df.drop(columns=["samples", "center", "bw", "elapsed", "variant"])
|
||||
fused_algname = (
|
||||
algname.removeprefix("cub.bench.").removeprefix("thrust.bench.")
|
||||
+ "."
|
||||
+ subbench
|
||||
)
|
||||
result[fused_algname] = df
|
||||
|
||||
for algname in result:
|
||||
if result[algname]["cccl"].nunique() != 1:
|
||||
print(f"WARNING: Multiple CCCL versions in one db '{algname}'")
|
||||
result[algname] = result[algname].drop(columns=["cccl"])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def file_exists(value):
|
||||
if not os.path.isfile(value):
|
||||
raise argparse.ArgumentTypeError(f"The file '{value}' does not exist.")
|
||||
return value
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="Analyze benchmark results.")
|
||||
parser.add_argument("reference", type=file_exists, help="Reference database file.")
|
||||
parser.add_argument("compare", type=file_exists, help="Comparison database file.")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
config_count = 0
|
||||
pass_count = 0
|
||||
faster_count = 0
|
||||
slower_count = 0
|
||||
|
||||
|
||||
def status(frac_diff, noise_ref, noise_cmp):
|
||||
global config_count
|
||||
global pass_count
|
||||
global faster_count
|
||||
global slower_count
|
||||
config_count += 1
|
||||
min_noise = min(noise_ref, noise_cmp)
|
||||
if abs(frac_diff) <= min_noise:
|
||||
pass_count += 1
|
||||
return Fore.BLUE + "SAME" + Fore.RESET
|
||||
if frac_diff < 0:
|
||||
faster_count += 1
|
||||
return Fore.GREEN + "FAST" + Fore.RESET
|
||||
if frac_diff > 0:
|
||||
slower_count += 1
|
||||
return Fore.RED + "SLOW" + Fore.RESET
|
||||
|
||||
|
||||
def compare():
|
||||
args = parse_args()
|
||||
reference_df = alg_dfs(args.reference)
|
||||
compare_df = alg_dfs(args.compare)
|
||||
for alg in sorted(reference_df.keys() & compare_df.keys()):
|
||||
print()
|
||||
print()
|
||||
print(f"# {alg}")
|
||||
# use every column except 'Noise', 'Mean', 'ctk', 'gpu' to match runs between reference and comparison file
|
||||
merge_columns = [
|
||||
col
|
||||
for col in reference_df[alg].columns
|
||||
if col not in ["Noise", "Mean", "ctk", "gpu"]
|
||||
]
|
||||
df = pd.merge(
|
||||
reference_df[alg],
|
||||
compare_df[alg],
|
||||
on=merge_columns,
|
||||
suffixes=("Ref", "Cmp"),
|
||||
)
|
||||
df["Abs. Diff"] = df["MeanCmp"] - df["MeanRef"]
|
||||
df["Rel. Diff"] = (df["Abs. Diff"] / df["MeanRef"]) * 100
|
||||
df["Status"] = list(
|
||||
map(status, df["Rel. Diff"], df["NoiseRef"], df["NoiseCmp"])
|
||||
)
|
||||
df = df.drop(columns=["ctkRef", "ctkCmp", "gpuRef", "gpuCmp"])
|
||||
print()
|
||||
print(df.to_markdown(index=False))
|
||||
|
||||
print("# Summary\n")
|
||||
print("- Total Matches: %d" % config_count)
|
||||
print(" - Pass (diff <= min_noise): %d" % pass_count)
|
||||
print(" - Faster (diff > min_noise): %d" % faster_count)
|
||||
print(" - Slower (diff > min_noise): %d" % slower_count)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
compare()
|
||||
Reference in New Issue
Block a user