experimental SVG-based video rendering engine made for music videos. React to MIDI or arbitrary signals from your DAW through "probe" VSTs
at main 4.4 kB view raw
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)