brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.8 KiB · b544551 Raw
120 lines · python
1#!/usr/bin/env python32#3# Determines which clang-tidy checks are "fast enough" to run in clangd.4# This runs clangd --check --check-tidy-time and parses the output.5# This program outputs a header fragment specifying which checks are fast:6#   FAST(bugprone-argument-comment, 5)7#   SLOW(misc-const-correctness, 200)8# If given the old header fragment as input, we lean to preserve its choices.9#10# This is not deterministic or hermetic, but should be run occasionally to11# update the list of allowed checks. From llvm-project:12#   clang-tools-extra/clangd/TidyFastChecks.py --clangd=build-opt/bin/clangd13# Be sure to use an optimized, no-asserts, tidy-enabled build of clangd!14 15import argparse16import os17import re18import subprocess19import sys20 21# Checks faster than FAST_THRESHOLD are fast, slower than SLOW_THRESHOLD slow.22# If a check is in between, we stick with our previous decision. This avoids23# enabling/disabling checks between releases due to random measurement jitter.24FAST_THRESHOLD = 8  # percent25SLOW_THRESHOLD = 1526 27parser = argparse.ArgumentParser()28parser.add_argument(29    "--target",30    help="X-macro output file. "31    "If it exists, existing contents will be used for hysteresis",32    default="clang-tools-extra/clangd/TidyFastChecks.inc",33)34parser.add_argument(35    "--source",36    help="Source file to benchmark tidy checks",37    default="clang/lib/Sema/Sema.cpp",38)39parser.add_argument(40    "--clangd", help="clangd binary to invoke", default="build/bin/clangd"41)42parser.add_argument("--checks", help="check glob to run", default="*")43parser.add_argument("--verbose", help="log clangd output", action="store_true")44args = parser.parse_args()45 46# Use the preprocessor to extract the list of previously-fast checks.47def read_old_fast(path):48    text = subprocess.check_output(49        [50            "cpp",51            "-P",  # Omit GNU line markers52            "-nostdinc",  # Don't include stdc-predef.h53            "-DFAST(C,T)=C",  # Print fast checks only54            path,55        ]56    )57    for line in text.splitlines():58        if line.strip():59            yield line.strip().decode("utf-8")60 61 62old_fast = list(read_old_fast(args.target)) if os.path.exists(args.target) else []63print(f"Old fast checks: {old_fast}", file=sys.stderr)64 65# Runs clangd --check --check-tidy-time.66# Yields (check, percent-overhead) pairs.67def measure():68    process = subprocess.Popen(69        [70            args.clangd,71            "--check=" + args.source,72            "--check-locations=0",  # Skip useless slow steps.73            "--check-tidy-time=" + args.checks,74        ],75        stderr=subprocess.PIPE,76    )77    recording = False78    for line in iter(process.stderr.readline, b""):79        if args.verbose:80            print("clangd> ", line, file=sys.stderr)81        if not recording:82            if b"Timing AST build with individual clang-tidy checks" in line:83                recording = True84            continue85        if b"Finished individual clang-tidy checks" in line:86            return87        match = re.search(rb"(\S+) = (\S+)%", line)88        if match:89            yield (match.group(1).decode("utf-8"), float(match.group(2)))90 91 92with open(args.target, "w", buffering=1) as target:93    # Produce an includable X-macros fragment with our decisions.94    print(95        f"""// This file is generated, do not edit it directly!96// Deltas are percentage regression in parsing {args.source}97#ifndef FAST98#define FAST(CHECK, DELTA)99#endif100#ifndef SLOW101#define SLOW(CHECK, DELTA)102#endif103""",104        file=target,105    )106 107    for check, time in measure():108        threshold = SLOW_THRESHOLD if check in old_fast else FAST_THRESHOLD109        decision = "FAST" if time <= threshold else "SLOW"110        print(f"{decision} {check} {time}% <= {threshold}%", file=sys.stderr)111        print(f"{decision}({check}, {time})", file=target)112 113    print(114        """115#undef FAST116#undef SLOW117""",118        file=target,119    )120