Skip to content

Commit 3ee651d

Browse files
committed
build: Make genlast write the "split" files
This gets a further speedup of about 2s (12s -> 9.5s elapsed build time) for stm32f405_feather For what are probably historical reasons, the qstr process involves preprocessing a large number of source files into a single "qstr.i.last" file, then reading this and splitting it into one "qstr" file for each original source ("*.c") file. By eliminating the step of writing qstr.i.last as well as making the regular-expression-matching part be parallelized, build speed is further improved. Because the step to build QSTR_DEFS_COLLECTED does not access qstr.i.last, the path is replaced with "-" in the Makefile.
1 parent 3bb5ac2 commit 3ee651d

File tree

2 files changed

+41
-18
lines changed

2 files changed

+41
-18
lines changed

py/genlast.py

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,65 @@
11
#!/usr/bin/env python3
22

33
import sys
4-
from concurrent.futures import ThreadPoolExecutor
4+
import re
5+
import os
6+
from concurrent.futures import ProcessPoolExecutor
57
import multiprocessing
68
import threading
79
import subprocess
810

11+
from makeqstrdefs import qstr_unescape, QSTRING_BLACK_LIST
12+
13+
re_line = re.compile(r"#[line]*\s(\d+)\s\"([^\"]+)\"", re.DOTALL)
14+
re_qstr = re.compile(r'MP_QSTR_[_a-zA-Z0-9]+', re.DOTALL)
15+
re_translate = re.compile(r'translate\(\"((?:(?=(\\?))\2.)*?)\"\)', re.DOTALL)
16+
17+
def write_out(fname, output):
18+
if output:
19+
for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]:
20+
fname = fname.replace(m, r)
21+
with open(output_dir + "/" + fname + ".qstr", "w") as f:
22+
f.write("\n".join(output) + "\n")
23+
24+
def process_file(fname, content):
25+
content = content.decode('utf-8', errors='ignore')
26+
output = []
27+
for match in re_qstr.findall(content):
28+
name = match.replace('MP_QSTR_', '')
29+
if name not in QSTRING_BLACK_LIST:
30+
output.append('Q(' + qstr_unescape(name) + ')')
31+
for match in re_translate.findall(content):
32+
output.append('TRANSLATE("' + match[0] + '")')
33+
34+
write_out(fname, output)
35+
936

1037
def checkoutput1(args):
1138
info = subprocess.run(args, check=True, stdout=subprocess.PIPE, input='')
1239
return info.stdout
1340

1441
idx1 = sys.argv.index('--')
1542
idx2 = sys.argv.index('--', idx1+1)
16-
check = sys.argv[1:idx1]
43+
output_dir = sys.argv[1]
44+
check = sys.argv[2:idx1]
1745
always = sys.argv[idx1+1:idx2]
1846
command = sys.argv[idx2+1:]
1947

20-
output_lock = threading.Lock()
48+
if not os.path.isdir(output_dir):
49+
os.makedirs(output_dir)
50+
2151
def preprocess(fn):
22-
output = checkoutput1(command + [fn])
23-
# Ensure our output doesn't interleave with others
24-
# a threading.Lock is not a context manager object :(
2552
try:
26-
output_lock.acquire()
27-
sys.stdout.buffer.write(output)
28-
finally:
29-
output_lock.release()
53+
output = checkoutput1(command + [fn])
54+
process_file(fn, output)
55+
except Exception as e:
56+
print(e, file=sys.stderr)
3057

3158
def maybe_preprocess(fn):
3259
if subprocess.call(["grep", "-lqE", "(MP_QSTR|translate)", fn]) == 0:
3360
preprocess(fn)
3461

35-
executor = ThreadPoolExecutor(max_workers=multiprocessing.cpu_count() + 1)
62+
executor = ProcessPoolExecutor(max_workers=multiprocessing.cpu_count() + 1)
3663
executor.map(maybe_preprocess, check)
3764
executor.map(preprocess, always)
3865
executor.shutdown()

py/mkrules.mk

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,14 @@ $(OBJ): | $(HEADER_BUILD)/qstrdefs.enum.h $(HEADER_BUILD)/mpversion.h
7676
# - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^)
7777
# - else, if list of newer prerequisites ($?) is not empty, then process just these ($?)
7878
# - else, process all source files ($^) [this covers "make -B" which can set $? to empty]
79-
$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(SRC_QSTR_PREPROCESSOR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h
79+
$(HEADER_BUILD)/qstr.split: $(SRC_QSTR) $(SRC_QSTR_PREPROCESSOR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h $(PY_SRC)/genlast.py
8080
$(STEPECHO) "GEN $@"
81-
$(Q)$(PYTHON3) $(PY_SRC)/genlast.py $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) -- $(SRC_QSTR_PREPROCESSOR) -- $(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) >$(HEADER_BUILD)/qstr.i.last;
82-
83-
$(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last $(PY_SRC)/makeqstrdefs.py
84-
$(STEPECHO) "GEN $@"
85-
$(Q)$(PYTHON3) $(PY_SRC)/makeqstrdefs.py split $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED)
81+
$(Q)$(PYTHON3) $(PY_SRC)/genlast.py $(HEADER_BUILD)/qstr $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) -- $(SRC_QSTR_PREPROCESSOR) -- $(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS)
8682
$(Q)touch $@
8783

8884
$(QSTR_DEFS_COLLECTED): $(HEADER_BUILD)/qstr.split $(PY_SRC)/makeqstrdefs.py
8985
$(STEPECHO) "GEN $@"
90-
$(Q)$(PYTHON3) $(PY_SRC)/makeqstrdefs.py cat $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED)
86+
$(Q)$(PYTHON3) $(PY_SRC)/makeqstrdefs.py cat - $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED)
9187

9288
# $(sort $(var)) removes duplicates
9389
#

0 commit comments

Comments
 (0)