Add a ForthMachine to the codebase, copying from 'studies'.#648
Conversation
… OLD, VTABLES-based version is up to 1.8x faster.
…, and calling dictionary words from outside the ForthMachine.
…pause and simplified raise/ignore boolean handling.
…strangely enough.
|
I verified that we still have the 5 ns per instruction. By contrast, Python's virtual machine on compiled bytecodes (similar in kind to what we do) takes ~900 ns per instruction. >>> import dis
>>> def f():
... x = 0
... for i in range(100000):
... x = 10 + x + 10 + x + 10 + x + 10 + x + 10 + x + 10
...
>>> # There are 25 Python bytecode instructions in this loop, which gets repeated 100000 times.
>>> dis.dis(f)
2 0 LOAD_CONST 1 (0)
2 STORE_FAST 0 (x)
3 4 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 2 (100000)
8 CALL_FUNCTION 1
10 GET_ITER
>> 12 FOR_ITER 48 (to 62)
14 STORE_FAST 1 (i)
4 16 LOAD_CONST 3 (10)
18 LOAD_FAST 0 (x)
20 BINARY_ADD
22 LOAD_CONST 3 (10)
24 BINARY_ADD
26 LOAD_FAST 0 (x)
28 BINARY_ADD
30 LOAD_CONST 3 (10)
32 BINARY_ADD
34 LOAD_FAST 0 (x)
36 BINARY_ADD
38 LOAD_CONST 3 (10)
40 BINARY_ADD
42 LOAD_FAST 0 (x)
44 BINARY_ADD
46 LOAD_CONST 3 (10)
48 BINARY_ADD
50 LOAD_FAST 0 (x)
52 BINARY_ADD
54 LOAD_CONST 3 (10)
56 BINARY_ADD
58 STORE_FAST 0 (x)
60 JUMP_ABSOLUTE 12
>> 62 LOAD_CONST 0 (None)
64 RETURN_VALUE
>>> begintime = time.time(); f(); print((time.time() - begintime) * 1e9)
2324416875.8392334
>>> 2324416875.8392334 / (25*100000)
929.7667503356934
>>> begintime = time.time(); f(); print((time.time() - begintime) * 1e9)
2277071237.564087
>>> 2277071237.564087 / (25*100000)
910.8284950256348
>>> begintime = time.time(); f(); print((time.time() - begintime) * 1e9)
2262091398.2391357
>>> 2262091398.2391357 / (25*100000)
904.8365592956543 |
|
For the future: the calculation in #648 (comment) is wrong! Since A function like this: def f():
x = 0
for i in range(100000):
x = 10 + x - 10 + x + 10 + x - 10 + x + 10 + x - 10would walk through the same number of bytecodes (see the See the bottom of https://github.com/jpivarski-talks/2024-08-19-python-school-setting-stage/blob/main/snake-eats-its-tail.ipynb This is still about 40× slower than the throughput of compiled instructions (at Anyway, no more saying, "Python takes 900 ns per instruction"! It takes about 3 ns per instruction. Incidentally, that's on par with AwkwardForth. The difference between Python and AwkwardForth must be due to something else. (Type checks?) |
bytecodesandassembly_instructions.pytest.importorskip("uproot").)Full-scale ROOT parsing measurements are not part of this PR.
Nor is the Avro → Awkward example.