55import re
66import subprocess
77import sys
8+ from collections import Counter
89from pathlib import Path
910
1011NAME = "build"
@@ -28,13 +29,13 @@ def run(*command: str) -> None:
2829 sys .exit (result .returncode )
2930
3031
31- def run_stderr (* command : str ) -> str :
32+ def run_capture (* command : str ) -> tuple [ str , str ] :
3233 result = subprocess .run (command , capture_output = True , encoding = "utf-8" )
3334 if result .returncode != 0 :
3435 print (result .stdout , end = "" , file = sys .stdout )
3536 print (result .stderr , end = "" , file = sys .stderr )
3637 sys .exit (result .returncode )
37- return result .stderr
38+ return result .stdout , result . stderr
3839
3940
4041def get_module (setup : Path ) -> str :
@@ -48,41 +49,78 @@ def count_lines(module: str, path: Path) -> None:
4849 save_result (f"{ NAME } /module/{ module } //lines" , lines )
4950
5051
52+ def count_bytes (module : str , path : Path , suffix : str ) -> None :
53+ try :
54+ bytes = path .with_suffix (suffix ).stat ().st_size
55+ except FileNotFoundError :
56+ return
57+ save_result (f"{ NAME } /module/{ module } //bytes { suffix } " , bytes , "B" )
58+
59+
5160def run_lean (module : str ) -> None :
52- stderr = run_stderr (
61+ stdout , stderr = run_capture (
5362 f"{ BENCH } /measure.py" ,
5463 * ("-t" , f"{ NAME } /module/{ module } " ),
5564 * ("-o" , f"{ OUT } " ),
5665 * ("-m" , "instructions" ),
66+ * ("-m" , "cycles" ),
5767 "--" ,
58- * (f"{ STAGE2 } /bin/lean.wrapped" , "--profile" , "-Dprofiler.threshold=9999999" ),
68+ f"{ STAGE2 } /bin/lean.wrapped" ,
69+ * ("--profile" , "-Dprofiler.threshold=9999999" ),
70+ "--stat" ,
5971 * sys .argv [1 :],
6072 )
6173
74+ # Output of `lean --profile`
75+ # See timeit.cpp for the time format
6276 for line in stderr .splitlines ():
63- # Output of `lean --profile`
64- # See timeit.cpp for the time format
6577 if match := re .fullmatch (r"\t(.*) ([\d.]+)(m?s)" , line ):
6678 name = match .group (1 )
6779 seconds = float (match .group (2 ))
6880 if match .group (3 ) == "ms" :
6981 seconds = seconds / 1000
7082 save_result (f"{ NAME } /profile/{ name } //wall-clock" , seconds , "s" )
7183
84+ # Output of `lean --stat`
85+ stat = Counter [str ]()
86+ for line in stdout .splitlines ():
87+ if match := re .fullmatch (r"number of (imported .*):\s+(\d+)$" , line ):
88+ name = match .group (1 )
89+ count = int (match .group (2 ))
90+ stat [name ] += count
91+ for name , count in stat .items ():
92+ if count > 0 :
93+ if name .endswith ("bytes" ):
94+ save_result (f"{ NAME } /stat/{ name } //bytes" , count , "B" )
95+ else :
96+ save_result (f"{ NAME } /stat/{ name } //amount" , count )
97+
7298
7399def main () -> None :
74100 parser = argparse .ArgumentParser ()
75101 parser .add_argument ("lean" , type = Path )
76102 parser .add_argument ("--setup" , type = Path )
103+ parser .add_argument ("--i" , "-i" , type = Path )
104+ parser .add_argument ("--o" , "-o" , type = Path )
77105 args , _ = parser .parse_known_args ()
78106
79107 lean : Path = args .lean
80108 setup : Path = args .setup
109+ ilean : Path | None = args .i
110+ olean : Path | None = args .o
81111
82112 module = get_module (setup )
113+
83114 count_lines (module , lean )
84115 run_lean (module )
85116
117+ if ilean is not None :
118+ count_bytes (module , ilean , ".ilean" )
119+ if olean is not None :
120+ count_bytes (module , olean , ".olean" )
121+ count_bytes (module , olean , ".olean.server" )
122+ count_bytes (module , olean , ".olean.private" )
123+
86124
87125if __name__ == "__main__" :
88126 main ()
0 commit comments