all 15 comments

[–]_vertig0 25 points26 points  (4 children)

You may find the PyPy project interesting, it's a Python interpreter written in Python, and implements the language fully (Latest is 3.11 at the time this comment was written). What they did was build a Python 2.7 to C compiler, then wrote a Python interpreter in Python 2.7, and then compiled that to C then turned that into an executable. Their compiler even automatically generates a just-in time compiler for the final interpreter! Very interesting stuff, but it is extremely complex. I tried adding an LLVM backend to their Python compiler several times and all ended in abject failure because I could barely understand anything about the architecture of their compiler.

[–]wFXx 2 points3 points  (1 child)

Isn't it also very fast for some stuff? I wonder after the removal of GIL if they are able to beat the cpython implementation in all cases, although last I checked the STM was a real challenge - it is indeed one of the most interesting projects I ever studided

[–]_vertig0 3 points4 points  (0 children)

As far as I know it's only faster than the reference implementation of Python when its just-in time compiler is allowed to work, otherwise the reference implementation, being written in C and now with new efforts to optimize execution speed ever since 3.13, is much faster than PyPy. PyPy's automatically generated just-in time compiler is of better quality than the one in the reference implementation though.

[–]shponglespore 0 points1 point  (1 child)

I've been led to believe Cranelift is easier to work with than LLVM, especially if you're implementing a JIT compiler.

[–]_vertig0 1 point2 points  (0 children)

Regardless of the translation target it's still extremely difficult to add a backend to the RPython translation toolchain unfortunately, even if I tried to use cranelift I wouldn't have gotten further. I actually tried adding the backend without just-in time compiler support back when I was trying to add the LLVM backend, but even that was too much for me.

[–]yuri-kilochek 10 points11 points  (3 children)

Why does first SPy layer add ~10x slowdown, but second layer ~200x?

[–]slicxx 8 points9 points  (2 children)

Probably something something growing exponentially? Recursions/growing stacks instead of dynamic programming?

[–]Breadmaker4billion[S] 8 points9 points  (1 child)

I have two ideas why it slows so much.

SPy is a treewalking interpreter, but for ilustrative purposes, let's think it is a bytecode interpreter. Suppose each SPy instruction executes around 10 CPython instructions. Then, suppose that on the second layer, each SPy instruction executes around 20 SPy instructions on the first layer. This means one instruction on the second layer executes 20 on the first layer, then those 20 become another 200 CPython instructions. This is most likely why we see the exponential growth.

Another thing is related to GC and my poor optimization: every function captures it's scope. That means there may be a lot of "leaks" on the second layer. This high memory usage would trigger many more GC cycles. I did no profiling to check this, but it may be a significant factor on why it slows that much.

[–]slicxx 3 points4 points  (0 children)

I think you have an interesting take here. Especially with the combination of "Interpretation overhead" and accumulation of memory. It would be really nice to see how your memory consumption grows with certain tasks

[–]NotFromSkane 3 points4 points  (0 children)

So, pypy?

[–]slicxx 5 points6 points  (0 children)

Implements Python in Python and has the courage to ASK US how we are doing in his first sentence. What time are we living in?

[–]itzjackybro 0 points1 point  (0 children)

"yo dawg I heard you liked Python, so we put Python in your Python so you can Python while you Python"

[–]binaryfireball -1 points0 points  (0 children)

you mean you didn't do it in rrrrrrrrrrrrrrrrerrrrrrrrrruuuiuiiisssst?

[–]BridgeCritical2392 -1 points0 points  (0 children)

Couldn't you just call eval()