mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 14:16:44 +00:00

This is an ongoing series of commits that are reformatting our Python code. Reformatting is done with `black`. If you end up having problems merging this commit because you have made changes to a python file, the best way to handle that is to run git checkout --ours <yourfile> and then reformat it with black. If you run into any problems, post to discourse about it and we will try to help. RFC Thread below: https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style Reviewed By: MatzeB Differential Revision: https://reviews.llvm.org/D150761
120 lines
3.8 KiB
Python
Executable File
120 lines
3.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Determines which clang-tidy checks are "fast enough" to run in clangd.
|
|
# This runs clangd --check --check-tidy-time and parses the output.
|
|
# This program outputs a header fragment specifying which checks are fast:
|
|
# FAST(bugprone-argument-comment, 5)
|
|
# SLOW(misc-const-correctness, 200)
|
|
# If given the old header fragment as input, we lean to preserve its choices.
|
|
#
|
|
# This is not deterministic or hermetic, but should be run occasionally to
|
|
# update the list of allowed checks. From llvm-project:
|
|
# clang-tools-extra/clangd/TidyFastChecks.py --clangd=build-opt/bin/clangd
|
|
# Be sure to use an optimized, no-asserts, tidy-enabled build of clangd!
|
|
|
|
import argparse
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
# Checks faster than FAST_THRESHOLD are fast, slower than SLOW_THRESHOLD slow.
|
|
# If a check is in between, we stick with our previous decision. This avoids
|
|
# enabling/disabling checks between releases due to random measurement jitter.
|
|
FAST_THRESHOLD = 8 # percent
|
|
SLOW_THRESHOLD = 15
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"--target",
|
|
help="X-macro output file. "
|
|
"If it exists, existing contents will be used for hysteresis",
|
|
default="clang-tools-extra/clangd/TidyFastChecks.inc",
|
|
)
|
|
parser.add_argument(
|
|
"--source",
|
|
help="Source file to benchmark tidy checks",
|
|
default="clang/lib/Sema/Sema.cpp",
|
|
)
|
|
parser.add_argument(
|
|
"--clangd", help="clangd binary to invoke", default="build/bin/clangd"
|
|
)
|
|
parser.add_argument("--checks", help="check glob to run", default="*")
|
|
parser.add_argument("--verbose", help="log clangd output", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
# Use the preprocessor to extract the list of previously-fast checks.
|
|
def read_old_fast(path):
|
|
text = subprocess.check_output(
|
|
[
|
|
"cpp",
|
|
"-P", # Omit GNU line markers
|
|
"-nostdinc", # Don't include stdc-predef.h
|
|
"-DFAST(C,T)=C", # Print fast checks only
|
|
path,
|
|
]
|
|
)
|
|
for line in text.splitlines():
|
|
if line.strip():
|
|
yield line.strip().decode("utf-8")
|
|
|
|
|
|
old_fast = list(read_old_fast(args.target)) if os.path.exists(args.target) else []
|
|
print(f"Old fast checks: {old_fast}", file=sys.stderr)
|
|
|
|
# Runs clangd --check --check-tidy-time.
|
|
# Yields (check, percent-overhead) pairs.
|
|
def measure():
|
|
process = subprocess.Popen(
|
|
[
|
|
args.clangd,
|
|
"--check=" + args.source,
|
|
"--check-locations=0", # Skip useless slow steps.
|
|
"--check-tidy-time=" + args.checks,
|
|
],
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
recording = False
|
|
for line in iter(process.stderr.readline, b""):
|
|
if args.verbose:
|
|
print("clangd> ", line, file=sys.stderr)
|
|
if not recording:
|
|
if b"Timing AST build with individual clang-tidy checks" in line:
|
|
recording = True
|
|
continue
|
|
if b"Finished individual clang-tidy checks" in line:
|
|
return
|
|
match = re.search(rb"(\S+) = (\S+)%", line)
|
|
if match:
|
|
yield (match.group(1).decode("utf-8"), float(match.group(2)))
|
|
|
|
|
|
with open(args.target, "w", buffering=1) as target:
|
|
# Produce an includable X-macros fragment with our decisions.
|
|
print(
|
|
f"""// This file is generated, do not edit it directly!
|
|
// Deltas are percentage regression in parsing {args.source}
|
|
#ifndef FAST
|
|
#define FAST(CHECK, DELTA)
|
|
#endif
|
|
#ifndef SLOW
|
|
#define SLOW(CHECK, DELTA)
|
|
#endif
|
|
""",
|
|
file=target,
|
|
)
|
|
|
|
for check, time in measure():
|
|
threshold = SLOW_THRESHOLD if check in old_fast else FAST_THRESHOLD
|
|
decision = "FAST" if time <= threshold else "SLOW"
|
|
print(f"{decision} {check} {time}% <= {threshold}%", file=sys.stderr)
|
|
print(f"{decision}({check}, {time})", file=target)
|
|
|
|
print(
|
|
"""
|
|
#undef FAST
|
|
#undef SLOW
|
|
""",
|
|
file=target,
|
|
)
|