File indexing completed on 2026-05-27 07:23:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 import argparse
0014 import re
0015 import collections
0016 import pathlib
0017
0018
0019 class InstructionCounter:
0020 """
0021 Class for counting the use of certain instructions in translation units.
0022
0023 The instructions and translation units are counted, not linked. So this
0024 class cannot reconstruct that a particular instruction was emitted in a
0025 particular translation unit. But I don't think that's necessary at this
0026 time."""
0027
0028 def __init__(self):
0029 """
0030 Initialize the counter.
0031
0032 This creates some empty integer dicts with default value zero."""
0033 self.instructions = collections.defaultdict(int)
0034 self.translations = collections.defaultdict(int)
0035
0036 def add(self, instr, trans):
0037 """Register the occurrence of an instruction in a translation unit."""
0038 self.instructions[instr] += 1
0039 self.translations[trans] += 1
0040
0041
0042 def oxford_join(lst):
0043 """
0044 Format a list of strings in a human-readable way using an Oxford comma.
0045
0046 This function takes ["a", "b", "c"] to the string "a, b, and c"."""
0047 if not lst:
0048 return ""
0049 elif len(lst) == 1:
0050 return str(lst[0])
0051 elif len(lst) == 2:
0052 return f"{str(lst[0])} and {str(lst[1])}"
0053 return f"{', '.join(lst[:-1])}, and {lst[-1]}"
0054
0055
0056 def run(files, source, build):
0057 """
0058 Perform a search for FP64 instructions in a list of files.
0059
0060 This function takes a list of file paths as well as the root path of the
0061 source code and the build path. These are necessary because the paths
0062 reported in the PTX emitted by NVCC are relative to the build directory. In
0063 order to get the paths relative to the GitHub root directory (which GitHub
0064 Action Commands require), we need to do some path magic."""
0065
0066
0067
0068
0069 counter = collections.defaultdict(InstructionCounter)
0070
0071
0072
0073 source_path = source.resolve()
0074 build_path = build.resolve()
0075
0076
0077
0078
0079 for n in files:
0080
0081
0082 with open(n, "r") as f:
0083 lines = f.read().split("\n")
0084
0085
0086 linedata = None
0087
0088
0089 for l in lines:
0090 if m := re.match(r"^//(?P<file>[/\w\-. ]*):(?P<line>\d+)", l):
0091
0092
0093
0094
0095 linedata = (m.group("file"), int(m.group("line")))
0096 elif m := re.match(
0097 r"^\s*(?P<instruction>(?:[a-z][a-z0-9]*)(?:\.[a-z][a-z0-9]+)*)", l
0098 ):
0099
0100
0101 if "f64" in m.group("instruction"):
0102
0103
0104
0105
0106
0107
0108 real_path = (build_path / linedata[0]).resolve()
0109 if linedata is not None:
0110
0111
0112
0113
0114 try:
0115 counter[
0116 (real_path.relative_to(source_path), linedata[1])
0117 ].add(m.group("instruction"), n)
0118 except ValueError:
0119 pass
0120 else:
0121
0122
0123 counter[None].add(m.group("instruction"), n)
0124
0125
0126
0127
0128 for dt in counter:
0129 instrs = oxford_join(
0130 [f"{counter[dt].instructions[i]} × `{i}`" for i in counter[dt].instructions]
0131 )
0132 units = oxford_join(
0133 [f"`{pathlib.Path(f).name}`" for f in counter[dt].translations]
0134 )
0135 details = (
0136 f"Instruction(s) generated are {instrs} in translation unit(s) {units}."
0137 )
0138
0139
0140
0141 if dt is None:
0142 print(
0143 f"::warning title=FP64 instructions emitted in unknown locations::{details}"
0144 )
0145 else:
0146 print(
0147 f"::warning file={dt[0]},line={dt[1]},title=FP64 instructions emitted::{details}"
0148 )
0149
0150
0151 if __name__ == "__main__":
0152
0153
0154
0155 parser = argparse.ArgumentParser(
0156 description="Find unwanted 64-bit float operations in annotated PTX."
0157 )
0158
0159 parser.add_argument("files", type=str, help="PTX file to use", nargs="+")
0160 parser.add_argument(
0161 "--source", "-S", type=pathlib.Path, help="source directory", required=True
0162 )
0163 parser.add_argument(
0164 "--build", "-B", type=pathlib.Path, help="build directory", required=True
0165 )
0166
0167 args = parser.parse_args()
0168
0169
0170 run(args.files, args.source, args.build)