on master help sign in
Add script to find slow-to-highlight files
f2cef70sharkdp
tests/scripts/find-slow-to-highlight-files.pynew file+101
@@ -0,0 +1,101 @@
1+import time
2+import os
3+import subprocess as sp
4+
5+
6+# Threshold speed in chars per second
7+THRESHOLD_SPEED = 20000
8+
9+# Maximum time we allow `bat` to run
10+BAT_TIMEOUT_SEC = 10
11+
12+# Maximum number of files to measure
13+MAX_NUM_FILES = 100
14+
15+# Root folder for the search
16+SEARCH_ROOT = os.getenv("HOME")
17+
18+
19+def find_slow_files(startup_time, language, glob_pattern):
20+ out = sp.check_output(
21+ [
22+ "fd",
23+ "--hidden",
24+ "--no-ignore",
25+ "--type=file",
26+ "--max-results",
27+ str(MAX_NUM_FILES),
28+ "--glob",
29+ glob_pattern,
30+ SEARCH_ROOT,
31+ ]
32+ )
33+
34+ paths = out.split(b"\n")[:-1]
35+ print(f"Language: {language}, glob pattern: {glob_pattern} ({len(paths)} matches)")
36+
37+ for path in paths:
38+ num_chars = int(sp.check_output(["wc", "-c", path]).split(b" ")[0].decode())
39+
40+ if num_chars < 500:
41+ # It is hard to measure the exact speed for short files
42+ continue
43+
44+ try:
45+ start = time.time()
46+ sp.check_output(["bat", "--color=always", path], timeout=BAT_TIMEOUT_SEC)
47+ duration = time.time() - start - startup_time
48+
49+ if duration <= 0:
50+ continue
51+
52+ highlighting_speed = num_chars / duration
53+
54+ if highlighting_speed < THRESHOLD_SPEED:
55+ print(f" {highlighting_speed:10.0f} chars/s: {path.decode()}")
56+
57+ except sp.CalledProcessError:
58+ print(f" Error while highlighting file '{path.decode()}'.")
59+
60+ except sp.TimeoutExpired:
61+ if num_chars < THRESHOLD_SPEED * BAT_TIMEOUT_SEC:
62+ print(f" Error: bat timed out on file '{path.decode()}'.")
63+ else:
64+ print(
65+ f" Warning: bat timed out on file '{path.decode()} (but the file is large)."
66+ )
67+
68+
69+def measure_bat_startup_speed():
70+ min_duration = None
71+ for _ in range(20):
72+ start = time.time()
73+ p = sp.Popen(
74+ ["bat", "--color=always", "--language=py"], stdin=sp.PIPE, stdout=sp.PIPE
75+ )
76+ p.communicate(input=b"test")
77+ duration = time.time() - start
78+
79+ if not min_duration or duration < min_duration:
80+ min_duration = duration
81+
82+ return min_duration
83+
84+
85+def main():
86+ print("Measuring 'bat' startup speed ... ", flush=True, end="")
87+ startup_time = measure_bat_startup_speed()
88+ print(f"{startup_time * 1000:.1f} ms")
89+
90+ output = sp.check_output(["bat", "--list-languages"]).decode()
91+
92+ for line in output.strip().split("\n"):
93+ language, extensions = line.split(":")
94+ for ext in extensions.split(","):
95+ find_slow_files(startup_time, language, ext)
96+ if not ext.startswith("."):
97+ find_slow_files(startup_time, language, f"*.{ext}")
98+
99+
100+if __name__ == "__main__":
101+ main()