Skip to content

Commit d439216

Browse files
Make the heap measurement independent of where the repo is cloned
With the memory job finally running, it reported 50K against a 48K budget -- where the same command on my machine reports 47K, on the same commit and the same interpreter. The game was not the variable. probe() inserted the work directory into sys.path as an absolute path, and a GitHub runner checks out to a deeper one. A couple of hundred extra bytes at the baseline pushes a parse allocation over a GC chunk boundary, and the reported minimum jumps three kilobytes. Measured directly: padding the path from 38 to 87 characters moved the answer from 47K to 50K with no other change. A bench whose answer depends on the depth of the checkout is not measuring the program. The probe now runs with the work directory as its cwd and touches sys.path not at all -- MicroPython's default already starts with '' -- so the stubs are staged next to the modules. 47K at 38, 87, 111 and 143 characters of path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AKLqS4PgnCXrzKHDH8Cnzy
1 parent 0c02d9a commit d439216

4 files changed

Lines changed: 34 additions & 8 deletions

File tree

‎.gitignore‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ build/
1010
tools/mp/micropython
1111
tools/mp/micropython-src/
1212
tools/mp/work/
13-
tools/mp/stubs/_probe.py
1413
pc/**/__pycache__/
1514
pc/.venv/
1615
pc/build/

‎docs/OPTIMIZATION.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ que personne le remarque. Epsilon n'embarque ni l'un ni l'autre, alors le build
4141
les désactive : la compilation passe de « à réparer à la main » à quinze
4242
secondes, et la mesure tourne à chaque commit.
4343

44+
Et une fois qu'elle a tourné, elle a annoncé **50 Ko** là où la même commande
45+
en annonçait 47 sur cette machine. Le jeu n'y était pour rien : la sonde
46+
insérait le dossier de travail dans `sys.path`, en absolu. Sur un runner GitHub
47+
ce chemin est plus long ; quelques centaines d'octets de plus au départ, une
48+
allocation de l'analyseur qui franchit une frontière de bloc, et le minimum
49+
mesuré saute de 3 Ko. Un banc de mesure dont la réponse dépend de l'endroit où
50+
le dépôt est cloné ne mesure pas le programme. La sonde tourne désormais avec
51+
le dossier de travail pour répertoire courant — `sys.path` de MicroPython
52+
commence déjà par `''` — et ne manipule plus aucun chemin : 47 Ko, quelle que
53+
soit la profondeur du clone.
54+
4455
Le build local est en 64 bits, donc ses pointeurs sont deux fois plus larges que
4556
ceux du ARM 32 bits de la calculatrice ; l'arbre syntaxique, qui est presque
4657
entièrement fait de pointeurs, coûte environ 1,6 fois plus ici. Le budget de

‎pc/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ le même échantillon.
117117
| Effet | RMS |
118118
|---|---|
119119
| Alerte boss | 0,164 |
120-
| Explosion | 0,041 |
121120
| Tir ennemi | 0,042 |
121+
| Explosion | 0,041 |
122122
| **Tir joueur** | **0,016** |
123123

124124
### `M` : trois crans, pas deux

‎tools/memcheck.py‎

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"""
2121

2222
import os
23+
import shutil
2324
import subprocess
2425
import sys
2526

@@ -34,19 +35,30 @@
3435

3536

3637
def probe(heap_k, entry, workdir):
37-
src = ("import kandinsky, ion, time, gc, sys\n"
38-
"sys.path.insert(0, %r)\n"
38+
"""Import `entry` on a heap of exactly `heap_k` KB. Returns None if it did
39+
not fit.
40+
41+
Nothing here mentions an absolute path. An earlier version inserted the
42+
work directory into sys.path, which made the answer depend on how deep the
43+
checkout sat: the longer string shifted the baseline by a couple of hundred
44+
bytes, that pushed a parse allocation over a chunk boundary, and the
45+
reported minimum jumped 3 KB. Same game, different number, depending on the
46+
machine. The interpreter runs with the work directory as its own cwd
47+
instead, and MicroPython's default sys.path already starts with '', so the
48+
modules and the stubs are found with no path string at all.
49+
"""
50+
src = ("import kandinsky, ion, time, gc\n"
3951
"gc.collect()\n"
4052
"b = gc.mem_free()\n"
4153
"import %s\n"
4254
"gc.collect()\n"
43-
"print('OK', b - gc.mem_free(), gc.mem_free())\n" % (workdir, entry))
44-
path = os.path.join(STUBS, "_probe.py")
55+
"print('OK', b - gc.mem_free(), gc.mem_free())\n" % entry)
56+
path = os.path.join(workdir, "_probe.py")
4557
with open(path, "w") as fh:
4658
fh.write(src)
4759
try:
4860
r = subprocess.run([MP, "-X", "heapsize=%dk" % heap_k, "_probe.py"],
49-
capture_output=True, text=True, cwd=STUBS, timeout=90)
61+
capture_output=True, text=True, cwd=workdir, timeout=90)
5062
except subprocess.TimeoutExpired:
5163
return None
5264
if r.stdout.startswith("OK"):
@@ -96,11 +108,15 @@ def main(argv):
96108
workdir = os.path.join(ROOT, "tools", "mp", "work")
97109
os.makedirs(workdir, exist_ok=True)
98110

99-
# Every dist/*.py module must be importable, so stage them all.
111+
# Every dist/*.py module must be importable, so stage them all -- and the
112+
# kandinsky/ion stubs beside them, since the probe imports by cwd alone.
100113
dist = os.path.join(ROOT, "dist")
101114
for f in sorted(os.listdir(dist)):
102115
if f.endswith(".py"):
103116
prepare(os.path.join(dist, f), workdir)
117+
for f in sorted(os.listdir(STUBS)):
118+
if f.endswith(".py") and not f.startswith("_"):
119+
shutil.copyfile(os.path.join(STUBS, f), os.path.join(workdir, f))
104120

105121
print("%-22s %8s %10s %10s %8s" %
106122
("module", "bytes", "min heap", "resident", "verdict"))

0 commit comments

Comments
 (0)