llvm-project

Форк
0
119 строк · 3.8 Кб
1
#!/usr/bin/env python3
2
#
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 to
11
# update the list of allowed checks. From llvm-project:
12
#   clang-tools-extra/clangd/TidyFastChecks.py --clangd=build-opt/bin/clangd
13
# Be sure to use an optimized, no-asserts, tidy-enabled build of clangd!
14

15
import argparse
16
import os
17
import re
18
import subprocess
19
import sys
20

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 avoids
23
# enabling/disabling checks between releases due to random measurement jitter.
24
FAST_THRESHOLD = 8  # percent
25
SLOW_THRESHOLD = 15
26

27
parser = argparse.ArgumentParser()
28
parser.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
)
34
parser.add_argument(
35
    "--source",
36
    help="Source file to benchmark tidy checks",
37
    default="clang/lib/Sema/Sema.cpp",
38
)
39
parser.add_argument(
40
    "--clangd", help="clangd binary to invoke", default="build/bin/clangd"
41
)
42
parser.add_argument("--checks", help="check glob to run", default="*")
43
parser.add_argument("--verbose", help="log clangd output", action="store_true")
44
args = parser.parse_args()
45

46
# Use the preprocessor to extract the list of previously-fast checks.
47
def read_old_fast(path):
48
    text = subprocess.check_output(
49
        [
50
            "cpp",
51
            "-P",  # Omit GNU line markers
52
            "-nostdinc",  # Don't include stdc-predef.h
53
            "-DFAST(C,T)=C",  # Print fast checks only
54
            path,
55
        ]
56
    )
57
    for line in text.splitlines():
58
        if line.strip():
59
            yield line.strip().decode("utf-8")
60

61

62
old_fast = list(read_old_fast(args.target)) if os.path.exists(args.target) else []
63
print(f"Old fast checks: {old_fast}", file=sys.stderr)
64

65
# Runs clangd --check --check-tidy-time.
66
# Yields (check, percent-overhead) pairs.
67
def 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 = False
78
    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 = True
84
            continue
85
        if b"Finished individual clang-tidy checks" in line:
86
            return
87
        match = re.search(rb"(\S+) = (\S+)%", line)
88
        if match:
89
            yield (match.group(1).decode("utf-8"), float(match.group(2)))
90

91

92
with 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 FAST
98
#define FAST(CHECK, DELTA)
99
#endif
100
#ifndef SLOW
101
#define SLOW(CHECK, DELTA)
102
#endif
103
""",
104
        file=target,
105
    )
106

107
    for check, time in measure():
108
        threshold = SLOW_THRESHOLD if check in old_fast else FAST_THRESHOLD
109
        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 FAST
116
#undef SLOW
117
""",
118
        file=target,
119
    )
120

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.