Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-26 08:22:17

0001 # SPDX-PackageName = "traccc, a part of the ACTS project"
0002 # SPDX-FileCopyrightText: CERN
0003 # SPDX-License-Identifier: MPL-2.0
0004 
0005 import pathlib
0006 import pandas
0007 import functools
0008 import numpy
0009 import tempfile
0010 import subprocess
0011 import operator
0012 import logging
0013 
0014 from .types import GpuSpec
0015 from .kernels import simplify_name, map_name
0016 from .utils import harmonic_sum
0017 
0018 log = logging.getLogger("traccc_bench_tools.parse_profile")
0019 
0020 
0021 def parse_triple(triple):
0022     assert triple[0] == "(" and triple[-1] == ")"
0023     x, y, z = triple[1:-1].split(", ")
0024     return int(x), int(y), int(z)
0025 
0026 
0027 def parse_profile_ncu(file: pathlib.Path, gpu_spec: GpuSpec, **kwargs):
0028     with tempfile.TemporaryDirectory() as tmpdirname:
0029         tmppath = pathlib.Path(tmpdirname)
0030 
0031         profile_file = tmppath / "profile.csv"
0032 
0033         with open(profile_file, "w") as f:
0034             subprocess.run(
0035                 [
0036                     "ncu",
0037                     "-i",
0038                     file,
0039                     "--csv",
0040                     "--print-units",
0041                     "base",
0042                 ],
0043                 stdout=f,
0044             )
0045 
0046         return parse_profile_csv(profile_file, gpu_spec, **kwargs)
0047 
0048 
0049 def parse_profile_csv(file: pathlib.Path, gpu_spec: GpuSpec, event_marker_kernel=None):
0050     if event_marker_kernel is None:
0051         event_marker_kernel = "ccl_kernel"
0052 
0053     df = pandas.read_csv(file)
0054 
0055     ndf = df[df["Metric Name"] == "gpu__time_duration.sum"][
0056         ["ID", "Kernel Name", "Block Size", "Grid Size", "Metric Value", "Metric Unit"]
0057     ]
0058 
0059     assert (ndf["Metric Unit"] == "ns").all()
0060 
0061     ndf["ThreadsPerBlock"] = df["Block Size"].apply(
0062         lambda x: functools.reduce(operator.mul, (parse_triple(x)))
0063     )
0064     ndf["BlocksPerGrid"] = df["Grid Size"].apply(
0065         lambda x: functools.reduce(operator.mul, (parse_triple(x)))
0066     )
0067     ndf["TotalThreads"] = ndf["ThreadsPerBlock"] * ndf["BlocksPerGrid"]
0068     ndf = ndf.drop(
0069         ["Block Size", "Grid Size", "ThreadsPerBlock", "BlocksPerGrid", "Metric Unit"],
0070         axis=1,
0071     )
0072     ndf["Metric Value"] = ndf["Metric Value"].apply(lambda x: int(x.replace(",", "")))
0073     ndf["Kernel Name"] = ndf["Kernel Name"].apply(simplify_name)
0074     ndf["Kernel Name"] = ndf["Kernel Name"].apply(map_name)
0075 
0076     curr_evt_id = None
0077     evt_ids = []
0078     for x in ndf.iloc:
0079         if x["Kernel Name"] == event_marker_kernel:
0080             if curr_evt_id is None:
0081                 curr_evt_id = 0
0082             else:
0083                 curr_evt_id += 1
0084         evt_ids.append(curr_evt_id)
0085 
0086     num_unidentified_event_ids = sum(1 for x in evt_ids if x is None)
0087 
0088     if num_unidentified_event_ids > 0:
0089         log.warning(
0090             "Event ID could not be determined for %d kernels",
0091             num_unidentified_event_ids,
0092         )
0093 
0094     ndf["EventID"] = evt_ids
0095 
0096     thr_occ = df[df["Metric Name"] == "Theoretical Occupancy"]
0097 
0098     ndf = ndf.merge(
0099         thr_occ[["ID", "Metric Value"]],
0100         on="ID",
0101         how="left",
0102         validate="one_to_one",
0103         suffixes=("", "R"),
0104     )
0105 
0106     ndf["Occupancy"] = ndf["Metric ValueR"].apply(lambda x: float(x) / 100.0)
0107 
0108     ndf["k"] = ndf["TotalThreads"] / (
0109         gpu_spec.n_sm * gpu_spec.n_threads_per_sm * ndf["Occupancy"]
0110     )
0111 
0112     ndf["Latency"] = ndf["Metric Value"] / 1e9
0113 
0114     ndf["Throughput"] = (numpy.ceil(ndf["k"]) / ndf["k"]) / (ndf["Metric Value"] / 1e9)
0115     ndf["RecThroughput"] = 1.0 / ndf["Throughput"]
0116 
0117     ndf = ndf.drop(["Metric ValueR"], axis=1)
0118 
0119     ndf = ndf.groupby(["Kernel Name", "EventID"], as_index=False).agg(
0120         {"Throughput": harmonic_sum, "RecThroughput": "sum", "Latency": "sum"},
0121     )
0122 
0123     ndf = ndf.groupby("Kernel Name", as_index=False).agg(
0124         ThroughputMean=("Throughput", "mean"),
0125         ThroughputStd=("Throughput", "std"),
0126         RecThroughputMean=("RecThroughput", "mean"),
0127         RecThroughputStd=("RecThroughput", "std"),
0128         LatencyMean=("Latency", "mean"),
0129         LatencyStd=("Latency", "std"),
0130     )
0131 
0132     return ndf.fillna(0)