On Mon, 7 Aug 2017, Steve Langasek wrote:
But I am concerned about possible implementation strategies here. exec() is
a very expensive syscall, and python is a frequently used interpreter. If
this were implemented as a wrapper that checked isatty(), printed a banner,
and then re-execed the real python, that could have a measurable performance
impact on some applications. There is a reason /usr/bin/python,
/usr/bin/gcc, etc. are always symlinks to the real interpreter on Debian,
not wrapper scripts - other distributions have tried to do this as a wrapper
script and the result wasn't pretty.
Python itself is not very fast to start up, though, so exec is not the
dominating cost. Some ad-hoc testing with the current version of pythonmux
(which uses the re-exec approach) shows that it takes about 13.8 ms to
print("Hello world") with /usr/bin/python and 15.5 ms to print("Hello
world") with pythonmux on my 2010-ish laptop.
For the sake of argument, I just pushed a branch of pythonmux that links
libpython3.5 and calls Py_Main instead of execing python3.5 (that is, if
the target interpreter is python3.5, it will not actually exec):
But it's quite a bit _slower_ with this approach (about 26.9 ms per run),
regardless of whether I link libpython3.5m.so or libpython3.5m.a. This
confuses me and I'm definitely curious to figure this out if that's worth
doing, but I think this is getting into a lot of weird complexity to save
1.7 ms on a mere hello world -- for comparison, if I add `import requests`
to my hello world program, each run now takes about 342 ms.
By the way, I do think I made pythonmux do too much since I wanted to make
it useful in the general case; in particular I don't think it's super
helpful to support scripts that say "I can run on Python 3.2 but not any
newer version". Given the way the discussion is going (both here and on
linux-sig) and how close we are to Python 2's end-of-life, I think it's
sufficient to check isatty(0) and the shebang line if one exists, call
libpython3's Py_Main if that seems reasonable, print a warning and attempt
to exec python2 otherwise, and print an error message about how to install
python2 if the exec fails.