News for hackers. Stuff that matters.

antocuni

yes (work in progress :))
hello, spy author here.

> Why do blue functions disappear when redshifting? If you red shift blue then it goes down in frequency so you might get green or red. Perhaps my physics brain is just over thinking it!

yes I think you are overthinking :). It's not meant to be accurate physics of course.

The usage of colors to distinguish comptime vs runtim code comes from PyPy: in that context, we used "green" and "red", and initial versions of SPy used the same convention.

Then someone pointed out that green/red is not colorblind friendly and so I changed it to blue.

Having actual colors for the two phases is VERY useful for visualization: e.g. we already have a "spy --colorize" command which shows you which parts are blue and which are red.

As for "redshifting": the AST "before" has a mixture of blue and red colors, while the AST "after" has only red nodes, thus the final AST is "more red" than the first one, that's why I chose that name.

hello, author of the blog post and author of SPy here.

> how can you reliably import libraries?

the blog post specifies it but probably not in great level of detail. Calling python libs from spy will go through libpython.so (so essentially we will embed CPython). So CPython will import the library, and there will be a SPy<=>CPython interop layer to convert/proxy objects on the two worlds.

thank you for the feedback! I wasn't aware of these features of Zulip, there are way too many competing technologies in this space and I miss the days in which everybody was IRC and that's it.
I haven't fully decided which route to take in that direction, but I think I'd like to support something similar do "go": you declare an interface (or, in python typing terms a Protocol) and then all the types which have the right methods automatically implement that interface/protocol
This looks exactly what I'm trying to do with SPy -- although SPy is still "not there" and it's WIP. I literally wrote an intro post about it yesterday: https://antocuni.eu/2025/10/29/inside-spy-part-1-motivations...
Re:Tracing JITs in the Real World CPython Core Dev Sprint on Friday September 26, 2025 @10:48AM (#45387150)
pypy IS compatible with C extensions, via what we call "cpyext": https://doc.pypy.org/en/latest/faq.html#do-c-extension-modul...

The problem of cpyext is that it's super slow, for good reasons: https://pypy.org/posts/2018/09/inside-cpyext-why-emulating-c...

There are efforts to create a new C API which is more friendly to alternative implementations (including CPython itself, when they want to change how they do things internally): https://hpyproject.org/ https://github.com/py-ni

Re:Tracing JITs in the Real World CPython Core Dev Sprint on Friday September 26, 2025 @04:28AM (#45384150)
From many points of view, what CPython JIT can do is a subset of what PyPy can do.

The biggest differences between the two JITs are: 1. PyPy is meta tracing, CPython is tracing 2. PyPy has "standard" code generation backends, CPython has copy&patch. 3. CPython so far uses "trace projection" while PyPy uses "trace recording".

(1+2) make CPython JIT much faster to compile and warmup than PyPy, although I suspect that most of the gain is because of (1). However, this comes at the expense of generality, because in PyPy you can automatically trace across all builtins, whereas in CPython you are limited to the bytecode.

Trace projection looked very interesting to me because it automatically solve a problem which I found everywhere in real world code: if you do trace recording, you don't know whether you will be actually able to close the loop, and so you must decide to give up after a certain threshold ("trace too long"). The problem is that there doesn't seem to be threshold which is generally good, so you always end up tracing too much (big warmup costs + literally you are doing unnecessary work) or not enough (the generated code is less optimal, sometimes up to 5-10x).

With trace projection you decide which loop to optimize "in retrospect" so you don't have that specific problem. However, you have OTHER problems (in particular that you don't know the actual values used in the trace) which makes it harder to optimize, so CPython JIT plans to switch to trace recording.

Re:Tracing JITs in the Real World CPython Core Dev Sprint on Friday September 26, 2025 @04:16AM (#45384079)
(author of the blog post here) "just compile when you know the types" is not a good strategy for Python. My EuroPython talk "Myths and fairy tales about Python performance" explains many reasons why Python is VERY hard to optimize: https://lwn.net/Articles/1031707/

One big advantage of tracing JITs is that they are generally easier to write an to maintain. For the specific case of PyPy, it's actually a "meta tracing JIT": you trace the interpreter, not the underlying program, which TL;DR means that you can write the interpreter (which is "easy") and you get a JIT compiler for free. The basic assumption of a tracing JIT is that you have one or more "hot loops" in which you have one (or few) fast paths which are taken most of the time.

If the assumption holds, tracing has big advantages because you eliminate most of dynamism and you automatically inline across multiple layer of function calls, which in turns make it possible to eliminate allocation of most temporary objects. The problem is that the assumption not always holds, and that's where you start to get problems.

But methods JITs are not THE solution either. Meta has a whole team developing Cinder, which is a method JIT for Python, but they had to introduce what they call "static python", which is an opt-in sets of constraints to remove some Python dynamism to make the JIT job easier.

Finally, as soon as you call any C extension, any JIT is out of luck and must deoptimize to present a "state of the world" which is compatible with that the C extension finds.

Re:Claude code modified my .bashrc without asking on Tuesday July 08, 2025 @10:07AM (#44500141)
this is done by the installation process, not by AI.
Re:A peek into a possible future of Python in the browser on Tuesday February 25, 2025 @04:23PM (#43177614)
(SPy author here) function calls in SPy are as cheap as in C.

You can check by yourself seeing of the spy compiler translates the code to C in the (super-experimental) spy playground: https://antocuni.pyscriptapps.com/spy-playground/latest/

Re:Musings on Tracing in PyPy on Friday January 10, 2025 @10:22AM (#42656395)
PyPy's difficulty with invoking native code is not because of its tracing JIT but because the CPython C API makes it very hard to deviate from _any_ CPython implementation details, including e.g. choice of memory management and precise layout of objects in memory. I wrote extensively about it here: https://pypy.org/posts/2018/09/inside-cpyext-why-emulating-c...

HPy proves that it is indeed possible to have high-performance C extensions with PyPy: https://pypy.org/posts/2019/12/hpy-kick-off-sprint-report-18...

Re:Hello, HPy on Tuesday March 30, 2021 @04:04PM (#26639679)
what is the python implementation you are involved with?

I agree with your concerns, HPy tries to address them since the beginning. Basically, there are two distinct compilation modes: - CPython ABI: in this mode, things like HPy_Dup and HPy_Close are translated directly into Py_INCREF and Py_DECREF. The overhead is 0 both in theory and in practice, since all the benchmark that we ran so far confirmed this.

- HPy Universal ABI: in this mode, you introduce the indirections which makes it possible e.g. the debug mode. Our benchmarks indicate a 5-10% overhead, which is in line with what you (and we :)) expected.

So, if you are an extension writer, you will be able to distribute both CPython-opimized and universal binaries

Re:Hello, HPy on Tuesday March 30, 2021 @10:39AM (#26635102)
We plan to introduce something similar to CPython's argument clinic eventually. I.e., you will be able to declare what is the C signature of your impl function and HPy will generate the argument parsing code automatically.

One nice effect of such an API is that under certain conditions, implementations will be allowed to bypass argument parsing entirely: e.g., if I have a function which takes two C longs, the PyPy JIT will be able to emit a call directly to it, without having to box/unbox the arguments just to do the call as it happens right now.

However, on the other hand we will need to provide an API similar to the existing PyArg_ParseTuple, because we want to make it easy to migrate existing extensions

Re:Hello, HPy on Tuesday March 30, 2021 @04:37AM (#26632338)
We plan to write a porting guide and examples at some point, but we didn't yet, also because we are still in the experimental phase and the API is still subject to change (although it changes less quickly nowadays).

In theory, most of the porting could be automated. The only thing which cannot is turning Py_INCREF/DECREF into HPy_Dup/HPy_Close: they are closely related, but HPy requires that you close each handle independently, contrarily to Python/C where you can DECREF the same PyObject* multiple times, as long as the final refcount is correct.

For that, the debug mode will be very useful because it precisely tells you which handles you didn't close and which ones you closed multiple times.

Re:Hello, HPy on Tuesday March 30, 2021 @04:26AM (#26632283)
hello, OP of the blog post here. Yes, the plan is to write a Cython backend at some point, so that all Cython extensions will benefit from HPy automatically.

The main Cython developer (Stefan Behnel) was present during the very first few meetings where we started to talk about HPy and gave positive feedback on that.