This repository has no description
1import os
2from pathlib import Path
3from subprocess import run
4from sys import argv
5from time import time_ns
6
7from rich.console import Console
8from rich.table import Table
9
10here = Path(__file__).parent
11
12ignored_tasks = []
13
14compare_with = ""
15if len(argv) > 1:
16 compare_with = Path(argv[1]).read_text(encoding="utf-8").strip()
17 compare_with = {
18 (line.split(",")[0], float(line.split(",")[1]), int(line.split(",")[2]))
19 for line in compare_with.splitlines()[1:]
20 }
21 print(compare_with)
22
23
24def avg(numbers: list[float]):
25 return sum(numbers) / len(numbers)
26
27
28end = 0
29start = 0
30
31if not Path("timings.log").exists():
32 start = time_ns()
33 result = run(
34 ["just", "schedule-hell", here.parent / "out.mp4", "--duration 5", "--resolution 320"],
35 capture_output=True,
36 env=os.environ | {"RUST_LOG": "debug", "RUST_BACKTRACE": "full"},
37 )
38 end = time_ns()
39
40 Path("timings.log").write_bytes(result.stdout + result.stderr)
41
42timings = [
43 line.split(" took ")
44 for line in Path("timings.log").read_text(encoding="utf-8").splitlines()
45 if " took " in line
46]
47
48
49def parse_duration(duration_string: str) -> float:
50 if " " in duration_string:
51 return sum(parse_duration(part) for part in duration_string.split(" "))
52 try:
53 figure = float(duration_string.strip("msµ"))
54 except ValueError:
55 return None
56
57 if "µs" in duration_string:
58 return figure * 1e-3
59 if "ms" in duration_string:
60 return figure
61 if "s" in duration_string:
62 return figure * 1e3
63 else:
64 return figure
65
66 raise ValueError(f"Duration string {duration_string!r} has unsupported unit")
67
68
69timings = [
70 (label.split("] ")[1], parse_duration(timing))
71 for label, timing in timings
72 if parse_duration(timing)
73]
74
75per_function: dict[str, list[float]] = {function: [] for function, _ in timings}
76
77for function, timing in timings:
78 per_function[function].append(timing)
79
80averages: list[tuple[str, float, int]] = [
81 (function, avg(timings), len(timings)) for function, timings in per_function.items()
82] + [
83 ("_Total_", (end - start) / 1e6, 1),
84]
85
86averages.sort(key=lambda item: item[1])
87
88header = ["Tâche", "Durée [ms]", "#"]
89
90if compare_with:
91 formatted_results = []
92 for function, timing_after, count_after in averages:
93 if function not in {function for function, _, _ in compare_with}:
94 continue
95 timing_before = next(
96 (timing for fn, timing, _ in compare_with if fn == function),
97 None,
98 )
99 count_before = next(
100 (count for fn, _, count in compare_with if fn == function),
101 None,
102 )
103 if timing_before is None or count_before is None:
104 continue
105 if function in ignored_tasks:
106 continue
107
108 formatted_results.append(
109 [
110 function,
111 f"{timing_after:.3f}",
112 f"{timing_before:.3f}",
113 (
114 f"{timing_after - timing_before:+.3f}"
115 if f"{timing_after - timing_before:.3f}" != "-0.000"
116 else "±0"
117 ),
118 f"{count_after}",
119 f"{count_before}",
120 (
121 f"{count_after - count_before:+}"
122 if count_after != count_before
123 else "±0"
124 ),
125 ]
126 )
127
128 header = [
129 "Tâche",
130 "Durée [ms]",
131 "Durée [ms] avant",
132 "Différence [±ms]",
133 "# après",
134 "# avant",
135 "Différence",
136 ]
137else:
138 formatted_results = [
139 [function, f"{timing:.3f}", f"{count}"] for function, timing, count in averages
140 ]
141
142
143def to_csv(lists: list[list[str]]):
144 return "\r\n".join(
145 ",".join(cell.replace(",", "_") for cell in line) for line in lists
146 )
147
148
149table = Table(*header)
150for row in formatted_results:
151 table.add_row(*row)
152Console().print(table)
153
154Path("results.csv").write_text(
155 to_csv(
156 [
157 header,
158 *[
159 [task, *things]
160 for task, *things in formatted_results
161 if task not in ignored_tasks
162 ],
163 ]
164 ),
165 encoding="utf8",
166)