8 ms·
This comes from the following enhancements: - Cheaper, lazy Python frames: 3-7% - Inlined Python function calls: 1-3% - PEP 659: Specializing Adaptive Interp
by Game_Ender 4y ago
This comes from the following enhancements:
- Cheaper, lazy Python frames: 3-7%
- Inlined Python function calls: 1-3%
- PEP 659: Specializing Adaptive Interpreter: variable
The interpreter changes work by generating specialized code so this might have a memory impact which they are working to offset and expect to cap at 20% more.
See the in progress release notes for details: https://docs.python.org/3.11/whatsnew/3.11.html#faster-cpython https://docs.python.org/3.11/whatsnew/3.11.html#faster-cpyth...
- SemanticStrengh 4y agoAre you saying python never inlined functions before??
- giancarlostoro 4y agoI'll assume this is a good faith question and answer it by quoting the "What's new in Python 3.11?" page (linked below the quote). > During a Python function call, Python will call an evaluating C function to interpret that function’s code. This effectively limits pure Python recursion to what’s safe for the C stack. > In 3.11, when CPython detects Python code calling another Python function, it sets up a new frame, and “jumps” to the new code inside the new frame. This avoids calling the C interpreting function altogether. > Most Python function calls now consume no C stack space. This speeds up most of such calls. In simple recursive functions like fibonacci or factorial, a 1.7x speedup was observed. This also means recursive functions can recurse significantly deeper (if the user increases the recursion limit). We measured a 1-3% improvement in pyperformance. https://docs.python.org/3.11/whatsnew/3.11.html#inlined-python-function-calls https://docs.python.org/3.11/whatsnew/3.11.html#inlined-pyth...
- SemanticStrengh 4y agoBTW It'd be nice if python implemented support for tail call recursive or even better, a growable/segmented stack in order to allow arbitrary pythons functions be stack overflow safe. e.g. https://gcc.gnu.org/wiki/SplitStacks#:~:text=Split%20Stacks%20in%20GCC&text=The%20goal%20of%20split%20stacks,as%20required%20by%20the%20program https://gcc.gnu.org/wiki/SplitStacks#:~:text=Split%20Stacks%....
- jleahy 4y agoThere was once stackless python that did this (Eve online was built in it), I don’t know if it still exists though.
- bqmjjx0kac 4y agoNeat! https://en.wikipedia.org/wiki/Stackless_Python https://en.wikipedia.org/wiki/Stackless_Python Sadly, it isn't true parallelism, more like green threads. And they didn't manage to kill the GIL.
- masklinn 4y agoIf Python doesn't depend on the C stack anymore (for most of its work), that's basically what you'll have for free. Python's own stackframes are heap-allocated and chained (so each function has its own stack, in essence), so its use of a single unified allocation space for stack is already an implementation detail of the interpreter.
- SemanticStrengh 4y agonice
- FreakLegion 4y agoWith Python it's possible to do tail-call optimization yourself. See this all-time great Stack Overflow answer and the linked repo for details (the actual code is quite short): https://stackoverflow.com/a/18506625 https://stackoverflow.com/a/18506625.
- BiteCode_dev 4y agoDon't understand why you are being downvoted, coming from another language, it's an understandable surprise. The explanation is that Python features heavy dynamism, meaning one can easily replace any part of the system at runtime (at any moment), including builtins, code objects, and even hook into the parser, AST, import mechanism, etc. This renders inlining a dangerous exercice: say you inline the builtin len() function, how do you know it's not the intent of a code that runs later to replace it with a different implementation? Now, there are ways to implement inlining, but they are not as straightforward as say, with a compiler, when you know nothing is going to change afterward. So it's something that had be delayed.
- SemanticStrengh 4y ago> how do you know it's not the intent of a code that runs later to replace it with a different implementation? I think progress could move forward by adding a compiler flag "assume no fully free function body replacement" you know just like in every other mainstream language.
- BiteCode_dev 4y agoIt's not body replacement, it's function reference erasing. There is no way in Python to tell something has been replaced or not, since variables are dumb labels and a reference is the same kind for any object. In fact, there is no particular difference between 2 objects in python. E.G: functions are objects, and any object can be called as a function. And it's just a reference to "something callable" in the namespace mapping (literally a dict in most implementations), which is mutable by definition Also a compiler flag would not help, since most users don't compile the python VM. Now, you could put a runtime flag, that list all stuff that are created for the first time in a namespace, and refuse to allow reassignment. It's possible, but it would break a LOT of things and prevent many patterns. The last attempt was to put guards, and to assume no replacement, but if a replacement occurs, then at this moment we revert locally this assumption. The process is refined at each iteration, but there is no turn-key solution as you seem to believe.
- masklinn 4y ago
- bjourne 4y agoOther languages do this by sacrificing correctness. If a() calls b() calls c() causes an exception Python will show you the correct callstack. In other languages the callstack will differ depending on whether the compiler decided to inline c() or b() in a(). Same thing with TCO, it destroys callstacks and is therefore incorrect. If one prefers correctness over performance one should use Python. If one doesn't mind sacrificing correctness to gain performance one can use other languages.
- planede 4y agoNot all languages make call stacks observable.
- kaba0 4y agoI’m not sure what language do you mean but Java has observable call stacks and inlines just fine. With JIT, deoptimizations are possible. But sure, for AOT languages it may happen, though stacks there are mostly meaningful only with debug symbols.
- bjourne 4y agoThe vast majority of languages that support inlining do not reconstruct callstacks. Java is one of few exceptions and, like Python, it does not support tco.
- kmod 4y agoBit of context for this: - Cheaper Python frames are enabled by making some semantic changes to the language, mostly by removing some dynamic functionality that no one uses - "Inlined Python function calls" is a bit misleading: Python functions are not inlined, it's the "code that does the bookkeeping for calling a Python function" that is now eliminated for Python-to-Python calls. - The most important part of the specializing interpreter is the attribute caching, which is quite significant Source: I work on Pyston, where we do many similar things (but can't make semantic changes to the language)
- dklend122 4y agoWhat are the goals and positioning of pyston given these other efforts?
- masklinn 4y ago> - Cheaper Python frames are enabled by making some semantic changes to the language, mostly by removing some dynamic functionality that no one uses What dynamic functionalities does no one use?
- oblvious-earth 4y agoNot sure what OP meant but basically internal frame struct has been significantly simplified to contain only essential information required at runtime. If a user is wanting to get or manipulate debugging information then the old frame struct will be generated when this is called.
- gosukiwi 4y agoAh! I remember reading something about self-optimizing interpreters, which is pretty cool. I think it's related to what they call "adaptive interpreter". The interpreter starts out with a generic/slow approach and as it gets more datatype info it uses more specialized and faster implementations.