10 ms·
Python is 1.3x faster by just adjusting some compiling options for libpython
- kevingadd 5y agoAnyone got an archive link? I can't read this without making a Facebook account and signing in
- eptcyka 5y agoI read it without signing in. The "Not now" link is greyed out and 4 points smaller and not a button. But it's there.
- mct 5y agoI'm seeing "You must log in to continue," with no "not now" option.
- qwertox 5y agoProbably expects JavaScript enabled or something. I also don't have a "not now" option. No JavaScript, no CSS. Honestly, how can someone into tech post something like this on FB?
- OJFord 5y agoLeaving aside whether or not they should want to post it there, I'm surprised it has an audience. Someone saw it and shared it to HN; enough read it to upvote it this much.. maybe Facebook's more popular than I thought! (That sounds silly or sarcastic, but 'among HN users and similar' I'm serious.)
- ineedasername 5y agoI did the first time around, but then I closed the tab, and when I wanted to go back to look at something in more detail I was blocked unless I signed in. Luckily someone posted the full text in another comment.
- Someone 5y agoI think I get to see the full text in iOS private mode without logging in. Didn’t have to click away anything, either.
- stereo 5y agoText if you don't want to visit Facebook: Summary: Python is 1.3x faster when compiled in a way that re-examines shitty technical decisions from the 1990s. ELF is the executable and shared library format on Linux and other Unixy systems. It comes to us from 1992's Solaris 2.0, from back before even the first season of the X-Files aired. ELF files (like X-Files) are full of barely-understood horrors described only in dusty old documents that nobody reads. If you don't know anything about symbol visibility, semantic interposition, relocations, the PLT, and the GOT, ELF will eat your program's performance. (Granted, that's better than being eaten by some monster from a secret underground government base.) ELF kills performance because it tries too hard to make the new-in-1992 world of dynamic linking look and act like the old world of static linking. ELF goes to tremendous lengths to make sure that every reference to a function or a variable throughout a process refers to the same function or variable no matter what shared library contains each reference. Everything is consistent. This approach is clean, elegant, and wrong: the cost of maintaining this ridiculous bijection between symbol name and symbol address is that each reference to a function or variable needs to go through a table of pointers that the dynamic linker maintains --- even when the reference is one function in a shared library calling another function in the same shared library. Yes, `mylibrary_foo()` in `libmylibrary.so` has to pay for the equivalent of a virtual function call every time it calls `mylibrary_bar()` just in case some other shared library loaded earlier happened to provide a different `mylibrary_bar()`. That basically never happens. (Weak symbols are an exception, but that's a subject for a different rant.) (Windows took a different approach and got it right. In Windows, it's okay for multiple DLLs to provide the same symbol, and there's no sad and desperate effort to pretend that a single namespace is still cool.) There's basically one case where anyone actually relies on this ELF table lookup stuff (called "interposition"): `LD_PRELOAD`. `LD_PRELOAD` lets you provide your own implementation of any function in a program by pre-loading a shared library containing that function before a program starts. If your `LD_PRELOAD`ed library provides a `mylibrary_bar()`, the ELF table lookup goo will make sure that `mylibrary_foo()` calls your `LD_PRELOAD`ed `mylibrary_bar()` instead of the one in your program. It's nice and dynamic, right? In exchange for every program on earth being massively slower than it has to be all the time, you, programmer, can replace `mylibrary_bar()` with `printf("XXX calling bar!!!")` by setting an environment variable. Good trade-off, right? LOL. There is no trade-off. You don't get to choose between performance and flexibility. You don't get to choose one. You get to choose zero things. Interposition has been broken for years: a certain non-GNU upstart compiler starting with "c" has been committing the unforgivable sin of optimizing calls between functions in the same shared library. Clang will inline that call from `mylibrary_foo()` to `mylibrary_bar()`, ELF be damned, and it's right to do so, because interposition is ridiculous and stupid and optimizes for c00l l1inker tr1ckz over the things people buy computers to actually do --- like render 314341 layers of nested iframe. Still, this Clang thing does mean that `LD_PRELOAD` interposition no longer affects all calls, because with Clang, contra the specification, will inline some calls to functions not marked inline --- which breaks some people's c00l l1inker tr1ckz . But we're all still paying the cost of PLT calls and GOT lookups anyway, all to support a feature (`LD_PRELOAD`) that doesn't even work reliably anymore, because, well, why change the defaults? Eventually, someone working on Python (ironically, of all things) noticed this waste of good performance. "Let's tell the compiler to do what Clang does accidentally, but all the time, and on purpose". Python got 30% faster without having to touch a single line of code in the Python interpreter. (This state of affairs is clearly evidence in favor of the software industry's assessment of its own intellectual prowess and justifies software people randomly commenting on things outside their alleged expertise.) All programs should be built with `-Bsymbolic` and `-fno-semantic-interposition`. All symbols should be hidden by default. `LD_PRELOAD` still works in this mode, but only for calls _between_ shared libraries, not calls _inside_ shared libraries. One day, I hope as a profession we learn to change the default settings on our tools.
- Scaevolus 5y agoThis is true for _libpython_ (the shared library version), which is the default on some distros (RedHat, Fedora, Arch), but many others (Debian, Ubuntu) use statically linked Python and never paid this performance tax.
- dheera 5y agoI think using Pypy instead of CPython will give you several times the performance boost as any of this.
- dathinab 5y agoLikely, but it doesn't work with all applications.
- dharmab 5y agoPypy is not a drop-in replacement for CPython. It does not support many libraries that rely on C extensions, and targets a slightly older version of the language.
- nwmcsween 5y agoAssuming pypy does what it says it does: Python -> RPython -> C -> LLVM Clang -> LLVM IR -> 'JIT', you're still paying a large tax compared to something like RPython -> Some IR -> 'JIT'
- joshuamorton 5y agoI think you've misinterpreted something. The pypy interpreter is written in rpython, but executed code itself never gets translated to rpython.
- coldtea 5y agoNow you have 10 problems. A reference to the classic line, oft attributed to JWZ: "Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems". The point being, switching from CPython to PyPy does not simply give you the performance boost and that's it. It comes with its own tradeoffs, including: (a) trading speed for much more memory consumption (b) slower C FFI - important for all kinds of Python workflows (e.g. Pandas, Numpy, and so on) (c) behind mainline CPython releases, and with subtle incompatibilities (d) slower startup times (due to the JITting involved) (e) different garbage collection model (and less predictable) (f) less support (from companies, distros, etc), fewer ports, less manpower to port quickly to new platforms (e.g. Apple's M1).
- th0ma5 5y agoNot entirely related but I recently started playing with the built in "dis" library and it is fun to see the compiled representation of functions that the runtime executes. Just an FYI if you're ever bored and are looking to get more familiar with assembly, it is a very approachable thing to play with.
- geofft 5y agoRelated: https://developers.redhat.com/blog/2020/06/25/red-hat-enterprise-linux-8-2-brings-faster-python-3-8-run-speeds https://developers.redhat.com/blog/2020/06/25/red-hat-enterp... > This article focuses on one specific performance improvement in the python38 package. As we'll explain, Python 3.8 is built with the GNU Compiler Collection (GCC)'s -fno-semantic-interposition flag. Enabling this flag disables semantic interposition, which can increase run speed by as much as 30%. (not logged in to FB, so maybe TFA is a reference to this one?)
- Dylan16807 5y agoAlso https://pythonspeed.com/articles/faster-python/ https://pythonspeed.com/articles/faster-python/ And having just read that yesterday, I was very confused to open this post and immediately see complaints about the author's tone.
- jchw 5y agoThere’s nothing wrong with this post factually, but the tone sucks. It has an immensely combative energy for what is not really a charged subject matter. Like sure. Today, a lot of the historical reasons for things seem silly and irrelevant. At one point, they did not seem silly and irrelevant. For compatibility with stuff sticking around from those days, we get some performance penalties that are not strictly necessary. I don’t think anyone is doing that to be an asshole, so the oddly antagonistic tone seems unjustified. And yes, Windows with a module-level namespace is cleaner in this regard, but Windows design is entirely different and has plenty of its own skeletons. ELF does not, to me, feel significantly more horrible than PE. And I’m not speaking from inexperience; I did at least write a couple of ELF and PE parsing softwares over time, most recently go-winloader[1]. Do we need to override symbols in the same library? Probably not... kind of. Your modules may in fact not need this. However, libc probably does. Take a look at what symbols libpthread exports on your system some time. I hate to be the person to point this out, but please consider not approaching subjects from this position. It feels alienating, and I have no idea why it’s necessary to have such a tone. [1]: https://github.com/jchv/go-winloader https://github.com/jchv/go-winloader
- fpgaminer 5y agoNot OP, but I read the "antagonistic" style of the post as just the usual catharsis humor. All in-jest. I've used that style of writing plenty before. It's a good way to blow off the steam of working with these rather absurd, archaic systems that we have to tackle on a daily basis. Programming can feel a bit kafkaesque at times, so a bit of aggressive/dark humor goes a long way. But I do agree, it felt too thick. Still a very interesting topic regardless.
- hn_throwaway_99 5y agoThe problem I see is that I often see this type of detached, "wow, look at all of these previous shitty decisions!" attitude inject itself, completely unnecessarily, into the workplace. I've actually made it something I won't compromise on: I refuse to hire people who I suspect will have this attitude. It's one thing to express frustration at previous decisions that make current work more difficult. However, when I see that morph into an arrogance of "how could people have made such a stupid decision" (especially when some of those "people" may still work at the company), without even trying to understand the context of why that decision was made in the first place, it shows to me that person is not an engineer I want to work with.
- derefr 5y agoDoesn’t gVisor require symbol interposition to do its sandboxing thing? (At least, for binaries with static-linked runtimes, like the type Golang produces by default.)
- falldmg 5y agoSymbol interposition? I don't know for sure, but I would guess gVisor is using ptrace or another mechanism, to interpose on syscalls, not library calls. But these flags, I believe, only impact interposition of symbols in the same library, so even if gVisor did use interposition for something, it may not matter.
- dathinab 5y agoIf you have a fully static-linked library you already don't have symbol interposition. Furthermore this options still allow the thinks you need interposition for, for calls from/to external dynamic linked libraries like libc. But most important gVisor is based around intercepting system calls (over simplified), for which you don't need symbol interposition.
- cerved 5y agoRight post, wrong platform
- BurningFrog 5y agoI'm confused. Is this about something I can do to speed up our 3.8 Python code, or about why Python 3.8 is faster than 3.7?
- ineedasername 5y agoI think it was addressed by python already: Eventually, someone working on Python (ironically, of all things) noticed this waste of good performance But It would be good to know when & what versions. I'm also not sure why this is "ironic". Who else but the experts on python would be more likely to discover this & resolve the issue? Which basically makes the whole thing a non-issue: Python creators made a choice when creating python. A while later they realized they could improve performance by revisiting that choice. The tone of the article makes it sound like this was an embarrassing mistake of massive proportions.
- ahupp 5y ago> Python creators made a choice when creating python. The tone of the article makes it sound like this was an embarrassing mistake of massive proportions. The article is talking about a bad decision in ELF and dynamic linking, not in Python specifically. The Python people just discovered that disabling that default behavior was useful.
- kaba0 5y agoI think the author meant ‘ironic’ due to the very stereotypic view of “Python is slow, why would it care about performance. At least I read it that way.
- kzrdude 5y agoCompletely beside the article - the first specializing, adaptive interpreter (PEP 659) improvements have been merged to CPython these last weeks, and hopefully we can see updates about benchmarks and performance sooner or later.
- codelord 5y agoI would just read the linked post: https://bugs.python.org/issue38980?fbclid=IwAR0cyfahpBywNzbqLCpcfwatOaU6W8UQp7LgVu8KZ8hDc-wKLjLE7wjOs7g https://bugs.python.org/issue38980?fbclid=IwAR0cyfahpBywNzbq... As it contains almost the same info without the rant and with better explanation.
- beervirus 5y agoAnd isn’t hosted on Facebook of all things.
- deleted 5y ago[deleted]
- blopker 5y agoFor what it's worth, Python 3.10 will add -fno-semantic-interposition when built with --with-optimizations by default. However, the slow down only affects Pythons built with --enabled-shared anyway. The issue is discussed here [0]. I also attempted to backport the fix to the official Python Docker image [1], but wasn't able to get much traction. I wish this would land since everyone using these images would get an instant speedup. [0]: https://bugs.python.org/issue38980 https://bugs.python.org/issue38980 [1]: https://github.com/docker-library/python/issues/501 https://github.com/docker-library/python/issues/501
- throwdbaaway 5y ago> However, the slow down only affects Pythons built with --enabled-shared anyway. On Gentoo, the ebuild for Python and Ruby both have --enable-shared hardcoded. Also, if you use prebuilt Ruby binaries from RVM, those were also built with --enable-shared. And if you build your own Ruby binaries with ruby-build, it also does --enable-shared. So, there are still plenty of opportunities around for instant speedup.
- mastrsushi 5y agoPython is like the cockroach equivalent of those shell scripting languages that came out of the late 80s to early 90s. Perl, Ruby, PHP, TCL, and Lua have definetly declined over the years. Python's biggest asset seems to be featured rich libraries, rather than the language itself.
- cutler 5y agoRuby is a much better designed language than Python but the community unfortunately made the mistake of focusing too much on Rails and web development at the expense of diversification. Python is the Skoda of scripting languages.
- ganzuul 5y ago{}, [], and / \ are all cumbersome to use on many keyboards because bankers got to them before programmers. Rather than solving the problem in hardware by getting a en-US keyboard we mitigate the RSI in software by choosing languages with less notation.
- taeric 5y agoCute, but somewhat ignores picking lisp; which just puts everything in parenthetical lists. :D
- aitchnyu 5y agoWhat does it mean in your country? For me, its a company priced out by carmakers who manufactured locally, and screwed over by dealers who didn't service cars properly. Ex Fabia owner from India.
- nwmcsween 5y agoThis isn't really an elf issue, more of a python issue, if you have internal symbols hide them.
- dbt00 5y agoThe people who did the work on finding and implementing this speedup talk about it here. https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup https://fedoraproject.org/wiki/Changes/PythonNoSemanticInter... They then proposed it for upstreaming here: https://bugs.python.org/issue38980 https://bugs.python.org/issue38980 And that's the new default. The link is to a facebook post by someone who neither discovered nor implemented this change.
- temac 5y agoedit: my comment addresses the text from the original link https://www.facebook.com/dan.colascione/posts/10107358290728348 https://www.facebook.com/dan.colascione/posts/10107358290728... The author is confused. no-semantic-interposition does not preclude unicity of symbols. There are things like -Wl,-Bsymbolic-functions to relinquish that (and lose strict conformity against the programming language you are using, by the way). When I read a virulent post at least I would like the author to have some deep expertise on the subject, and not mix everything they read about (including related but different matters). I won't even talk about the "interposition is useless anyway because clang has an historical bug" part. As for elf shared libs providing a single symbol space, there are arguments for and against. An argument for a single symbol space is that a process with segregated one per dynamic module is a beast the C and C++ standards know nothing about. And don't even get me started on processes with multiple different C or C++ runtimes simultaneously (take a look at the list of CRTs loaded in an instance of explorer.exe, it is horrifying). Another one is that you can easily move things around between dynamic libs or split them, etc. If various subsets are actually used by multiple executables, this can be quite useful (lacking that property, note that MS had to invent their own additional virtual/redirection layer to refactor the Win32 libs) A practical argument against is that it is "hard" (read: virtually impossible) to dynamically link binary only modules maintained with different-enough toolchains. Likewise for different versions of the same lib (e.g. via transitive deps). But then the question of is this even a good idea shall be asked (well, if you want to load a plugin in a proprietary software I understand this can be wanted -- and this is actually similar to using libs of a proprietary platform; any other use case?)
- dang 5y agoWe changed the url from https://www.facebook.com/dan.colascione/posts/10107358290728348 https://www.facebook.com/dan.colascione/posts/10107358290728..., which is behind a login wall and points to this. Keep in mind that many of the complaints in this thread were posted in the context of that original URL.
- Black101 5y agoOne day it will catch up... performance-wise...
- MaskRay 5y agoFolks may be interested in the two blog posts which have more technical details: https://maskray.me/blog/2021-05-09-fno-semantic-interposition https://maskray.me/blog/2021-05-09-fno-semantic-interpositio... https://maskray.me/blog/2021-05-16-elf-interposition-and-bsymbolic https://maskray.me/blog/2021-05-16-elf-interposition-and-bsy...
- QuadrupleA 5y agoIt looks like the mod_wsgi / Apache stack I've used for years does indeed use the shared libpython described here (according to running lld on mod_wsgi.so). So this compiler flag could have saved me 30% of a server - or saved my users 23% of the server processing latency of their TTFBs. Though my servers are already overprovisioned, and latency is probably more due to memory / IO and... oh nevermind. Kudos to the python devs, looking forward to more speed improvements.
- freediver 5y agoI tested this. tldr; I could not replicate speed benefits except for heavy stack usage. Python 3.10 is 8% slower than python 3.8. Python 3.10 with said optimization is 3% slower overall than Python 3.10 without it except for stack usage. Python 3.8 python-speed v1.2 using python v3.8.5 string/mem: 1476.42 ms pi calc/math: 1817.37 ms regex: 1984.63 ms fibonnaci/stack: 1085.79 ms total: 6364.21 ms (lower is better) Python 3.10 no optimization python-speed v1.2 using python v3.10.0 string/mem: 1580.52 ms pi calc/math: 1796.23 ms regex: 2110.86 ms fibonnaci/stack: 1337.18 ms total: 6824.79 ms (lower is better) Python 3.10 with optimization python-speed v1.2 using python v3.10.0 string/mem: 1559.45 ms pi calc/math: 1821.25 ms regex: 2387.64 ms fibonnaci/stack: 1299.8 ms total: 7068.13 ms (lower is better) Anything I am missing? Tested using https://github.com/vprelovac/python-speed https://github.com/vprelovac/python-speed
- stuaxo 5y agoStopping LD_PRELOAD working is pretty big though. This might be OK, if two versions were provided.
- DeathMetal3000 5y agoIsn’t it .3 times (30%) faster? I think they meant to say 1.3x _as fast_ which is very different.