Skip to content

Commit 2baa4c2

Browse files
Merge pull request #57 from MarcellPerger1/refactor
Repurpose main.py into a mini-benchmark
2 parents b098a1a + 76716eb commit 2baa4c2

File tree

4 files changed

+116
-70
lines changed

4 files changed

+116
-70
lines changed

.github/workflows/run_tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ jobs:
2727
run: |
2828
chmod +x ./run_tests.sh
2929
./run_tests.sh --verbose
30+
- name: Run mini-benchmark
31+
run: |
32+
python ./benchmark.py

benchmark.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import cProfile
2+
import contextlib
3+
import time
4+
5+
from parser.astgen.ast_node import AstProgramNode
6+
from parser.astgen.astgen import AstGen
7+
from parser.common.tree_print import tformat
8+
from parser.cst.nodes import ProgramNode
9+
from parser.cst.treegen import TreeGen
10+
from parser.lexer import Tokenizer, format_tokens
11+
from util import readfile
12+
13+
PROFILER = True
14+
15+
16+
class _Timer:
17+
_start = _end = None
18+
19+
def __enter__(self):
20+
self._start = time.perf_counter()
21+
return self
22+
23+
def __exit__(self, exc_type, exc_val, exc_tb):
24+
self._end = time.perf_counter()
25+
26+
def get(self):
27+
return self._end - self._start
28+
29+
30+
class BenchOnce:
31+
_tokenizer: Tokenizer
32+
_cstgen: TreeGen
33+
_cst: ProgramNode
34+
_ast: AstProgramNode
35+
36+
def __init__(self, src: str, idx: int = -1, do_ast=True):
37+
self.src = src
38+
self.idx = idx
39+
self.should_do_ast = do_ast
40+
self.lines: list[tuple[float, str]] = [] # First item used as key
41+
42+
@classmethod
43+
def _fmt_time_taken(cls, name: str, delta_sec: float):
44+
return f'{name:<17} done in {delta_sec * 1000:.2f}ms'
45+
46+
@classmethod
47+
def _maybe_profiler(cls):
48+
if PROFILER:
49+
return cProfile.Profile()
50+
return contextlib.nullcontext(None)
51+
52+
def run(self):
53+
with self._maybe_profiler() as p:
54+
self.do_tokenize()
55+
self.do_token_fmt()
56+
self.do_cst()
57+
self.do_cst_fmt()
58+
if self.should_do_ast:
59+
self.do_ast()
60+
self.do_ast_fmt()
61+
if p:
62+
p.dump_stats(f'perf_dump_{self.idx}.prof')
63+
print(f'Perf for idx={self.idx} ({PROFILER=}):')
64+
for _k, s in sorted(self.lines):
65+
print(f' {s}')
66+
67+
def _add_line(self, sort_key: float, name: str, delta_sec: float):
68+
self.lines.append((sort_key, self._fmt_time_taken(name, delta_sec)))
69+
70+
def do_tokenize(self):
71+
with _Timer() as t:
72+
self._tokenizer = Tokenizer(self.src).tokenize()
73+
self._add_line(0.0, 'Tokens', t.get())
74+
75+
def do_token_fmt(self):
76+
with _Timer() as t:
77+
_s = format_tokens(self.src, self._tokenizer.tokens, True)
78+
self._add_line(0.5, 'Tokens_fmt', t.get())
79+
80+
def do_cst(self):
81+
with _Timer() as t:
82+
self._cstgen = TreeGen(self._tokenizer)
83+
self._cst = self._cstgen.parse()
84+
self._add_line(1.0, 'CST', t.get())
85+
86+
def do_cst_fmt(self):
87+
with _Timer() as t:
88+
_s = tformat(self._cst)
89+
self._add_line(1.5, 'CST_fmt', t.get())
90+
91+
def do_ast(self):
92+
with _Timer() as t:
93+
self._ast = AstGen(self._cstgen).parse()
94+
self._add_line(2.0, 'AST', t.get())
95+
96+
def do_ast_fmt(self):
97+
with _Timer() as t:
98+
_s = tformat(self._ast)
99+
self._add_line(2.5, 'AST_fmt', t.get())
100+
101+
102+
def benchmark(src: str, idx: int = -1, do_ast=True):
103+
return BenchOnce(src, idx, do_ast).run()
104+
105+
106+
def main():
107+
benchmark(readfile('main_example_0.st'), 0, do_ast=False)
108+
benchmark(readfile('main_example_1.st'), 1)
109+
110+
111+
if __name__ == '__main__':
112+
main()

main.py

Lines changed: 0 additions & 69 deletions
This file was deleted.

parser/astgen/astgen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class AstGen:
8787
def __init__(self, cst: CstGen):
8888
self.cst = cst
8989
self.src = self.cst.src
90-
self.result: AstNode | None = None
90+
self.result: AstProgramNode | None = None
9191

9292
def parse(self):
9393
if not self.result:

0 commit comments

Comments
 (0)