[opensuse-factory] Proposal to remove pyc/pyo from Python on TW
Hi, As you know the Python packages are collecting the pyc/pyo precompiled binaries inside the RPM. This is mostly a good idea, as makes the first execution of the Python code faster, as is skipped the stage where the interpreter compile the .py code. But this also makes the Python stack a bit fat. Most of the time this is not a problem, but things are changing. We have JeOS and MicroOS, both minimal images (build with different goals and technology) that search for be small and slim. But we want to include a bit of Python in there, like salt-minion or cloud-init. And now the relative size of Python is evident. For Python 2.7 and 3.7 is possible to remove the pyc code from the system and instruct the interpreter to avoid the recreation of the pyc once the code is executed. The Python interpreter, by default, will compile and store the pyc in the disk for each `import`, but this behavior can be disable when we call Python. But this will make the initial execution of a big Python stack a bit slow, as the pyc needs to be recreated in memory for each invocation. The slowness can be relevant in some situations, so is better to not enable this feature. But in Python 3.8 there is a new feature in place, bpo-33499, that will recognize a new env variable (PYTHONPYCACHEPREFIX) that will change the place where __pycache__ is stored [2]. I backported this feature to 3.7 and create a JeOS image that includes salt-minion. I created an small shim that replace the python3.7 binary to enable this cache prefix feature, to point it to /var/ cache/pycache/<username>, and I removed from the image all the python compiled code. I decided salt-minion as saltsack is a relevant Python codebase. I needed to port to 3.7 150 python libraries to create the first PoC. The PoC works properly locally. I have yet some bits that I need to publish in the repo, but the general idea seems to work OK. I can also publish the gain on size for the ISO with the patch and without the patch, to have more data to compare. I also estimated some gains for different scenarios. For example in a normal TW installation: * Python 2.7 + 3.6 - pyc/pyc: 127M total - py: 109M total * Python 3.6 only - pyc/pyc: 91M total - py: 70M total Python pyc/pyo size is more than the py code size, so we can potentially half the size of the Python 3 stack. Maybe for a normal TW installation the absolute gain is not much (91M). But for other scenarios can be relevant, like in OpenStack Cloud, where the size of the Python code is big. I made some calculations based on all the different OpenStack services: * Python 2.7 OpenStack services - pyc/pyo: 1.2G total - py: 804M total Saving 1.2G each node is a more important number. So, my proposal is to remove the pyc from the Python 3 packages and enable the cache layer on Tumbleweed since Python 3.7. I do not know if do that by default or under certain configurations, as I am not sure how to that feature optional. Any ideas? Any suggestions? What do you think if I follow this path? Some ideas that I have are add a new %pycache-clean macro that will remove the __pycache__ from the RPM, add a new rpmlint check to make sure that there are not pyc for a python3 package, update the wiki and update the py2pack code to generate good python3 spec files for openSUSE. But if most of the community do not agree with this approach, I can drop the idea : ) [1] https://bugs.python.org/issue33499 [2] https://docs.python.org/3.8/whatsnew/3.8.html p.s: Sorry if the message is delivered two times, one from the .com account. My bad. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 10/4/18 4:52 PM, Alberto Planas Dominguez wrote:
I created an small shim that replace the python3.7 binary to enable this cache prefix feature, to point it to /var/ cache/pycache/<username>, and I removed from the image all the python compiled code.
The above sounds to me that compiled code goes into several user-specific pycache directories. How does that save space? Ciao, Michael.
On Thu, Oct 4, 2018 at 10:52 AM Alberto Planas Dominguez
Hi,
As you know the Python packages are collecting the pyc/pyo precompiled binaries inside the RPM. This is mostly a good idea, as makes the first execution of the Python code faster, as is skipped the stage where the interpreter compile the .py code.
But this also makes the Python stack a bit fat. Most of the time this is not a problem, but things are changing. We have JeOS and MicroOS, both minimal images (build with different goals and technology) that search for be small and slim. But we want to include a bit of Python in there, like salt-minion or cloud-init. And now the relative size of Python is evident.
For Python 2.7 and 3.7 is possible to remove the pyc code from the system and instruct the interpreter to avoid the recreation of the pyc once the code is executed. The Python interpreter, by default, will compile and store the pyc in the disk for each `import`, but this behavior can be disable when we call Python.
But this will make the initial execution of a big Python stack a bit slow, as the pyc needs to be recreated in memory for each invocation. The slowness can be relevant in some situations, so is better to not enable this feature.
But in Python 3.8 there is a new feature in place, bpo-33499, that will recognize a new env variable (PYTHONPYCACHEPREFIX) that will change the place where __pycache__ is stored [2]. I backported this feature to 3.7 and create a JeOS image that includes salt-minion. I created an small shim that replace the python3.7 binary to enable this cache prefix feature, to point it to /var/ cache/pycache/<username>, and I removed from the image all the python compiled code.
I decided salt-minion as saltsack is a relevant Python codebase. I needed to port to 3.7 150 python libraries to create the first PoC.
The PoC works properly locally. I have yet some bits that I need to publish in the repo, but the general idea seems to work OK. I can also publish the gain on size for the ISO with the patch and without the patch, to have more data to compare.
I've heard variations of this theme for almost a decade now. There are three major problems with this: * Python is _very_ slow without the cache, and generating the cache is a slow operation. This is a terrible penalty for systems that heavily rely on Python. And failure to write the cache means every run is fully interpreted and very slow. * Generating the bytecode on the system means that we aren't evaluating the code to check whether it actually works for the target Python at build-time. This is a huge problem for ensuring the code is actually compatible with the target version of Python. While it's of course possible to have some things slip by, even with bytecode generation, it's a lot less likely. * It makes it much more likely that we'll leave garbage on the filesystem with installs and uninstalls of Python software. That just adds up to unaccounted space being taken up for relatively static content that should be pre-generated and tracked. OpenMandriva went with this approach for a while, and they're switching back because of these issues, especially as they've become more aggressive about upgrading the Python stack and keeping modules up to date since they switched /usr/bin/python to point to Python 3. -- 真実はいつも一つ!/ Always, there's only one truth! -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thursday 2018-10-04 18:04, Neal Gompa wrote:
But in Python 3.8 there is a new feature in place, bpo-33499, that will recognize a new env variable (PYTHONPYCACHEPREFIX) that will change the place where __pycache__ is stored [2]. I backported this feature to 3.7 and create a JeOS image that includes salt-minion. I created an small shim that replace the python3.7 binary to enable this cache prefix feature, to point it to /var/ cache/pycache/<username>, and I removed from the image all the python compiled code.
I've heard variations of this theme for almost a decade now. There are three major problems with this:
* Python is _very_ slow without the cache, and generating the cache is a slow operation. This is a terrible penalty for systems that heavily rely on Python. And failure to write the cache means every run is fully interpreted and very slow.
It seems weird that among all the scripting interpreters in a Linux distribution, this seems like a cpython-only issue. What is it that sh, perl are doing right? I can't remember seeing equally vocal lamentations about their execution speeds or techniques here. -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thursday, October 4, 2018 6:04:27 PM CEST Neal Gompa wrote:
I've heard variations of this theme for almost a decade now. There are three major problems with this:
* Python is _very_ slow without the cache, and generating the cache is a slow operation. This is a terrible penalty for systems that heavily rely on Python. And failure to write the cache means every run is fully interpreted and very slow.
But in the proposal there is a cache, only that living in a different place. Also you are wrong believing that Python will not generate the pyc if is not there, as they will reside in memory. Python can only execute pycs, so the speed is exactly the same. The penalty is only the first time that pyc is generated.
* Generating the bytecode on the system means that we aren't evaluating the code to check whether it actually works for the target Python at build-time. This is a huge problem for ensuring the code is actually compatible with the target version of Python. While it's of course possible to have some things slip by, even with bytecode generation, it's a lot less likely.
Actually no, as the pyc will be generated on OBS just when the %check happens. The proposal is not integrating those pyc in the RPM.
* It makes it much more likely that we'll leave garbage on the filesystem with installs and uninstalls of Python software. That just adds up to unaccounted space being taken up for relatively static content that should be pre-generated and tracked.
That is true, but is true for any cache management. This can be cleaned regularly or thing about a new macro that will make sure that the pyc for the upgraded module is not there anymore. Or not do anything and delegate it to the normal management of any server.
OpenMandriva went with this approach for a while, and they're switching back because of these issues, especially as they've become more aggressive about upgrading the Python stack and keeping modules up to date since they switched /usr/bin/python to point to Python 3.
Note that the proposal is backporting a new feature from 3.8 that will enable the living of the pyc files in a different place. I am not sure how OpenMandriva implemented this feature. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thursday 2018-10-04 16:52, Alberto Planas Dominguez wrote:
I also estimated some gains for different scenarios. For example in a normal TW installation:
* Python 2.7 + 3.6 - pyc/pyc: 127M total - py: 109M total
* Python 3.6 only - pyc/pyc: 91M total - py: 70M total
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
Am 04.10.18 um 18:39 schrieb Jan Engelhardt:
On Thursday 2018-10-04 16:52, Alberto Planas Dominguez wrote:
I also estimated some gains for different scenarios. For example in a normal TW installation:
* Python 2.7 + 3.6 - pyc/pyc: 127M total - py: 109M total
* Python 3.6 only - pyc/pyc: 91M total - py: 70M total
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-)
Would that work? That sounds like the perfect solution to me :) Greetings, Stephan P.S. Dropping cross post -- Lighten up, just enjoy life, smile more, laugh more, and don't get so worked up about things. Kenneth Branagh -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thu, Oct 4, 2018 at 1:05 PM Stephan Kulow
Am 04.10.18 um 18:39 schrieb Jan Engelhardt:
On Thursday 2018-10-04 16:52, Alberto Planas Dominguez wrote:
I also estimated some gains for different scenarios. For example in a normal TW installation:
* Python 2.7 + 3.6 - pyc/pyc: 127M total - py: 109M total
* Python 3.6 only - pyc/pyc: 91M total - py: 70M total
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-)
Would that work? That sounds like the perfect solution to me :)
If openSUSE consistently byte-compiled like Fedora does through a brp script, then it might. I'd probably suggest that the source be available via a subpackage if you're really considering that, because it does make debugging Python code way harder (traceback information comes from .py files, I believe). -- 真実はいつも一つ!/ Always, there's only one truth! -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Donnerstag, 4. Oktober 2018 19:05:16 CEST Stephan Kulow wrote:
Am 04.10.18 um 18:39 schrieb Jan Engelhardt:
On Thursday 2018-10-04 16:52, Alberto Planas Dominguez wrote:
I also estimated some gains for different scenarios. For example in a normal TW installation:
* Python 2.7 + 3.6
- pyc/pyc: 127M total - py: 109M total
* Python 3.6 only
- pyc/pyc: 91M total - py: 70M total
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-)
Would that work? That sounds like the perfect solution to me :)
Not in a trivial way. There is a reason the files in __pycache__ have the {implementation}.opt-{optimization} infix, the bytecode is implementation defined. If you want python to use only the bytecode, you have to place it in the source directory (i.e. on level above the __pycache__ directory), and remove the infix from the name. The .pyc file can be a symlink into the __pycache__ directory. E.g.: --- -+ foo.py + foo.pyc -> __pycache__/foo.cpython-36.pyc + __pycache__ -+ foo.cpython-36.pyc + foo.cpython-36.opt-1.pyc + foo.cpython-36.opt-2.pyc __ Then you have to split this into a least 3 packages - source - bytecode with default optimization level + symlink, all - bytecode for other optimization levels To add some more fun, the bytecode files for all or at least some optimization levels may be bitidentical, which currently is leveraged by hardlinking the files. That is no longer possible when you split the bytecode files. You also have to decide on your default optimization level. As opt-1 and opt-2 remove any assert's, using e.g. opt-1 as default level may change the runtime behaviour of you code. Kind regards, Stefan-- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thursday, October 4, 2018 6:39:41 PM CEST Jan Engelhardt wrote:
On Thursday 2018-10-04 16:52, Alberto Planas Dominguez wrote:
I also estimated some gains for different scenarios. For example in a normal TW installation:
* Python 2.7 + 3.6
- pyc/pyc: 127M total - py: 109M total
* Python 3.6 only
- pyc/pyc: 91M total - py: 70M total
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-)
I would definitively not do that, as the traceback will lack context. Imagine supporting a system that fails without pointing the source code that generate the error. In my experience having the pys makes the debugging experience a lot better. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
Am 05.10.18 um 10:41 schrieb Alberto Planas Dominguez:
On Thursday, October 4, 2018 6:39:41 PM CEST Jan Engelhardt wrote:
On Thursday 2018-10-04 16:52, Alberto Planas Dominguez wrote:
I also estimated some gains for different scenarios. For example in a normal TW installation:
* Python 2.7 + 3.6
- pyc/pyc: 127M total - py: 109M total
* Python 3.6 only
- pyc/pyc: 91M total - py: 70M total
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-)
I would definitively not do that, as the traceback will lack context. Imagine supporting a system that fails without pointing the source code that generate the error. In my experience having the pys makes the debugging experience a lot better.
The same is true for C and C++ :) But you optimize for size (and speed) not for debugging experience Greetings, Stephan -- Lighten up, just enjoy life, smile more, laugh more, and don't get so worked up about things. Kenneth Branagh -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Friday, October 5, 2018 10:44:45 AM CEST Stephan Kulow wrote:
Am 05.10.18 um 10:41 schrieb Alberto Planas Dominguez:
On Thursday, October 4, 2018 6:39:41 PM CEST Jan Engelhardt wrote:
On Thursday 2018-10-04 16:52, Alberto Planas Dominguez wrote:
I also estimated some gains for different scenarios. For example in a normal TW installation:
* Python 2.7 + 3.6
- pyc/pyc: 127M total - py: 109M total
* Python 3.6 only
- pyc/pyc: 91M total - py: 70M total
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-)
I would definitively not do that, as the traceback will lack context. Imagine supporting a system that fails without pointing the source code that generate the error. In my experience having the pys makes the debugging experience a lot better.
The same is true for C and C++ :)
But you optimize for size (and speed) not for debugging experience
Not for a dynamic language. IMO the debugging factor makes this comparison unbalance. In Python the main debugging tool is the traceback, is what the user report, and is the information where the diagnosis is based on. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 2018-10-05T10:41:22, Alberto Planas Dominguez
I would definitively not do that, as the traceback will lack context. Imagine supporting a system that fails without pointing the source code that generate the error. In my experience having the pys makes the debugging experience a lot better.
That's what debug{info,source} are for. We obviously need a way to translate the traceback from a system where those weren't installed at the time of the trace, but that's not different from any other support incident. -- Architect SDS, Distinguished Engineer SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg) "Architects should open possibilities and not determine everything." (Ueli Zbinden) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Friday, October 5, 2018 10:44:53 AM CEST Lars Marowsky-Bree wrote:
On 2018-10-05T10:41:22, Alberto Planas Dominguez
wrote: I would definitively not do that, as the traceback will lack context. Imagine supporting a system that fails without pointing the source code that generate the error. In my experience having the pys makes the debugging experience a lot better.
That's what debug{info,source} are for. We obviously need a way to translate the traceback from a system where those weren't installed at the time of the trace, but that's not different from any other support incident.
Uhmm sure it is. Another user commented that a pyc only distribution will require the change of the pyc name schema and location. So for each python package we have the three subpackages, two of the duplicating the pyc information, and only to have the the traceback info. And this is only if we make the two pyc packages co-installables, as in other case the user needs to replace one package for another. In every debugging session you will find that updating the py, sometimes will not be reflected on the expected output, until you realized that you are still executing the old pyc, and you need to manually remove it. But now you have two pyc candidates to remove. This scenario scares me a lot : )) -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 2018-10-04, 16:39 GMT, Jan Engelhardt wrote:
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-)
Well, it's a bit more complicated than that. 1. *.pyc files are arch independent (it's just an ouput of the marshall underneath), but they are not interpreter independent. So, if you install only *.pyc files generated by CPython, you cannot use the same library with Jython or PyPy (IronPython seems to be catching second breath on https://github.com/IronLanguages/ironpython2). That limitation probably isn’t a problem with IoT microimages, but I think it is quite showstopper for the general openSUSE/SLE. And no, if you study https://is.gd/EgL9S4 (Case 3 and Case 4) carefully, it is not possible to have both __pycache__ and sourceless *.pyc files together. 2. We would need to port patches from https://bugs.python.org/issue33499 to all desired versions of Python. 3. I am not sure how big the performance penalty will be. 4. We would need to make an extensive changes to our packaging macros to allow automatic generation of python-foo-source modules and working with them. Best, Matěj -- https://matej.ceplovi.cz/blog/, Jabber: mcepl@ceplovi.cz GPG Finger: 3C76 A027 CA45 AD70 98B5 BC1D 7920 5802 880B C9D8 Anger is often what pain looks like when it shows itself in public. -- Krista Tippett -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Freitag, 5. Oktober 2018 13:24:24 CEST Matěj Cepl wrote:
On 2018-10-04, 16:39 GMT, Jan Engelhardt wrote:
Or one could remove py and keep pyc/pyo. That's basically how GNU C C++ & Fortran, Erlang, ocaml, .. all work ;-)
Well, it's a bit more complicated than that.
1. *.pyc files are arch independent (it's just an ouput of the marshall underneath), but they are not interpreter independent. So, if you install only *.pyc files generated by CPython, you cannot use the same library with Jython or PyPy (IronPython seems to be catching second breath on https://github.com/IronLanguages/ironpython2). That limitation probably isn’t a problem with IoT microimages, but I think it is quite showstopper for the general openSUSE/SLE.
And no, if you study https://is.gd/EgL9S4 (Case 3 and Case 4) carefully, it is not possible to have both __pycache__ and sourceless *.pyc files together.
If you read it *really carefully*, you will see you can have both __pycache__ and {name}.pyc together, but not {name}.pyc and {name}.py (or more specifically, {name}.py disables {name}.pyc). --- $> echo "import bar" > foo.py $> echo "print('bar')" > bar.py $> python3 foo.py $> ln -s ln -s __pycache__/bar.cpython-36.pyc bar.pyc $> strace -efile -o '|grep bar' python3 ./foo.py $> mv bar.py{,_bak} $> strace -efile -o '|grep bar' python3 ./foo.py --- (Re)moving bar.py does not stop bar.pyc from working. So you can ship foo.pyc and __pycache__/foo.{implementation}[opt-*].pyc in the same package, in foo.py in a different one. You still have to decide with the different optimization levels. Kind regards, Stefan
On 10/4/18 10:52 AM, Alberto Planas Dominguez wrote:
Hi,
As you know the Python packages are collecting the pyc/pyo precompiled binaries inside the RPM. This is mostly a good idea, as makes the first execution of the Python code faster, as is skipped the stage where the interpreter compile the .py code.
But this also makes the Python stack a bit fat. Most of the time this is not a problem, but things are changing. We have JeOS and MicroOS, both minimal images (build with different goals and technology) that search for be small and slim.
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger? I can think of 1 trade-of, in the Cloud, when a new instance is created the image file is copied. Therefore a smaller image improves the overall instance start up as there is less data to copy. However, from my experience in GCE, where we at some point built 8GB images then switched to 10 GB images, there was no noticeable difference between the two image sizes w.r.t. start up time of an instance.
But we want to include a bit of Python in there, like salt-minion or cloud-init. And now the relative size of Python is evident.
Well, especially for cloud-init at the last couple of get together events of upstream contributors start up time for cloud-init was a big discussion point. A lot of effort has gone into making cloud-init faster. The results of this effort would be eliminated with such a move. The result here is that we would trade a measurable hit, i.e. X seconds slower for cloud-init for a non quantified "size goal" with non quantified benefits.
For Python 2.7 and 3.7 is possible to remove the pyc code from the system and instruct the interpreter to avoid the recreation of the pyc once the code is executed. The Python interpreter, by default, will compile and store the pyc in the disk for each `import`, but this behavior can be disable when we call Python.
But this will make the initial execution of a big Python stack a bit slow, as the pyc needs to be recreated in memory for each invocation. The slowness can be relevant in some situations, so is better to not enable this feature.
But in Python 3.8 there is a new feature in place, bpo-33499, that will recognize a new env variable (PYTHONPYCACHEPREFIX) that will change the place where __pycache__ is stored [2]. I backported this feature to 3.7 and create a JeOS image that includes salt-minion. I created an small shim that replace the python3.7 binary to enable this cache prefix feature, to point it to /var/ cache/pycache/<username>, and I removed from the image all the python compiled code.
I decided salt-minion as saltsack is a relevant Python codebase. I needed to port to 3.7 150 python libraries to create the first PoC.
The PoC works properly locally. I have yet some bits that I need to publish in the repo, but the general idea seems to work OK. I can also publish the gain on size for the ISO with the patch and without the patch, to have more data to compare.
I also estimated some gains for different scenarios. For example in a normal TW installation:
* Python 2.7 + 3.6 - pyc/pyc: 127M total - py: 109M total
* Python 3.6 only - pyc/pyc: 91M total - py: 70M total
Python pyc/pyo size is more than the py code size, so we can potentially half the size of the Python 3 stack.
And we need to consider all the points made when we had this discussion sometime last year, I think at that point it was started by Duncan. Having these numbers is interesting but what is the goal of the image you want to build and what is the benefit of the smaller size for JeOS or MicriOS?
Maybe for a normal TW installation the absolute gain is not much (91M).
Well it is not just the install. We would be penalizing every user with a start up time penalty to save 91M, sorry that appears to me as an optimization for the corner case at the expense of the most common path.
But for other scenarios can be relevant, like in OpenStack Cloud, where the size of the Python code is big. I made some calculations based on all the different OpenStack services:
* Python 2.7 OpenStack services - pyc/pyo: 1.2G total - py: 804M total
Saving 1.2G each node is a more important number.
See above, w.r.t. start up time of an instance I think we'd have to show that this saving actually makes a difference when the image is copied to start a new instance. Backend storage is very fast these days and I am not convinced this actually makes a difference.
So, my proposal is to remove the pyc from the Python 3 packages and enable the cache layer on Tumbleweed since Python 3.7. I do not know if do that by default or under certain configurations, as I am not sure how to that feature optional.
Any ideas?
IMHO there are mechanism for you to do this for the corner cases, i.e. JeOS and MicroOS image builds. It is very easy with kiwi to run "find / -name '*.pyc' | xargs rm ' during the image build state. This gives you what you are after, a smaller image size without penalizing everyone else.
Any suggestions?
See above, remove the files during image build for JeOS and MicroOS.
What do you think if I follow this path?
I oppose this path. We'd be penalizing every start up of every instance of EC2. We have feature requests to improve our boot performance and this is counter acting our efforts. Also it'll be uncomfortable to explain why when someone runs 'systemd analyze' our cloud-init in EC2 will be significantly slower than the same version of cloud-init on other distros. Later, Robert -- Robert Schweikert MAY THE SOURCE BE WITH YOU Distinguished Architect LINUX Team Lead Public Cloud rjschwei@suse.com IRC: robjo
On Thu, Oct 04, Robert Schweikert wrote:
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
Ever downloaded an image at every boot via LTE? That's what some of our customers are doing, as they don't want to send technicians out in the wild to do that via usb stick. And in virtualisation environments (not public cloud), disks are no longer cheap, as you have many, many virtual machines. So why for you a jump from 8 GB to 10 GB in the public cloud is no big problem, a lot of customers would like to see that we use only 4 GB, as that would allow them to store double as many virtual machines as today. And the LTE fraction would even like to see images in the 150MB range...
Having these numbers is interesting but what is the goal of the image you want to build and what is the benefit of the smaller size for JeOS or MicriOS?
The requested goal by our big customers are less than 500MB, else see above. And no, we don't want any of your proposed hacks, we are very happy that we were able to remove all of this hacks from building images. This only breaks RPM and updating the images. Thorsten -- Thorsten Kukuk, Distinguished Engineer, Senior Architect SLES & CaaSP SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nuernberg, Germany GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 10/4/18 1:33 PM, Thorsten Kukuk wrote:
On Thu, Oct 04, Robert Schweikert wrote:
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
Ever downloaded an image at every boot via LTE? That's what some of our customers are doing, as they don't want to send technicians out in the wild to do that via usb stick.
And in virtualisation environments (not public cloud), disks are no longer cheap, as you have many, many virtual machines. So why for you a jump from 8 GB to 10 GB in the public cloud is no big problem, a lot of customers would like to see that we use only 4 GB,
But we can build a 4GB functional openSUSE or SLES image with pyc code included, I'm pretty sure. Our images in the Public Cloud are 10GB on the request of the providers, not because we need the space.
as that would allow them to store double as many virtual machines as today. And the LTE fraction would even like to see images in the 150MB range...
I see the problem with that request.
Having these numbers is interesting but what is the goal of the image you want to build and what is the benefit of the smaller size for JeOS or MicriOS?
The requested goal by our big customers are less than 500MB, else see above.
And no, we don't want any of your proposed hacks, we are very happy that we were able to remove all of this hacks from building images. This only breaks RPM and updating the images.
OK, fair enough, although I do not consider image manipulation via images.sh a hack, I agree that it will cause issues with the update path. Then again an image that gets downloaded for every boot should get rebuilt for updates, rather than being updated in place. So we have two groups with seemingly conflicting interests that we'll try to make happy without favoring one at the expense of the other. We've been here before ;) Can we teach rpm to handle this better? I am thinking of something like --no-pycache as an option for install. This would skip the install of pyc/pyo, egg, and other Python artifacts and leave a record in the rpmdb that the package was installed with this option. Then it could be handled in the update path properly and not install the byte compiled files on update, nor try to remove them from the previous package install. Of course there needs to be an option to get the "missing" files, maybe something like "--add-pycache". For MicroOS and JeOS image builds this could then be set as an option for the kiwi image build, well kiwi would need to learn about the new option, but that is not too terribly difficult. We might need to introduce a macro to mark the files in the rpm package appropriately, maybe something like {%_pycache_file} The concept already exists in rpm (--excludedocs) to piggy back on. But I certainly don't know enough about the state of the rpm community if something like this would fly upstream or if this is something we'd consider doing on our own. mls? Something along those lines would meet both of our needs. Later, Robert -- Robert Schweikert MAY THE SOURCE BE WITH YOU Distinguished Architect LINUX Team Lead Public Cloud rjschwei@suse.com IRC: robjo
On Thu, Oct 4, 2018 at 2:36 PM Robert Schweikert
On 10/4/18 1:33 PM, Thorsten Kukuk wrote:
On Thu, Oct 04, Robert Schweikert wrote:
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
Ever downloaded an image at every boot via LTE? That's what some of our customers are doing, as they don't want to send technicians out in the wild to do that via usb stick.
And in virtualisation environments (not public cloud), disks are no longer cheap, as you have many, many virtual machines. So why for you a jump from 8 GB to 10 GB in the public cloud is no big problem, a lot of customers would like to see that we use only 4 GB,
But we can build a 4GB functional openSUSE or SLES image with pyc code included, I'm pretty sure. Our images in the Public Cloud are 10GB on the request of the providers, not because we need the space.
as that would allow them to store double as many virtual machines as today. And the LTE fraction would even like to see images in the 150MB range...
I see the problem with that request.
Having these numbers is interesting but what is the goal of the image you want to build and what is the benefit of the smaller size for JeOS or MicriOS?
The requested goal by our big customers are less than 500MB, else see above.
And no, we don't want any of your proposed hacks, we are very happy that we were able to remove all of this hacks from building images. This only breaks RPM and updating the images.
OK, fair enough, although I do not consider image manipulation via images.sh a hack, I agree that it will cause issues with the update path. Then again an image that gets downloaded for every boot should get rebuilt for updates, rather than being updated in place.
So we have two groups with seemingly conflicting interests that we'll try to make happy without favoring one at the expense of the other. We've been here before ;)
Can we teach rpm to handle this better? I am thinking of something like
--no-pycache
as an option for install. This would skip the install of pyc/pyo, egg, and other Python artifacts and leave a record in the rpmdb that the package was installed with this option. Then it could be handled in the update path properly and not install the byte compiled files on update, nor try to remove them from the previous package install. Of course there needs to be an option to get the "missing" files, maybe something like "--add-pycache".
For MicroOS and JeOS image builds this could then be set as an option for the kiwi image build, well kiwi would need to learn about the new option, but that is not too terribly difficult. We might need to introduce a macro to mark the files in the rpm package appropriately, maybe something like
{%_pycache_file}
The concept already exists in rpm (--excludedocs) to piggy back on. But I certainly don't know enough about the state of the rpm community if something like this would fly upstream or if this is something we'd consider doing on our own.
There is a feature in the latest rpm versions: the %artifact attribute, which actually would make sense to mark *.py[co] files with. And there's an install filter switch for it, too. This is already used for the newer upstream debuginfo stuff, too. It should be present now with rpm 4.14.1, and I'm working on moving us to rpm 4.14.2. -- 真実はいつも一つ!/ Always, there's only one truth! -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 10/4/18 2:41 PM, Neal Gompa wrote:
On Thu, Oct 4, 2018 at 2:36 PM Robert Schweikert
wrote: <snip>
And no, we don't want any of your proposed hacks, we are very happy that we were able to remove all of this hacks from building images. This only breaks RPM and updating the images.
OK, fair enough, although I do not consider image manipulation via images.sh a hack, I agree that it will cause issues with the update path. Then again an image that gets downloaded for every boot should get rebuilt for updates, rather than being updated in place.
So we have two groups with seemingly conflicting interests that we'll try to make happy without favoring one at the expense of the other. We've been here before ;)
Can we teach rpm to handle this better? I am thinking of something like
--no-pycache
as an option for install. This would skip the install of pyc/pyo, egg, and other Python artifacts and leave a record in the rpmdb that the package was installed with this option. Then it could be handled in the update path properly and not install the byte compiled files on update, nor try to remove them from the previous package install. Of course there needs to be an option to get the "missing" files, maybe something like "--add-pycache".
For MicroOS and JeOS image builds this could then be set as an option for the kiwi image build, well kiwi would need to learn about the new option, but that is not too terribly difficult. We might need to introduce a macro to mark the files in the rpm package appropriately, maybe something like
{%_pycache_file}
The concept already exists in rpm (--excludedocs) to piggy back on. But I certainly don't know enough about the state of the rpm community if something like this would fly upstream or if this is something we'd consider doing on our own.
There is a feature in the latest rpm versions: the %artifact attribute, which actually would make sense to mark *.py[co] files with. And there's an install filter switch for it, too.
This is already used for the newer upstream debuginfo stuff, too. It should be present now with rpm 4.14.1, and I'm working on moving us to rpm 4.14.2.
Sounds like one part of our problem is already solved. Now getting it back to SLES 12 and SLES 15 that's a different question. And of course fixing up all those python spec files...... Later, Robert -- Robert Schweikert MAY THE SOURCE BE WITH YOU Distinguished Architect LINUX Team Lead Public Cloud rjschwei@suse.com IRC: robjo
On Thursday, October 4, 2018 9:07:50 PM CEST Robert Schweikert wrote:
On 10/4/18 2:41 PM, Neal Gompa wrote:
On Thu, Oct 4, 2018 at 2:36 PM Robert Schweikert
wrote: <snip> There is a feature in the latest rpm versions: the %artifact attribute, which actually would make sense to mark *.py[co] files with. And there's an install filter switch for it, too. This is already used for the newer upstream debuginfo stuff, too. It should be present now with rpm 4.14.1, and I'm working on moving us to rpm 4.14.2.
Sounds like one part of our problem is already solved. Now getting it back to SLES 12 and SLES 15 that's a different question. And of course fixing up all those python spec files......
I do not see it for sles12 nor 15, but for Tumbleweed. I think that I miss to be clear that this is a Python 3.7 feature that is a backport for the still not released 3.8. I would not follow the -B path except for very specific uses cases that I do not have in mind. The %artifact idea sounds nice to me. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
Robert Schweikert schrieb:
On 10/4/18 2:41 PM, Neal Gompa wrote:
[...] There is a feature in the latest rpm versions: the %artifact attribute, which actually would make sense to mark *.py[co] files with. And there's an install filter switch for it, too.
This is already used for the newer upstream debuginfo stuff, too. It should be present now with rpm 4.14.1, and I'm working on moving us to rpm 4.14.2.
Sounds like one part of our problem is already solved. Now getting it back to SLES 12 and SLES 15 that's a different question. And of course fixing up all those python spec files......
Adding %artifact could be done fully automatic by rpm itself based on file pattern. AFAICS tagging artifacts so far is hardcoded to debuginfo though. So there's still work to do. rpmbuild would need to extend eg. the fileattrs mechanism¹ also support hooks for %artifact. With that it would be just a matter of a rebuild. Also, a config option would be needed to have rpm -i/-U automatically use that mode, like %_excludedocs and %_install_langs. cu Ludwig [1] /usr/lib/rpm/fileattrs/python.attr -- (o_ Ludwig Nussel //\ V_/_ http://www.suse.com/ SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thu, Oct 04, 2018 at 02:41:51PM -0400, Neal Gompa wrote:
There is a feature in the latest rpm versions: the %artifact attribute, which actually would make sense to mark *.py[co] files with. And there's an install filter switch for it, too.
I don't think so. There's a query filter switch, but not an install filter switch. %artifact was introduced to hide files from queries. Cheers, Michael. -- Michael Schroeder mls@suse.de SUSE LINUX GmbH, GF Jeff Hawn, HRB 16746 AG Nuernberg main(_){while(_=~getchar())putchar(~_-1/(~(_|32)/13*2-11)*13);} -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Fri, Oct 5, 2018 at 6:04 AM Michael Schroeder
On Thu, Oct 04, 2018 at 02:41:51PM -0400, Neal Gompa wrote:
There is a feature in the latest rpm versions: the %artifact attribute, which actually would make sense to mark *.py[co] files with. And there's an install filter switch for it, too.
I don't think so. There's a query filter switch, but not an install filter switch. %artifact was introduced to hide files from queries.
You're right, my mistake. But it probably wouldn't take much to extend it to that, too. -- 真実はいつも一つ!/ Always, there's only one truth! -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
Am 04.10.18 um 20:36 schrieb Robert Schweikert:
Can we teach rpm to handle this better? I am thinking of something like
--no-pycache
as an option for install. This would skip the install of pyc/pyo, egg, and other Python artifacts and leave a record in the rpmdb that the package was installed with this option. Just mark them as %doc, there's already an option to omit documentation files ;-) The best thing would really be to not ship sources by default (put them in an extra RPM), but apparently the python compiler is not good enough to produce easily runnable binaries.
(OT: I'm really happy I never moved away from perl when it comes to scripting languages ;-)) -- Stefan Seyfried "For a successful technology, reality must take precedence over public relations, for nature cannot be fooled." -- Richard Feynman -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thu, 4 Oct 2018, Robert Schweikert wrote:
On 10/4/18 1:33 PM, Thorsten Kukuk wrote:
On Thu, Oct 04, Robert Schweikert wrote:
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
Ever downloaded an image at every boot via LTE? That's what some of our customers are doing, as they don't want to send technicians out in the wild to do that via usb stick.
And in virtualisation environments (not public cloud), disks are no longer cheap, as you have many, many virtual machines. So why for you a jump from 8 GB to 10 GB in the public cloud is no big problem, a lot of customers would like to see that we use only 4 GB,
But we can build a 4GB functional openSUSE or SLES image with pyc code included, I'm pretty sure. Our images in the Public Cloud are 10GB on the request of the providers, not because we need the space.
as that would allow them to store double as many virtual machines as today. And the LTE fraction would even like to see images in the 150MB range...
I see the problem with that request.
Having these numbers is interesting but what is the goal of the image you want to build and what is the benefit of the smaller size for JeOS or MicriOS?
The requested goal by our big customers are less than 500MB, else see above.
And no, we don't want any of your proposed hacks, we are very happy that we were able to remove all of this hacks from building images. This only breaks RPM and updating the images.
OK, fair enough, although I do not consider image manipulation via images.sh a hack, I agree that it will cause issues with the update path. Then again an image that gets downloaded for every boot should get rebuilt for updates, rather than being updated in place.
So we have two groups with seemingly conflicting interests that we'll try to make happy without favoring one at the expense of the other. We've been here before ;)
Can we teach rpm to handle this better? I am thinking of something like
--no-pycache
as an option for install. This would skip the install of pyc/pyo, egg, and other Python artifacts and leave a record in the rpmdb that the package was installed with this option. Then it could be handled in the update path properly and not install the byte compiled files on update, nor try to remove them from the previous package install. Of course there needs to be an option to get the "missing" files, maybe something like "--add-pycache".
For MicroOS and JeOS image builds this could then be set as an option for the kiwi image build, well kiwi would need to learn about the new option, but that is not too terribly difficult. We might need to introduce a macro to mark the files in the rpm package appropriately, maybe something like
{%_pycache_file}
The concept already exists in rpm (--excludedocs) to piggy back on. But I certainly don't know enough about the state of the rpm community if something like this would fly upstream or if this is something we'd consider doing on our own.
mls?
Something along those lines would meet both of our needs.
Well, I suppose first splitting off .py[co] from .py into separate sub-packages would make sense. It has already been noted that one can drop the .py if you keep the .py[co] and this would leave choice. I guess for dependences you'd then have $foo-py: Provides: $foo $foo-pyc: Provides: $foo $bar: Requires: $foo so installing either -py or -pyc resolves the dependence. We have to somehow prefer one or the other to make our dependence solver happy I guess, not sure if it supports a systemwide "pattern" like "Prefer: *-py" ;) Richard.
Later, Robert
--
Richard Biener
On 10/4/18 7:33 PM, Thorsten Kukuk wrote:
On Thu, Oct 04, Robert Schweikert wrote:
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
Ever downloaded an image at every boot via LTE? That's what some of our customers are doing, as they don't want to send technicians out in the wild to do that via usb stick.
Wouldn't that be a corner case though as Robert mentioned?
And in virtualisation environments (not public cloud), disks are no longer cheap, as you have many, many virtual machines. So why for you a jump from 8 GB to 10 GB in the public cloud is no big problem, a lot of customers would like to see that we use only 4 GB, as that would allow them to store double as many virtual machines as today. And the LTE fraction would even like to see images in the 150MB range...
I think the statement is accurate that storage prices are going down as technology progresses, not up. There might be stalls in that development from time to time, but I think the trend is clear [1].
Having these numbers is interesting but what is the goal of the image you want to build and what is the benefit of the smaller size for JeOS or MicriOS?
The requested goal by our big customers are less than 500MB, else see above.
And no, we don't want any of your proposed hacks, we are very happy that we were able to remove all of this hacks from building images. This only breaks RPM and updating the images.
I wouldn't consider using KIWI for custom size adjustments a hack but rather the appropriate way customizing images. As long as the method isn't obscure and complicated, I would prefer it over a one-fits-all solution as proposed in the original post. Thanks, Adrian
[1] https://www.backblaze.com/blog/hard-drive-cost-per-gigabyte/ -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Fri, Oct 05, John Paul Adrian Glaubitz wrote:
On 10/4/18 7:33 PM, Thorsten Kukuk wrote:
On Thu, Oct 04, Robert Schweikert wrote:
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
Ever downloaded an image at every boot via LTE? That's what some of our customers are doing, as they don't want to send technicians out in the wild to do that via usb stick.
Wouldn't that be a corner case though as Robert mentioned?
Not really, the number of thus machines is higher than in a typical datacenter.
And in virtualisation environments (not public cloud), disks are no longer cheap, as you have many, many virtual machines. So why for you a jump from 8 GB to 10 GB in the public cloud is no big problem, a lot of customers would like to see that we use only 4 GB, as that would allow them to store double as many virtual machines as today. And the LTE fraction would even like to see images in the 150MB range...
I think the statement is accurate that storage prices are going down as technology progresses, not up. There might be stalls in that development from time to time, but I think the trend is clear [1].
If the need for more storage is growing faster than the price is going down, storage is getting more expensive. And a lot of datacenters are in this situation. If you can double the number of virtual machines by cutting them into halves: the price of the storage cannot going down that fast and big enough as that doubling the storage would be cheaper. Thorsten -- Thorsten Kukuk, Distinguished Engineer, Senior Architect SLES & CaaSP SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nuernberg, Germany GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 10/5/18 7:15 AM, Thorsten Kukuk wrote:
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
Ever downloaded an image at every boot via LTE? That's what some of our customers are doing, as they don't want to send technicians out in the wild to do that via usb stick.
Wouldn't that be a corner case though as Robert mentioned?
Not really, the number of thus machines is higher than in a typical datacenter.
Hmm, do we have any numbers on this? Are these micro images now the most common use case of openSUSE/SLE these days? Unless I am misunderstanding, the suggested change would affect all installations of openSUSE/SLE while the benefit would only be measurable for cloud instances. Adrian -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
If you can double the number of virtual machines by cutting them into halves: the price of the storage cannot going down that fast and big enough as that doubling the storage would be cheaper.
If the goal is to massively increase the number of VMs that can be run on the available storage an alternative approach is to use de-duplication, either automatic on the host filesystem or block level, or manually with qemu qcow2 base images. For booting over a metered network connection, it's not the size of the remote image that matters but how much of it is transferred. As far as I know, python uses the time of last modification to decide whether to re-compile, i.e. the contents of the py files are normally not requested. Therefore, to reduce the network traffic, one needs to minimise how much traffic is wasted on py data due to block sharing and readahead, e.g. with mksquashfs -sort. -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Friday 2018-10-05 10:10, Joachim Wagner wrote:
If you can double the number of virtual machines by cutting them into halves: the price of the storage cannot going down that fast and big enough as that doubling the storage would be cheaper.
For booting over a metered network connection, it's not the size of the remote image that matters but how much of it is transferred.
Negative - it depends on your mechanism of transfer (in other words, implementation). Only if you have block-based transfer, like sshfs, nfs, or HTTP (again, if the implementation is smart enough), then that works. Otherwise, everything counts. Like when yast2 loads the 6-file-comprising rescue image. -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
For booting over a metered network connection, it's not the size of the remote image that matters but how much of it is transferred.
Negative - it depends on your mechanism of transfer (in other words, implementation). Only if you have block-based transfer [...]
Otherwise, everything counts. Like when yast2 loads the 6-file-comprising rescue image.
If somebody chooses to download the full image at every boot then either they are not aware of the possibility of block-based transfer or the costs of the network connection do not hurt enough to re-think the implementation. Re-reading Alberto's messages, however, he seems to have sufficient local storage for both py and pyc files. @Alberto: What specific practical problem are you trying to solve by reducing the size of python modules? -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Friday, October 5, 2018 11:04:53 AM CEST Joachim Wagner wrote:
Re-reading Alberto's messages, however, he seems to have sufficient local storage for both py and pyc files. @Alberto: What specific practical problem are you trying to solve by reducing the size of python modules?
That is correct, I have space in my local machine. I think that the first practical problem that I want to solve is not make JeOS or MicroOS so big only for requiring some Python code in it. This will decrease the download time and the dd time. I do no want to grow the image by +1.3 x [.py size]. Growing in size so fast makes, IMHO, Python a bit less interesting when I want to include it in my images and containers. Also can save a lot of space (and make the installation a bit faster) on big Python projects, like OpenStack. At the end I expect that including cloud-init or salt-minion in my images will have half of the requirements in size that we actually have, without sacrificing speed and easy to debug. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
I think that the first practical problem that I want to solve is not make JeOS or MicroOS so big only for requiring some Python code in it.
Thanks. Googling these names, they seem to be Linux distributions. If these are distributed as read-to-run images, my answer would be to simply delete the unwanted files before shipping, e.g. in the dockerfile. If, however, these distributions are installed from packages the ongoing discussion about tagging the files in the rpm is probably the right track. -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 2018-10-05T07:15:29, Thorsten Kukuk
Ever downloaded an image at every boot via LTE?
If distribution times are crucial, doesn't this sound like a need for an incremental/differential distribution mechanism? I mean, I get it, reducing the base is really helpful, but a local cache of some form seems highly desirable to further reduce the impact. Regards, Lars -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg) "Architects should open possibilities and not determine everything." (Ueli Zbinden) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
Am 04.10.18 um 19:33 schrieb Thorsten Kukuk:
And the LTE fraction would even like to see images in the 150MB range...
How about telling them to just avoid python at all, then? If I have some Internet-of-Shit thing that boots via LTE, it surely also has a cheap CPU and as little RAM as possible. So I'd better use something that does more work per watt. Python obviously (as can be seen from this thread) is one of the worst possible choices for that task.
And no, we don't want any of your proposed hacks, we are very happy that we were able to remove all of this hacks from building images. This only breaks RPM and updating the images.
They are booted every time via LTE and then updated with rpm? Come on, get serious, you are not going to believe what you are trying to sell us here, are you? Penalizing all openSUSE users (this is opensuse-factory after all) and all serious SLES customers for some crazy embedded fringe scenario is -- ahem -- worth discussing. -- Stefan Seyfried "For a successful technology, reality must take precedence over public relations, for nature cannot be fooled." -- Richard Feynman -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Fri, Oct 05, Stefan Seyfried wrote:
They are booted every time via LTE and then updated with rpm? Come on, get serious, you are not going to believe what you are trying to sell us here, are you?
Please read again. What you claim is not what I wrote. Thorsten -- Thorsten Kukuk, Distinguished Engineer, Senior Architect SLES & CaaSP SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nuernberg, Germany GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thursday 2018-10-04 19:23, Robert Schweikert wrote:
Backend storage is very fast these days
For some definition of "fast". -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Thursday, October 4, 2018 7:23:45 PM CEST Robert Schweikert wrote:
On 10/4/18 10:52 AM, Alberto Planas Dominguez wrote:
But this also makes the Python stack a bit fat. Most of the time this is not a problem, but things are changing. We have JeOS and MicroOS, both minimal images (build with different goals and technology) that search for be small and slim.
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
I can think of 1 trade-of, in the Cloud, when a new instance is created the image file is copied. Therefore a smaller image improves the overall instance start up as there is less data to copy. However, from my experience in GCE, where we at some point built 8GB images then switched to 10 GB images, there was no noticeable difference between the two image sizes w.r.t. start up time of an instance.
That is a good example, indeed. The main problem is that the ration py / pyc is around 1.3 to 1.5, so for each KB of .py I have to add 1.3 or 1.5 of .pyc. We are more than doubling the space. I can think how removing more than a half of the size can overall improve the speed of upgrading a system, the size of the rpm and drpm, the download time of JeOS and MicroOS or the time to upload something to Cinder.
But we want to include a bit of Python in there, like salt-minion or cloud-init. And now the relative size of Python is evident.
Well, especially for cloud-init at the last couple of get together events of upstream contributors start up time for cloud-init was a big discussion point. A lot of effort has gone into making cloud-init faster. The results of this effort would be eliminated with such a move.
I plan to measure this. The first boot can be slower, but I am still not able to have numbers here. This argument can be indeed relevant and make the proposal a bad one, but by far I do not think that the big chunk of time goes under the pyc generation in the cloud-init case, as there are more architectural problems in that.
Having these numbers is interesting but what is the goal of the image you want to build and what is the benefit of the smaller size for JeOS or MicriOS?
I have one local that I am replicating it in OBS. Will appear today or this weeked in the repo pointed in the first email.
Maybe for a normal TW installation the absolute gain is not much (91M).
Well it is not just the install. We would be penalizing every user with a start up time penalty to save 91M, sorry that appears to me as an optimization for the corner case at the expense of the most common path.
I do not see the penalization, sorry. The proposal is not to wipe out pyc and use -B when calling the Python code, is about moving the pyc generation in / var/cache (or some other cache place) and delay the pyc generation until the first boot. The difference is that pyc will be there, maybe in a ram disk, or in a faster fs, or in the same old harddisk than always. If there is a considerable penalty on the first launch, we can thing on alternatives, like making the feature optional or prepopulating a subset of the stack.
So, my proposal is to remove the pyc from the Python 3 packages and enable the cache layer on Tumbleweed since Python 3.7. I do not know if do that by default or under certain configurations, as I am not sure how to that feature optional.
Any ideas?
IMHO there are mechanism for you to do this for the corner cases, i.e. JeOS and MicroOS image builds. It is very easy with kiwi to run "find / -name '*.pyc' | xargs rm ' during the image build state. This gives you what you are after, a smaller image size without penalizing everyone else.
Well, this is how I am testing it now.
What do you think if I follow this path?
I oppose this path. We'd be penalizing every start up of every instance of EC2. We have feature requests to improve our boot performance and this is counter acting our efforts.
Not true, as the cache will be populated after the first boot. And again, by far the slowest path is not the pyc generation. But I agree that I need to deliver the numbers. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 10/5/18 4:23 AM, Alberto Planas Dominguez wrote:
On Thursday, October 4, 2018 7:23:45 PM CEST Robert Schweikert wrote:
On 10/4/18 10:52 AM, Alberto Planas Dominguez wrote:
But this also makes the Python stack a bit fat. Most of the time this is not a problem, but things are changing. We have JeOS and MicroOS, both minimal images (build with different goals and technology) that search for be small and slim.
Can you share the definition of "small and slim". What is the target size we want to get to and why does it matter if the image is a "bit" bigger?
I can think of 1 trade-of, in the Cloud, when a new instance is created the image file is copied. Therefore a smaller image improves the overall instance start up as there is less data to copy. However, from my experience in GCE, where we at some point built 8GB images then switched to 10 GB images, there was no noticeable difference between the two image sizes w.r.t. start up time of an instance.
That is a good example, indeed. The main problem is that the ration py / pyc is around 1.3 to 1.5, so for each KB of .py I have to add 1.3 or 1.5 of .pyc. We are more than doubling the space.
I can think how removing more than a half of the size can overall improve the speed of upgrading a system, the size of the rpm and drpm, the download time of JeOS and MicroOS or the time to upload something to Cinder.
Can you please formulate your goals concisely and stick to it? Are we back to discussing side effects? This is confusing. You started out stating that there is a goal to reduce image sizes for JeOS and MicroOS builds and that Python was a contributing factor to image "bloat". This was seconded by Thorsten providing a specific use case where we have people asking for 150 MB images. The image size and the size of the rpm are tangentially related. By example, an rpm contains docs, this contributes to the rpm size, but these can easily be excluded at install time with the --excludedocs option, and thus would not contribute to a measure such as image size. So the relationship you are creating with the download and upgrade example is really a different cup of tea than the goal, as I read it, in the original proposal. If your goal is to reduce the size of the Python packages then we probably need a different solution compared to a goal that produces a smaller image size when Python is part of an image.
But we want to include a bit of Python in there, like salt-minion or cloud-init. And now the relative size of Python is evident.
Well, especially for cloud-init at the last couple of get together events of upstream contributors start up time for cloud-init was a big discussion point. A lot of effort has gone into making cloud-init faster. The results of this effort would be eliminated with such a move.
I plan to measure this. The first boot can be slower, but I am still not able to have numbers here. This argument can be indeed relevant and make the proposal a bad one, but by far I do not think that the big chunk of time goes under the pyc generation in the cloud-init case, as there are more architectural problems in that.
Well I think the common agreement is that pyc generation is pretty slow. But lets put some perspective behind that and look at data rather than taking common believes as facts. On a t2.micro instance in AWS, running the SUSE stock SLES 15 BYOS image. The instance was booted (first boot), then the cloud-init cache was cleared with # cloud-init clean then shutdown -r now, i.e. a soft reboot of the VM. # systemd-analyze blame | grep cloud 6.505s cloud-init-local.service 1.013s cloud-config.service 982ms cloud-init.service 665ms cloud-final.service All these services are part of cloud-init Clear the cloud-init cache so it will re-run # cloud-init clean Clear out all Python artifacts: # cd / # find . -name '__pycache__' | xargs rm -rf # find . -name '*.pyc' | xargs rm # find . -name '*.pyo' | xargs rm This should reasonably approximate the state you are proposing, I think. Reboot: # systemd-analyze blame | grep cloud 7.469s cloud-init-local.service 1.070s cloud-init.service 976ms cloud-config.service 671ms cloud-final.service so a 13% increase for the runtime of the cloud-init-local service. And this is just a quick and dirty test with a soft reboot of the VM. Number would probably be worse with a stop-start cycle. I'll leave that to be dis-proven for those interested.
Having these numbers is interesting but what is the goal of the image you want to build and what is the benefit of the smaller size for JeOS or MicriOS?
I have one local that I am replicating it in OBS. Will appear today or this weeked in the repo pointed in the first email.
Maybe for a normal TW installation the absolute gain is not much (91M).
Well it is not just the install. We would be penalizing every user with a start up time penalty to save 91M, sorry that appears to me as an optimization for the corner case at the expense of the most common path.
I do not see the penalization, sorry.
Well I'd say the penalty is shown above, 13% in one particular example. This or worse would hit our users every time they start a new instance in AWS, GCE, Azure, OpenStack,.....
The proposal is not to wipe out pyc
The way I read your proposal was to eliminate py{c,o} from the packages, i.e. we have to byte-compile when any python module is used
and use -B when calling the Python code, is about moving the pyc generation in / var/cache (or some other cache place) and delay the pyc generation until the first boot.
OK, this part of the statement seems in line with my understanding of your proposal. You say "first-boot" are you implying a process that does a system-wide byte compilation of all installed Python code? That would probably add a rather large time penalty to first boot and is not going to work for us in the Public Cloud. But data would have to be collected on such a process to make a real decision. Or do you mean "module load" when you say "first boot", i.e. the byte-compilation takes place when a Python module is loaded for the first time? The effect of this is shown in the above example. I have an issue with a 13% drop in performance for every user on initial start up. This is penalizing the majority to cover one specific use case. Sorry it is hard for me to see this any other way.
The difference is that pyc will be there, maybe in a ram disk, or in a faster fs, or in the same old harddisk than always.
If there is a considerable penalty on the first launch, we can thing on alternatives, like making the feature optional or prepopulating a subset of the stack.
So, my proposal is to remove the pyc from the Python 3 packages and enable the cache layer on Tumbleweed since Python 3.7. I do not know if do that by default or under certain configurations, as I am not sure how to that feature optional.
Any ideas?
IMHO there are mechanism for you to do this for the corner cases, i.e. JeOS and MicroOS image builds. It is very easy with kiwi to run "find / -name '*.pyc' | xargs rm ' during the image build state. This gives you what you are after, a smaller image size without penalizing everyone else.
Well, this is how I am testing it now.
What do you think if I follow this path?
I oppose this path. We'd be penalizing every start up of every instance of EC2. We have feature requests to improve our boot performance and this is counter acting our efforts.
Not true, as the cache will be populated after the first boot.
How is my statement not true? Above you state that the cache is filled on "first boot". I hope we can all agree that byte-compilation is not a 0 time operation. Therefore, there is a time penalty in the boot process in some way shape or form. Increasing the boot time is counter to our efforts to reduce the boot time for our cloud images.
And again, by far the slowest path is not the pyc generation. But I agree that I need to deliver the numbers.
The numbers in execution time in my crude test above show that pyc is not the slowest for cloud-init, but >10% slow down is not insignificant. I think fiddling at the Python package level is not the best approach to solve the problem, unless of course making the Python packages smaller is your primary goal. Later, Robert -- Robert Schweikert MAY THE SOURCE BE WITH YOU Distinguished Architect LINUX Team Lead Public Cloud rjschwei@suse.com IRC: robjo
On Sat, Oct 06, Robert Schweikert wrote:
Can you please formulate your goals concisely and stick to it? Are we back to discussing side effects? This is confusing.
The goal is the same as with every iteration of this dicussion: python is too fat, python3 even more. And a lot of people don't like that for various, different reasons. As I already wrote: size matters again today, for various reasons and use cases. So we need a solution for this. We don't discuss or talk here about a single use case with a special solution, we talk here about a generic problem. And the solutions are quite different. And I don't think we can solve the problem with one change, we need to takle that from various directions and do that already. Albertos suggestion is only one of several things currently going on. Some people rewrite the python scripts in go or bash, other plan to drop them. Like Red Hat plans, according to two presentations last week, to drop cloud-init as it is too fat and slow and either revive the go implementation from CoreOS or replace it with Ignition. Thorsten -- Thorsten Kukuk, Distinguished Engineer, Senior Architect SLES & CaaSP SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nuernberg, Germany GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Sat, Oct 6, 2018 at 12:39 PM Thorsten Kukuk
On Sat, Oct 06, Robert Schweikert wrote:
Can you please formulate your goals concisely and stick to it? Are we back to discussing side effects? This is confusing.
The goal is the same as with every iteration of this dicussion: python is too fat, python3 even more. And a lot of people don't like that for various, different reasons. As I already wrote: size matters again today, for various reasons and use cases. So we need a solution for this.
It may be worth talking to upstream RPM about making %artifact optionally filtered out for install and auto-marking *.py[oc] as artifact files.
We don't discuss or talk here about a single use case with a special solution, we talk here about a generic problem. And the solutions are quite different. And I don't think we can solve the problem with one change, we need to takle that from various directions and do that already. Albertos suggestion is only one of several things currently going on. Some people rewrite the python scripts in go or bash, other plan to drop them. Like Red Hat plans, according to two presentations last week, to drop cloud-init as it is too fat and slow and either revive the go implementation from CoreOS or replace it with Ignition.
Within Fedora, the current effort is around extending Ignition to support everything we use in cloud-init for Fedora instance configuration. Currently, it's scoped to Fedora CoreOS, but there are plans to support the main Fedora Cloud Edition, too. If there's some interest in this for openSUSE, I can port over the ignition packaging from Fedora to openSUSE for people to poke at. -- 真実はいつも一つ!/ Always, there's only one truth! -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Saturday, October 6, 2018 11:24:46 AM CEST Robert Schweikert wrote:
On 10/5/18 4:23 AM, Alberto Planas Dominguez wrote:
[...]
Can you please formulate your goals concisely and stick to it? Are we back to discussing side effects? This is confusing.
Uhmm. Is too hard to understand that the proposal is to remove the pyc, because this is doubling the size of the Python stack? Doing this have some good benefits, and also some bad stuff. The good stuff are related with less size used on RPMs and disk and the implications of this, and the bad stuff are maybe related with security and a penalty the first time the Python code runs. If those side effects confuse you I am not sure how to achieve an informed decision without analyzing those. In any case let me be clear: my goal is to decrease the size of the Python stack, and my proposal is removing the pyc from the initial first install, backporting a feature from 3.8 to have the pyc in a different file system. The backported code is this one: https://build.opensuse.org/package/view_file/home:aplanas:Images/python3/ bpo-33499_Add_PYTHONPYCACHEPREFIX_env_var_for_alt_bytecode.patch?expand=1 I tested it and it works. [...]
If your goal is to reduce the size of the Python packages then we probably need a different solution compared to a goal that produces a smaller image size when Python is part of an image.
I am open to read about other alternatives to make the Python stack size smaller. I can see only two: remove the pyc (and delegating the creation of them on a different file system during the first execution), and analyzing all the Requirements to be sure that there are not extra subtrees installed that are not needed. IMHO both are needed, but my proposal was only about how to use a new feature from 3.8 to achieve a good compromise of speed / size when the pycs are removed from the RPM
But we want to include a bit of Python in there, like salt-minion or cloud-init. And now the relative size of Python is evident.
Well, especially for cloud-init at the last couple of get together events of upstream contributors start up time for cloud-init was a big discussion point. A lot of effort has gone into making cloud-init faster. The results of this effort would be eliminated with such a move.
I plan to measure this. The first boot can be slower, but I am still not able to have numbers here. This argument can be indeed relevant and make the proposal a bad one, but by far I do not think that the big chunk of time goes under the pyc generation in the cloud-init case, as there are more architectural problems in that.
Well I think the common agreement is that pyc generation is pretty slow.
Citation needed. My tests give in my machine a 6.08MB/s of compilation speed. I tested it installing django with python 3.6 in a venv and doing this: # To avoid measure the dir crawling # find . -name "*.py" > LIST # time python -m compileall -f -qq -i LIST real 0m1.406s user 0m1.257s sys 0m0.148s # du -hsb 44812156 . # find . -name "__pycache__" -exec rm -rf {} \; # du -hsb 35888321 . (44812156 - 35888321) / 1.4 ~= 6.08 MB/s
But lets put some perspective behind that and look at data rather than taking common believes as facts.
On a t2.micro instance in AWS, running the SUSE stock SLES 15 BYOS image. The instance was booted (first boot), then the cloud-init cache was cleared with
# cloud-init clean
then shutdown -r now, i.e. a soft reboot of the VM.
# systemd-analyze blame | grep cloud 6.505s cloud-init-local.service 1.013s cloud-config.service 982ms cloud-init.service 665ms cloud-final.service
All these services are part of cloud-init
Clear the cloud-init cache so it will re-run # cloud-init clean
Clear out all Python artifacts:
# cd / # find . -name '__pycache__' | xargs rm -rf # find . -name '*.pyc' | xargs rm # find . -name '*.pyo' | xargs rm
This should reasonably approximate the state you are proposing, I think. Reboot:
# systemd-analyze blame | grep cloud 7.469s cloud-init-local.service 1.070s cloud-init.service 976ms cloud-config.service 671ms cloud-final.service
so a 13% increase for the runtime of the cloud-init-local service. And this is just a quick and dirty test with a soft reboot of the VM. Number would probably be worse with a stop-start cycle. I'll leave that to be dis-proven for those interested.
This is a very nice contribution to the discussion. I tested it in engcloud and I have a 9.3% of overload during the boot. It spend 0.205s to create the initials pyc needed for cloud-init: * With pyc in place # systemd-analyze blame | grep cloud 1.985s cloud-init-local.service 1.176s cloud-init.service 609ms cloud-config.service 531ms cloud-final.service * Without pyc in place # systemd-analyze blame | grep cloud 2.190s cloud-init-local.service 1.165s cloud-init.service 844ms cloud-config.service 528ms cloud-final.service The sad thing is that the __real__ first boot is a bit worse: * First boot. with pyc in place # systemd-analyze blame | grep cloud 36.494s cloud-init.service 2.673s cloud-init-local.service 1.420s cloud-config.service 730ms cloud-final.service Comparing to this real first boot, the pyc cost generation represent the 0.54% for cloud-init (not in relation with the total boot time). We can ignore it, as I guess that the images used for EC2 will have some tweaks to avoid the file system resize, or some other magic that makes the boot more similar to the second boot. Once the pycs are generated they will be reused, so the 0.205s of penalty are amortized in the second and subsequent boots. We still store the pyc in /var/ cache. In any case, 0.205s is not so big for a 15.187 total boot time that this instance have for each new reboot, as the boot time is dominated by other factors as wicked and other services. The image is still in engcloud, is an SLE 12 SP3 under the name 'aplanas- test'. Feel free to access it (send me your public key to have ssh access there) to double check my data.
Well it is not just the install. We would be penalizing every user with a start up time penalty to save 91M, sorry that appears to me as an optimization for the corner case at the expense of the most common path.
I do not see the penalization, sorry.
Well I'd say the penalty is shown above, 13% in one particular example. This or worse would hit our users every time they start a new instance in AWS, GCE, Azure, OpenStack,.....
The cost is amortized, and the corner case, IMHO, is more yours than mine. Your case is a fresh boot of a just installed EC2 VM. I agree that there is a penalty of ~10% (or a 0.54% in my SLE12 SP3 OpenStack case), but this is only for this first boot. But booting just-created VM is hardly the normal use case.
The proposal is not to wipe out pyc
The way I read your proposal was to eliminate py{c,o} from the packages, i.e. we have to byte-compile when any python module is used
and use -B when calling the Python code, is about moving the pyc generation in / var/cache (or some other cache place) and delay the pyc generation until the first boot.
OK, this part of the statement seems in line with my understanding of your proposal.
You say "first-boot" are you implying a process that does a system-wide byte compilation of all installed Python code?
No, the first time that the Python code runs. This strategy have good results as not all the Python code is loaded when a service is running. For example, in the Django venv scenario for this email, the initial size of the venv was 57MB, after removing all the pyc from site- packages I had a venv of 45MB. If I create a new Django application (with database access, models and views) I have a venv of 47MB, so only 2MB of pyc are generated during run time, as I propose. You still save 10MB of space without sacrificing run-time speed.
Or do you mean "module load" when you say "first boot", i.e. the byte-compilation takes place when a Python module is loaded for the first time? The effect of this is shown in the above example. I have an issue with a 13% drop in performance for every user on initial start up.
This is penalizing the majority to cover one specific use case. Sorry it is hard for me to see this any other way.
Again, hardly booting fresh VMs is a majority here. [...]
What do you think if I follow this path?
I oppose this path. We'd be penalizing every start up of every instance of EC2. We have feature requests to improve our boot performance and this is counter acting our efforts.
Not true, as the cache will be populated after the first boot.
How is my statement not true?
How maintaining a a /var/cache is going to penalize every start up of every instance of EC2? That is not true, again. You are populating /var/cache with the modules used the first time. Subsequent boots will not be penalized. This is an amortization case, so at the end, there is no penalty.
And again, by far the slowest path is not the pyc generation. But I agree that I need to deliver the numbers.
The numbers in execution time in my crude test above show that pyc is not the slowest for cloud-init, but >10% slow down is not insignificant.
I do not want to impose any sub-optimal technical solution that hurt openSUSE and the Python developers, but this argument of yours is not complete. For the normal qcow2 image generated by kiwi, the penalty of sle12sp3 is ~0.5% for cloud-init, not for the total boot time. Fixing the resize issue makes the same 0.205s invested to generate the pyc, a ~10% of the time that cloud-init uses to start the service. In this case the cloud-init time is around 2s, where the total boot time is about 15.2s.
I think fiddling at the Python package level is not the best approach to solve the problem, unless of course making the Python packages smaller is your primary goal.
I agree that this needs to be addressed too. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 10/8/18 7:35 AM, Alberto Planas Dominguez wrote:
On Saturday, October 6, 2018 11:24:46 AM CEST Robert Schweikert wrote:
On 10/5/18 4:23 AM, Alberto Planas Dominguez wrote:
[...]
Can you please formulate your goals concisely and stick to it? Are we back to discussing side effects? This is confusing.
Uhmm. Is too hard to understand that the proposal is to remove the pyc, because this is doubling the size of the Python stack?
No this has nothing to do with the proposal. Paraphrasing: You started out by stating that the problem you are trying to solve is the size of images, namely JeOS and MicroOS, at least that is the way I read the initial mail. Then you proposed that one way to do this is to drop pyc from the packages. And I am not denying that this may be one approach. However, this is not the only way to get there, as this discussion has shown. Further this discussion has shown that the relationship between rpm size and image size is tangential. Along the way you have drifted to pushing "rpm size" as an important topic rather than sticking to the original problem definition of "image size" as the problem to be solved.
Doing this have some good benefits, and also some bad stuff. The good stuff are related with less size used on RPMs and disk and the implications of this, and the bad stuff are maybe related with security and a penalty the first time the Python code runs.
If those side effects confuse you I am not sure how to achieve an informed decision without analyzing those.
The side effects are not confusing, I am trying to figure out which of the problems, image size or rpm size is the more important one to you to be solved.
In any case let me be clear: my goal is to decrease the size of the Python stack, and my proposal is removing the pyc from the initial first install, backporting a feature from 3.8 to have the pyc in a different file system.
OK, this is different from the original e-mail where it was implied that "image size" was the primary target. Thus marking things as %artifact in RPM wouldn't really help with this goal as the package size would remain the same or might grow slightly as there would be more metadata in the package.
The backported code is this one:
https://build.opensuse.org/package/view_file/home:aplanas:Images/python3/ bpo-33499_Add_PYTHONPYCACHEPREFIX_env_var_for_alt_bytecode.patch?expand=1
I tested it and it works.
[...]
If your goal is to reduce the size of the Python packages then we probably need a different solution compared to a goal that produces a smaller image size when Python is part of an image.
I am open to read about other alternatives to make the Python stack size smaller. I can see only two: remove the pyc (and delegating the creation of them on a different file system during the first execution), and analyzing all the Requirements to be sure that there are not extra subtrees installed that are not needed.
IMHO both are needed, but my proposal was only about how to use a new feature from 3.8 to achieve a good compromise of speed / size when the pycs are removed from the RPM
But we want to include a bit of Python in there, like salt-minion or cloud-init. And now the relative size of Python is evident.
Well, especially for cloud-init at the last couple of get together events of upstream contributors start up time for cloud-init was a big discussion point. A lot of effort has gone into making cloud-init faster. The results of this effort would be eliminated with such a move.
I plan to measure this. The first boot can be slower, but I am still not able to have numbers here. This argument can be indeed relevant and make the proposal a bad one, but by far I do not think that the big chunk of time goes under the pyc generation in the cloud-init case, as there are more architectural problems in that.
Well I think the common agreement is that pyc generation is pretty slow.
Citation needed.
You are reading this thread, right? At least 2 other people that are part of the discussion mentioned this as a concern. But OK, I should have used "sentiment" rather than "agreement" in my statement.
My tests give in my machine a 6.08MB/s of compilation speed. I tested it installing django with python 3.6 in a venv and doing this:
# To avoid measure the dir crawling # find . -name "*.py" > LIST # time python -m compileall -f -qq -i LIST
real 0m1.406s user 0m1.257s sys 0m0.148s
# du -hsb 44812156 .
# find . -name "__pycache__" -exec rm -rf {} \; # du -hsb 35888321 .
(44812156 - 35888321) / 1.4 ~= 6.08 MB/s
But lets put some perspective behind that and look at data rather than taking common believes as facts.
On a t2.micro instance in AWS, running the SUSE stock SLES 15 BYOS image. The instance was booted (first boot), then the cloud-init cache was cleared with
# cloud-init clean
then shutdown -r now, i.e. a soft reboot of the VM.
# systemd-analyze blame | grep cloud 6.505s cloud-init-local.service 1.013s cloud-config.service 982ms cloud-init.service 665ms cloud-final.service
All these services are part of cloud-init
Clear the cloud-init cache so it will re-run # cloud-init clean
Clear out all Python artifacts:
# cd / # find . -name '__pycache__' | xargs rm -rf # find . -name '*.pyc' | xargs rm # find . -name '*.pyo' | xargs rm
This should reasonably approximate the state you are proposing, I think. Reboot:
# systemd-analyze blame | grep cloud 7.469s cloud-init-local.service 1.070s cloud-init.service 976ms cloud-config.service 671ms cloud-final.service
so a 13% increase for the runtime of the cloud-init-local service. And this is just a quick and dirty test with a soft reboot of the VM. Number would probably be worse with a stop-start cycle. I'll leave that to be dis-proven for those interested.
This is a very nice contribution to the discussion.
I tested it in engcloud and I have a 9.3% of overload during the boot. It spend 0.205s to create the initials pyc needed for cloud-init:
That would not be sufficient, all pycs in the dependency tree would need to be generated, you cannot just measure the creation of the cloud-init pyc files. cloud-init is going to be one of, if not the first Python processes running in the boot sequence, which implies that no pyc files exist for the cloud-init dependencies.
* With pyc in place
# systemd-analyze blame | grep cloud 1.985s cloud-init-local.service 1.176s cloud-init.service 609ms cloud-config.service 531ms cloud-final.service
* Without pyc in place
# systemd-analyze blame | grep cloud 2.190s cloud-init-local.service 1.165s cloud-init.service 844ms cloud-config.service 528ms cloud-final.service
The sad thing is that the __real__ first boot is a bit worse:
* First boot. with pyc in place
# systemd-analyze blame | grep cloud 36.494s cloud-init.service 2.673s cloud-init-local.service 1.420s cloud-config.service 730ms cloud-final.service
Comparing to this real first boot, the pyc cost generation represent the 0.54% for cloud-init (not in relation with the total boot time). We can ignore it, as I guess that the images used for EC2 will have some tweaks to avoid the file system resize, or some other magic that makes the boot more similar to the second boot.
First boot execution of cloud-init is also significantly slower in the Public Cloud. However, not as bad as in your example. In any case your second comparison appears to making a leap that I, at this point do not agree with. You are equating the generation of pyc code in a "hot system" to the time it takes to load everything in a "cold system". A calculation of percentage contribution of pyc creation in a "cold system" would only be valid if that scenario were tested. Which we have not done, but would certainly not be too difficult to test.
Once the pycs are generated they will be reused, so the 0.205s of penalty are amortized in the second and subsequent boots. We still store the pyc in /var/ cache.
In any case, 0.205s is not so big for a 15.187 total boot time that this instance have for each new reboot, as the boot time is dominated by other factors as wicked and other services.
The image is still in engcloud, is an SLE 12 SP3 under the name 'aplanas- test'. Feel free to access it (send me your public key to have ssh access there) to double check my data.
Well it is not just the install. We would be penalizing every user with a start up time penalty to save 91M, sorry that appears to me as an optimization for the corner case at the expense of the most common path.
I do not see the penalization, sorry.
Well I'd say the penalty is shown above, 13% in one particular example. This or worse would hit our users every time they start a new instance in AWS, GCE, Azure, OpenStack,.....
The cost is amortized, and the corner case, IMHO, is more yours than mine. Your case is a fresh boot of a just installed EC2 VM. I agree that there is a penalty of ~10% (or a 0.54% in my SLE12 SP3 OpenStack case), but this is only for this first boot.
Which is a problem for those users that start a lot of instances to throw them away and start new instances the next time they are needed. This would be a typical autoscaling use case or a typical test use case. It is relatively easy to calculate a cost for this with some estimates. If my test for my application needs 2000 (an arbitrary number I picked) test instances, and every test instance takes .2 seconds longer to boot, to use your number, than the total time penalty is ~6.7 seconds. If this test uses an instance type that costs me $10 per hour the slow down costs me ~ $1.1 every time I run my test. So if the test case runs once a week it would amount to ~$57 per year. If we go with the 1 second penalty in my example it's going to be more expensive.
But booting just-created VM is hardly the normal use case.
The proposal is not to wipe out pyc
The way I read your proposal was to eliminate py{c,o} from the packages, i.e. we have to byte-compile when any python module is used
and use -B when calling the Python code, is about moving the pyc generation in / var/cache (or some other cache place) and delay the pyc generation until the first boot.
OK, this part of the statement seems in line with my understanding of your proposal.
You say "first-boot" are you implying a process that does a system-wide byte compilation of all installed Python code?
No, the first time that the Python code runs.
This strategy have good results as not all the Python code is loaded when a service is running. For example, in the Django venv scenario for this email, the initial size of the venv was 57MB, after removing all the pyc from site- packages I had a venv of 45MB. If I create a new Django application (with database access, models and views) I have a venv of 47MB, so only 2MB of pyc are generated during run time, as I propose. You still save 10MB of space without sacrificing run-time speed.
Or do you mean "module load" when you say "first boot", i.e. the byte-compilation takes place when a Python module is loaded for the first time? The effect of this is shown in the above example. I have an issue with a 13% drop in performance for every user on initial start up.
This is penalizing the majority to cover one specific use case. Sorry it is hard for me to see this any other way.
Again, hardly booting fresh VMs is a majority here.
That is an assumption on your part, from my perspective. Data I can produce has no place on this list, sorry, so I will share in private e-mail when I have it.
[...]
What do you think if I follow this path?
I oppose this path. We'd be penalizing every start up of every instance of EC2. We have feature requests to improve our boot performance and this is counter acting our efforts.
Not true, as the cache will be populated after the first boot.
How is my statement not true?
How maintaining a a /var/cache is going to penalize every start up of every instance of EC2?
Every time I start a new instance the cache has to be created as no pyc files would be in the image. If we pursue the approach of multiple packages, as suggested in one or two messages in this thread, then we could build Public Cloud images with pyc files included.
That is not true, again. You are populating /var/cache with the modules used the first time.
Yes, and the cache is initially empty and has to be filled.
Subsequent boots will not be penalized.
I am not talking about subsequent boots of a stopped instance.
This is an amortization case, so at the end, there is no penalty.
No sorry, it is not free. If you have to pay a $5 parking ticket because you forgot to put money in the meter it doesn't matter how many times you park at the meter and put money in, you will always have paid the $5, you're not getting the money back. If cloud-init is 10% slower, an assumption as we have no data at this point for a cold start, on first boot, it is 10% slower. We are not getting that time back, it is time spent and lost. Later, Robert -- Robert Schweikert MAY THE SOURCE BE WITH YOU Distinguished Architect LINUX Team Lead Public Cloud rjschwei@suse.com IRC: robjo
On Monday, October 8, 2018 4:55:33 PM CEST Robert Schweikert wrote:
On 10/8/18 7:35 AM, Alberto Planas Dominguez wrote:
On Saturday, October 6, 2018 11:24:46 AM CEST Robert Schweikert wrote:
On 10/5/18 4:23 AM, Alberto Planas Dominguez wrote:
[Dropping a very unproductive content]
In any case let me be clear: my goal is to decrease the size of the Python stack, and my proposal is removing the pyc from the initial first install, backporting a feature from 3.8 to have the pyc in a different file system.
OK, this is different from the original e-mail where it was implied that "image size" was the primary target.
That was my initial motivator, yes. But the goal, I hope, is clear now with my previous paragraph.
My tests give in my machine a 6.08MB/s of compilation speed. I tested it installing django with python 3.6 in a venv and doing this:
# To avoid measure the dir crawling # find . -name "*.py" > LIST # time python -m compileall -f -qq -i LIST
real 0m1.406s user 0m1.257s sys 0m0.148s
# du -hsb 44812156 .
# find . -name "__pycache__" -exec rm -rf {} \; # du -hsb 35888321 .
(44812156 - 35888321) / 1.4 ~= 6.08 MB/s
But lets put some perspective behind that and look at data rather than taking common believes as facts.
On a t2.micro instance in AWS, running the SUSE stock SLES 15 BYOS image. The instance was booted (first boot), then the cloud-init cache was cleared with
# cloud-init clean
then shutdown -r now, i.e. a soft reboot of the VM.
# systemd-analyze blame | grep cloud
6.505s cloud-init-local.service 1.013s cloud-config.service
982ms cloud-init.service 665ms cloud-final.service
All these services are part of cloud-init
Clear the cloud-init cache so it will re-run # cloud-init clean
Clear out all Python artifacts:
# cd / # find . -name '__pycache__' | xargs rm -rf # find . -name '*.pyc' | xargs rm # find . -name '*.pyo' | xargs rm
This should reasonably approximate the state you are proposing, I think. Reboot:
# systemd-analyze blame | grep cloud
7.469s cloud-init-local.service 1.070s cloud-init.service
976ms cloud-config.service 671ms cloud-final.service
so a 13% increase for the runtime of the cloud-init-local service. And this is just a quick and dirty test with a soft reboot of the VM. Number would probably be worse with a stop-start cycle. I'll leave that to be dis-proven for those interested.
This is a very nice contribution to the discussion.
I tested it in engcloud and I have a 9.3% of overload during the boot. It
spend 0.205s to create the initials pyc needed for cloud-init:
That would not be sufficient, all pycs in the dependency tree would need to be generated, you cannot just measure the creation of the cloud-init pyc files. cloud-init is going to be one of, if not the first Python processes running in the boot sequence, which implies that no pyc files exist for the cloud-init dependencies.
Of course it is enough for the argument. In fact is a critical part of the discussion: you delegate the pyc create when they are needed, and once required will be stored in the cache. When cloud-init is loaded, Python will read all the `import`s and the required subtree of pyc will be generated before the execution of _any_ Python code. You are not compiling only the pyc from cloud-init, but for all the dependencies that are required. Unless there are some lazy load in cloud-init based on something like stevedore (that I do not see), or is full for `import`s inside functions and methods, the pyc generation of the required subtree will be the first thing that Python will do.
* With pyc in place
# systemd-analyze blame | grep cloud
1.985s cloud-init-local.service 1.176s cloud-init.service
609ms cloud-config.service 531ms cloud-final.service
* Without pyc in place
# systemd-analyze blame | grep cloud
2.190s cloud-init-local.service 1.165s cloud-init.service
844ms cloud-config.service 528ms cloud-final.service
The sad thing is that the __real__ first boot is a bit worse:
* First boot. with pyc in place
# systemd-analyze blame | grep cloud
36.494s cloud-init.service
2.673s cloud-init-local.service 1.420s cloud-config.service
730ms cloud-final.service
Comparing to this real first boot, the pyc cost generation represent the 0.54% for cloud-init (not in relation with the total boot time). We can ignore it, as I guess that the images used for EC2 will have some tweaks to avoid the file system resize, or some other magic that makes the boot more similar to the second boot.
First boot execution of cloud-init is also significantly slower in the Public Cloud. However, not as bad as in your example.
If this is the case, this first boot is the one that will generate the pyc, not the later one.
In any case your second comparison appears to making a leap that I, at this point do not agree with. You are equating the generation of pyc code in a "hot system" to the time it takes to load everything in a "cold system". A calculation of percentage contribution of pyc creation in a "cold system" would only be valid if that scenario were tested. Which we have not done, but would certainly not be too difficult to test.
I do not get the point. At the end we measured the proportion of the time Python spend generating the pyc for cloud-init and all the dependencies needed for the service, in relation with the overall time that cloud init spend during the initialization of the service. I am not sure what do you mean by hot and clod here, as I removed all the pyc from site-packages to have a measure of the relation of the generation of the pyc over the time that cloud init uses to start the service.
The cost is amortized, and the corner case, IMHO, is more yours than mine. Your case is a fresh boot of a just installed EC2 VM. I agree that there is a penalty of ~10% (or a 0.54% in my SLE12 SP3 OpenStack case), but this is only for this first boot.
Which is a problem for those users that start a lot of instances to throw them away and start new instances the next time they are needed. This would be a typical autoscaling use case or a typical test use case.
Correct. The 0.205s will be added for each new fresh VM. Am I correct to assume that also this is an scenario where the resize in the initial boot is happening? If so, the overall impact is much less that the 10% that we are talking about, and more close to the %0.5 that I measured in OpenStack.
It is relatively easy to calculate a cost for this with some estimates. If my test for my application needs 2000 (an arbitrary number I picked) test instances, and every test instance takes .2 seconds longer to boot, to use your number, than the total time penalty is ~6.7 seconds. If this test uses an instance type that costs me $10 per hour the slow down costs me ~ $1.1 every time I run my test. So if the test case runs once a week it would amount to ~$57 per year.
Imagine the cost of the resize of the kiwi operation, must be around some thousands dollars. But you are right. If there is a weekly re-escalation of 2000 instances during the 54 weeks of a year, you can measure the cost of the pyc generation. Is in my understanding that CPU cost is cheaper in relation with network transfer and storage. Can we measure the savings of network and storage here? I have the feeling that are more that 57$ per year. We are interchanging CPU per network and storage savings, that with those 2000 instances per week during a full year will be also measurable.
This is penalizing the majority to cover one specific use case. Sorry it is hard for me to see this any other way.
Again, hardly booting fresh VMs is a majority here.
That is an assumption on your part, from my perspective.
Do you really thing that TW and Leap are optimized for boot speed in a cloud scenario? If the majority of users are launching all day and night VMs I vote to optimize this use case before anything else.
If we pursue the approach of multiple packages, as suggested in one or two messages in this thread, then we could build Public Cloud images with pyc files included.
Or better, the user can add a `python -m compileall` in the kiwi config.sh, that will populate /var/cache for the cloud images only. I think that we need a productive argumentation here. All engineering decisions are based on a trade-off. Some times the trade-off do not pay by itself, but I really think that this is not the case. Or at least your arguments so far do not point in this direction. If / when the use case is such that the trade-off between space and cpu is so critical (scenario that is not the one that you described, I am sorry), the opportunities for optimization are in a different place. And we need to address those too. In a classical use case the savings in space in the different places are justified IMHO, and the amortization of the pyc generation will be justified in less than 2 seconds after the service is running for the first time. In a cloud use case the user can boot the image, prepare it (avoiding the penalty of the resize step and other details), update it and save it as a volume that can be cloned those 2000 times, completely avoiding any penalization for the pyc generation too. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 10/8/18 12:07 PM, Alberto Planas Dominguez wrote:
On Monday, October 8, 2018 4:55:33 PM CEST Robert Schweikert wrote:
On 10/8/18 7:35 AM, Alberto Planas Dominguez wrote:
On Saturday, October 6, 2018 11:24:46 AM CEST Robert Schweikert wrote:
On 10/5/18 4:23 AM, Alberto Planas Dominguez wrote:
[Dropping a very unproductive content]
I am really trying hard to leave out "color commentary" and adjectives, it would be nice to see the effort reciprocated.
In any case let me be clear: my goal is to decrease the size of the Python stack, and my proposal is removing the pyc from the initial first install, backporting a feature from 3.8 to have the pyc in a different file system.
OK, this is different from the original e-mail where it was implied that "image size" was the primary target.
That was my initial motivator, yes. But the goal, I hope, is clear now with my previous paragraph.
My tests give in my machine a 6.08MB/s of compilation speed. I tested it installing django with python 3.6 in a venv and doing this:
# To avoid measure the dir crawling # find . -name "*.py" > LIST # time python -m compileall -f -qq -i LIST
real 0m1.406s user 0m1.257s sys 0m0.148s
# du -hsb 44812156 .
# find . -name "__pycache__" -exec rm -rf {} \; # du -hsb 35888321 .
(44812156 - 35888321) / 1.4 ~= 6.08 MB/s
But lets put some perspective behind that and look at data rather than taking common believes as facts.
On a t2.micro instance in AWS, running the SUSE stock SLES 15 BYOS image. The instance was booted (first boot), then the cloud-init cache was cleared with
# cloud-init clean
then shutdown -r now, i.e. a soft reboot of the VM.
# systemd-analyze blame | grep cloud
6.505s cloud-init-local.service 1.013s cloud-config.service
982ms cloud-init.service 665ms cloud-final.service
All these services are part of cloud-init
Clear the cloud-init cache so it will re-run # cloud-init clean
Clear out all Python artifacts:
# cd / # find . -name '__pycache__' | xargs rm -rf # find . -name '*.pyc' | xargs rm # find . -name '*.pyo' | xargs rm
This should reasonably approximate the state you are proposing, I think. Reboot:
# systemd-analyze blame | grep cloud
7.469s cloud-init-local.service 1.070s cloud-init.service
976ms cloud-config.service 671ms cloud-final.service
so a 13% increase for the runtime of the cloud-init-local service. And this is just a quick and dirty test with a soft reboot of the VM. Number would probably be worse with a stop-start cycle. I'll leave that to be dis-proven for those interested.
This is a very nice contribution to the discussion.
I tested it in engcloud and I have a 9.3% of overload during the boot. It
spend 0.205s to create the initials pyc needed for cloud-init:
That would not be sufficient, all pycs in the dependency tree would need to be generated, you cannot just measure the creation of the cloud-init pyc files. cloud-init is going to be one of, if not the first Python processes running in the boot sequence, which implies that no pyc files exist for the cloud-init dependencies.
Of course it is enough for the argument. In fact is a critical part of the discussion: you delegate the pyc create when they are needed, and once required will be stored in the cache.
When cloud-init is loaded, Python will read all the `import`s and the required subtree of pyc will be generated before the execution of _any_ Python code. You are not compiling only the pyc from cloud-init, but for all the dependencies that are required.
Unless there are some lazy load in cloud-init based on something like stevedore (that I do not see), or is full for `import`s inside functions and methods, the pyc generation of the required subtree will be the first thing that Python will do.
I think we are in agreement, problem appears to be that we have a different idea about what "create the initials pyc needed for cloud-init:" means. For me this arrived as what you stated, i.e. "pyc needed for cloud-init" which says nothing about dependencies. For you this statement appears to imply that the pyc files for the dependencies were also generated in this test. More explicit and concise communication would certainly help.
* With pyc in place
# systemd-analyze blame | grep cloud
1.985s cloud-init-local.service 1.176s cloud-init.service
609ms cloud-config.service 531ms cloud-final.service
* Without pyc in place
# systemd-analyze blame | grep cloud
2.190s cloud-init-local.service 1.165s cloud-init.service
844ms cloud-config.service 528ms cloud-final.service
The sad thing is that the __real__ first boot is a bit worse:
* First boot. with pyc in place
# systemd-analyze blame | grep cloud
36.494s cloud-init.service
2.673s cloud-init-local.service 1.420s cloud-config.service
730ms cloud-final.service
Comparing to this real first boot, the pyc cost generation represent the 0.54% for cloud-init (not in relation with the total boot time). We can ignore it, as I guess that the images used for EC2 will have some tweaks to avoid the file system resize, or some other magic that makes the boot more similar to the second boot.
First boot execution of cloud-init is also significantly slower in the Public Cloud. However, not as bad as in your example.
If this is the case, this first boot is the one that will generate the pyc, not the later one.
In any case your second comparison appears to making a leap that I, at this point do not agree with. You are equating the generation of pyc code in a "hot system" to the time it takes to load everything in a "cold system". A calculation of percentage contribution of pyc creation in a "cold system" would only be valid if that scenario were tested. Which we have not done, but would certainly not be too difficult to test.
I do not get the point. At the end we measured the proportion of the time Python spend generating the pyc for cloud-init and all the dependencies needed for the service, in relation with the overall time that cloud init spend during the initialization of the service.
I am not sure what do you mean by hot and clod here, as I removed all the pyc from site-packages to have a measure of the relation of the generation of the pyc over the time that cloud init uses to start the service.
OK, maybe I can explain this better. We agree that there is a significant difference in the cloud-init execution time between initial start up of the VM vs. a reboot, even if the cloud-init cache (not the pyc files) is cleared. This implies that something is working behind the scene to our advantage and makes a VM reboot faster w.r.t. cloud-init execution when compared to the start a new instance scenario. Given that we do not know what this "makes it work faster" part is, we should not draw any conclusion that the pyc build will take equally as short/long of a time on initial start up as it takes in a "reboot the VM" scenario. This will have to be tested.
The cost is amortized, and the corner case, IMHO, is more yours than mine. Your case is a fresh boot of a just installed EC2 VM. I agree that there is a penalty of ~10% (or a 0.54% in my SLE12 SP3 OpenStack case), but this is only for this first boot.
Which is a problem for those users that start a lot of instances to throw them away and start new instances the next time they are needed. This would be a typical autoscaling use case or a typical test use case.
Correct. The 0.205s will be added for each new fresh VM. Am I correct to assume that also this is an scenario where the resize in the initial boot is happening? If so, the overall impact is much less that the 10% that we are talking about, and more close to the %0.5 that I measured in OpenStack.
The data I presented as an example was generated with a 10GB image size for the creation of an instance with a 10GB root volume size. So there is a, what should be a negligible, contribution from the growpart script, which is called by cloud-init and runs in a subprocess. I attribute "negligible" in this case as growpart will exit very fast is no resizing is required. It still take time for process start up etc. but again I consider this as negligible. But you are correct, by increasing the time it takes for other things cloud-init calls, such as root volume resize, one can decrease the percentage of time allocated to pyc creation. If I would want to take this to an extreme I could start a process during user data processing that runs for several minutes and thus I could make an argument that pyc creation takes almost no time. However, that would be misleading. I think in an effort to arrive as close as reasonably possible at the "real cost" of the pyc generation for the cloud-init example, we should minimize the externally executed processes by cloud-init, such as minimizing the runtime for growpart, which is done by not manipulating the instance root volume size as compared to the image size. The other thing that comes into play when comparing different frameworks is that different modules get loaded by cloud-init and also if we do not have the exact same config file that would also cause differences as cloud-init only loads configuration modules that are needed based on the given configuration, a certain "lazy load" mechanism.
It is relatively easy to calculate a cost for this with some estimates. If my test for my application needs 2000 (an arbitrary number I picked) test instances, and every test instance takes .2 seconds longer to boot, to use your number, than the total time penalty is ~6.7 seconds. If this test uses an instance type that costs me $10 per hour the slow down costs me ~ $1.1 every time I run my test. So if the test case runs once a week it would amount to ~$57 per year.
Imagine the cost of the resize of the kiwi operation, must be around some thousands dollars.
But you are right. If there is a weekly re-escalation of 2000 instances during the 54 weeks of a year, you can measure the cost of the pyc generation.
Is in my understanding that CPU cost is cheaper in relation with network transfer and storage. Can we measure the savings of network and storage here?
Not in the Public Cloud, there is no data. Network data into the framework is always free and the size of the root volumes in our images is already 10GB (30GB in Azure) and thus offers up ample space for the pyc files. Meaning there is no gain if the actual disk space used by the packages we install is smaller and we have more empty space in the 10GB (30GB in Azure) image.
I have the feeling that are more that 57$ per year.
Nope the cost for this to the user in the Public Cloud is 0, see above.
We are interchanging CPU per network and storage savings, that with those 2000 instances per week during a full year will be also measurable.
This is penalizing the majority to cover one specific use case. Sorry it is hard for me to see this any other way.
Again, hardly booting fresh VMs is a majority here.
That is an assumption on your part, from my perspective.
Do you really thing that TW and Leap are optimized for boot speed in a cloud scenario?
No, but whatever we put into TW inevitably ends up in SLE and there it does matter.
If the majority of users are launching all day and night VMs I vote to optimize this use case before anything else.
If we pursue the approach of multiple packages, as suggested in one or two messages in this thread, then we could build Public Cloud images with pyc files included.
Or better, the user can add a `python -m compileall` in the kiwi config.sh, that will populate /var/cache for the cloud images only.
Well, I could turn around and state that this is a "hack" and "...we don't want any of your proposed hacks.." in our image creation process. Hopefully sounds familiar.... ;) Anyway, on a more serious note, if we can resolve the security concerns and properly handle the upgrade mechanism while not generating multiple packages I am not categorically opposed to such an addition in our Public Cloud image builds.
I think that we need a productive argumentation here.
And I thought we were having that for the most part. (My contribution to color commentary)
All engineering decisions are based on a trade-off. Some times the trade-off do not pay by itself, but I really think that this is not the case. Or at least your arguments so far do not point in this direction.
Sorry, I am not following you here, are you dismissing the example of paid CPU for large test cases as invalid? If that is the case, then yes we are not having a productive discussion :( .
If / when the use case is such that the trade-off between space and cpu is so critical (scenario that is not the one that you described, I am sorry), the opportunities for optimization are in a different place. And we need to address those too.
In a classical use case the savings in space in the different places are justified IMHO, and the amortization of the pyc generation will be justified in less than 2 seconds after the service is running for the first time.
In a cloud use case the user can boot the image, prepare it (avoiding the penalty of the resize step and other details), update it and save it as a volume that can be cloned those 2000 times, completely avoiding any penalization for the pyc generation too.
This is not the predominant use case in the Public Cloud, based on information we have from our partners. I would appreciate if, rather than proposing solutions about "how to change people's habits", which almost never work, we'd discuss solutions that can meet the needs of things being pointed out as topics to consider in arriving at the solution. Later, Robert -- Robert Schweikert MAY THE SOURCE BE WITH YOU Distinguished Architect LINUX Team Lead Public Cloud rjschwei@suse.com IRC: robjo
On Monday, October 8, 2018 7:17:08 PM CEST Robert Schweikert wrote:
On 10/8/18 12:07 PM, Alberto Planas Dominguez wrote:
[Dropping a very unproductive content]
I am really trying hard to leave out "color commentary" and adjectives, it would be nice to see the effort reciprocated.
Indeed. Sorry if my choose of words are not correct. Maybe in Spanish I would use something more neutral. [...]
When cloud-init is loaded, Python will read all the `import`s and the required subtree of pyc will be generated before the execution of _any_ Python code. You are not compiling only the pyc from cloud-init, but for all the dependencies that are required.
Unless there are some lazy load in cloud-init based on something like stevedore (that I do not see), or is full for `import`s inside functions and methods, the pyc generation of the required subtree will be the first thing that Python will do.
I think we are in agreement, problem appears to be that we have a different idea about what
"create the initials pyc needed for cloud-init:"
means. For me this arrived as what you stated, i.e. "pyc needed for cloud-init" which says nothing about dependencies. For you this statement appears to imply that the pyc files for the dependencies were also generated in this test.
More explicit and concise communication would certainly help.
I see, I hope that now is clear. The pyc subtree is generated before any Python code runs, as they are generates as soon the `import` statement is parsed. [...]
In any case your second comparison appears to making a leap that I, at this point do not agree with. You are equating the generation of pyc code in a "hot system" to the time it takes to load everything in a "cold system". A calculation of percentage contribution of pyc creation in a "cold system" would only be valid if that scenario were tested. Which we have not done, but would certainly not be too difficult to test.
I do not get the point. At the end we measured the proportion of the time Python spend generating the pyc for cloud-init and all the dependencies needed for the service, in relation with the overall time that cloud init spend during the initialization of the service.
I am not sure what do you mean by hot and clod here, as I removed all the pyc from site-packages to have a measure of the relation of the generation of the pyc over the time that cloud init uses to start the service.
OK, maybe I can explain this better. We agree that there is a significant difference in the cloud-init execution time between initial start up of the VM vs. a reboot, even if the cloud-init cache (not the pyc files) is cleared. This implies that something is working behind the scene to our advantage and makes a VM reboot faster w.r.t. cloud-init execution when compared to the start a new instance scenario. Given that we do not know what this "makes it work faster" part is, we should not draw any conclusion that the pyc build will take equally as short/long of a time on initial start up as it takes in a "reboot the VM" scenario. This will have to be tested.
I understand now. Looks like that the version of cloud init in place for sle12 sp3 do not have the `clear` command. In any case I inspected site-packages and all the pycs are there after the reboot, so I can consider the time of generating pycs to be a constant time, not related about if or not the cloud- init cache is already populated or not, as this will affect the non-constant time of the total time that cloud-init needs to start. In any case I will look into that.
The cost is amortized, and the corner case, IMHO, is more yours than mine. Your case is a fresh boot of a just installed EC2 VM. I agree that there is a penalty of ~10% (or a 0.54% in my SLE12 SP3 OpenStack case), but this is only for this first boot.
Which is a problem for those users that start a lot of instances to throw them away and start new instances the next time they are needed. This would be a typical autoscaling use case or a typical test use case.
Correct. The 0.205s will be added for each new fresh VM. Am I correct to assume that also this is an scenario where the resize in the initial boot is happening? If so, the overall impact is much less that the 10% that we are talking about, and more close to the %0.5 that I measured in OpenStack. The data I presented as an example was generated with a 10GB image size for the creation of an instance with a 10GB root volume size. So there is a, what should be a negligible, contribution from the growpart script, which is called by cloud-init and runs in a subprocess.
I attribute "negligible" in this case as growpart will exit very fast is no resizing is required. It still take time for process start up etc. but again I consider this as negligible.
But you are correct, by increasing the time it takes for other things cloud-init calls, such as root volume resize, one can decrease the percentage of time allocated to pyc creation.
If I would want to take this to an extreme I could start a process during user data processing that runs for several minutes and thus I could make an argument that pyc creation takes almost no time. However, that would be misleading.
(Read the next as a joke) This point is were my set of words becomes too scarce to choose a colorless word to answer this argument. But I understand the idea behind it :-)
I think in an effort to arrive as close as reasonably possible at the "real cost" of the pyc generation for the cloud-init example, we should minimize the externally executed processes by cloud-init, such as minimizing the runtime for growpart, which is done by not manipulating the instance root volume size as compared to the image size.
Very true, removing all that is slow during the boot time will make the pyc time more relevant in the total amount. IMHO this is a very far time in the future, if happens. But I encourage you and all the cloud stakeholders to make this argument relevant, as this will make the distribution very attractive for Cloud.
It is relatively easy to calculate a cost for this with some estimates. If my test for my application needs 2000 (an arbitrary number I picked) test instances, and every test instance takes .2 seconds longer to boot, to use your number, than the total time penalty is ~6.7 seconds. If this test uses an instance type that costs me $10 per hour the slow down costs me ~ $1.1 every time I run my test. So if the test case runs once a week it would amount to ~$57 per year.
Imagine the cost of the resize of the kiwi operation, must be around some thousands dollars.
But you are right. If there is a weekly re-escalation of 2000 instances during the 54 weeks of a year, you can measure the cost of the pyc generation.
Is in my understanding that CPU cost is cheaper in relation with network transfer and storage. Can we measure the savings of network and storage here? Not in the Public Cloud, there is no data. Network data into the framework is always free and the size of the root volumes in our images is already 10GB (30GB in Azure) and thus offers up ample space for the pyc files. Meaning there is no gain if the actual disk space used by the packages we install is smaller and we have more empty space in the 10GB (30GB in Azure) image.
So uploading ISO / qcow2 images and storing them for a long period is free? [...]
Or better, the user can add a `python -m compileall` in the kiwi config.sh, that will populate /var/cache for the cloud images only.
Well, I could turn around and state that this is a "hack" and "...we don't want any of your proposed hacks.." in our image creation process. Hopefully sounds familiar.... ;)
Indeed, the hack is breaking the content of the RPM removing files from the places where zypper put in (/usr). There is no hack making /var/cache hot before the service runs :-)
Anyway, on a more serious note, if we can resolve the security concerns and properly handle the upgrade mechanism while not generating multiple packages I am not categorically opposed to such an addition in our Public Cloud image builds.
Thanks! I see the security problem, indeed. I will work to provide an answer to this problem and propose it here. Meanwhile the image from [1] is providing some of the pieces that I talk in the first email. This is the image that I am using for another project related with Salt, but as today: * Python 3.7 is installed (in TW we still have 3.6) * Python 3.7 contains the patch from 3.8 to enable storage of pycache in a different file system * I added two shim loaders (written in shell), that replace python3.7 and python3.7m, to enable the 3.8 feature * As a hack, I removed all the pycache from the ISO (I know, I know ...), so all is generated under demand on /var/cache [1] https://build.opensuse.org/project/monitor/home:aplanas:Images? arch_x86_64=1&defaults=0&repo_images=1&succeeded=1
I think that we need a productive argumentation here.
And I thought we were having that for the most part. (My contribution to color commentary)
Your data was very helpful, you are right. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 10/9/18 4:04 AM, Alberto Planas Dominguez wrote:
On Monday, October 8, 2018 7:17:08 PM CEST Robert Schweikert wrote:
On 10/8/18 12:07 PM, Alberto Planas Dominguez wrote:
[Dropping a very unproductive content]
<snip>
Is in my understanding that CPU cost is cheaper in relation with network transfer and storage. Can we measure the savings of network and storage here? Not in the Public Cloud, there is no data. Network data into the framework is always free and the size of the root volumes in our images is already 10GB (30GB in Azure) and thus offers up ample space for the pyc files. Meaning there is no gain if the actual disk space used by the packages we install is smaller and we have more empty space in the 10GB (30GB in Azure) image.
So uploading ISO / qcow2 images and storing them for a long period is free?
No, that is not free. However, I think there is some intermingling of concepts occurring. Let me try and explain by example. A user starts and instance from a SUSE provided image. The size of the image is 10GB in EC2 and GCE. The customer has no cost for storage of the root volume or any network data transferred into the instance during update, i.e. "zypper up" does not generate any cost for the customer even if the customer pulls packages from OBS or SCC. The cost is for the instance, i.e. CPU and memory cost. Also given that Public Cloud frameworks generally have a really good network connection and most instances have a decent network speed the size of the rpm that is being pulled in is not much of a concern. This is the case I had in mind when I provided the example calculation of how a "on first use pyc generation" strategy can cost a user money. In this second example the user generates their own image and uploads it. In this case the user is responsible for the cost of the root volume storage. In AWS for ssd based storage this amounts to $0.1 per GB per month. So if a user can save 1 GB of storage because there are no pyc files in their image and they make their image exactly the size they need they stand the potential of saving 10 cents a month or $1.2 over the course of a year. If I go back to the example with 2000 test instances, from my point of view, it is apparent that the cost savings potential by optimizing for size are significantly smaller when compared to the cost increase potential due to increased CPU use. So this scenario, IMHO, would also favor the use case where we can, in some way shape or form have images that contain the pyc files.
[...]
Or better, the user can add a `python -m compileall` in the kiwi config.sh, that will populate /var/cache for the cloud images only.
Well, I could turn around and state that this is a "hack" and "...we don't want any of your proposed hacks.." in our image creation process. Hopefully sounds familiar.... ;)
Indeed, the hack is breaking the content of the RPM removing files from the places where zypper put in (/usr). There is no hack making /var/cache hot before the service runs :-)
Anyway, on a more serious note, if we can resolve the security concerns and properly handle the upgrade mechanism while not generating multiple packages I am not categorically opposed to such an addition in our Public Cloud image builds.
Thanks!
I see the security problem, indeed. I will work to provide an answer to this problem and propose it here.
Meanwhile the image from [1] is providing some of the pieces that I talk in the first email. This is the image that I am using for another project related with Salt, but as today:
* Python 3.7 is installed (in TW we still have 3.6) * Python 3.7 contains the patch from 3.8 to enable storage of pycache in a different file system * I added two shim loaders (written in shell), that replace python3.7 and python3.7m, to enable the 3.8 feature * As a hack, I removed all the pycache from the ISO (I know, I know ...), so all is generated under demand on /var/cache
[1] https://build.opensuse.org/project/monitor/home:aplanas:Images? arch_x86_64=1&defaults=0&repo_images=1&succeeded=1
Over the next couple of days I will try to find the time to generate a SLES 15 image and clear the py{c,o} and __pycache__ and get it uploaded to EC2 so we can get a number for "cold start" for cloud-init. Later, Robert -- Robert Schweikert MAY THE SOURCE BE WITH YOU Distinguished Architect LINUX Team Lead Public Cloud rjschwei@suse.com IRC: robjo
On 2018-10-08, 17:17 GMT, Robert Schweikert wrote:
I think that we need a productive argumentation here.
And I thought we were having that for the most part. (My contribution to color commentary)
I really don't know enough about the 10GB (or 30GB) images (/me shudders in horror) and their starting time, but as the one who will most likely have to implement and maintain most of this, let me add one argument against this. If we really want to do such drastic change to all Python packages, I would really prefer if this discusion was done on python-devel and/or python-ideas upstream, so that we won't end up as the only with different configuration of Python and with our unique bugs. Could somebody who wants to make the case for this change do so on python-ideas and start a discussion there, please? Best, Matěj -- https://matej.ceplovi.cz/blog/, Jabber: mcepl@ceplovi.cz GPG Finger: 3C76 A027 CA45 AD70 98B5 BC1D 7920 5802 880B C9D8 There is no reason to suppose that most human beings are engaged in maximizing anything unless it be unhappiness, and even this with incomplete success. -- Ronald Coase Introduction to “The Firm, the Market, and the Law” -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Tuesday, October 9, 2018 12:16:13 PM CEST Matěj Cepl wrote:
On 2018-10-08, 17:17 GMT, Robert Schweikert wrote:
I think that we need a productive argumentation here.
And I thought we were having that for the most part. (My contribution to color commentary)
I really don't know enough about the 10GB (or 30GB) images (/me shudders in horror) and their starting time, but as the one who will most likely have to implement and maintain most of this, let me add one argument against this.
Do you mean for the packaging? I was hopping to get some magic %macro as the %artifact (once updated, if this is a viable solution)
If we really want to do such drastic change to all Python packages, I would really prefer if this discusion was done on python-devel and/or python-ideas upstream, so that we won't end up as the only with different configuration of Python and with our unique bugs. Could somebody who wants to make the case for this change do so on python-ideas and start a discussion there, please?
How python-devel can help here? My PoV is this is a collective decision inside openSUSE. I have a PoC in place, but I still need to make my full point before reaching any decision on the topic. In that regard, we are upstream. For example, the patch that is in 3.7 comes from 3.8. I can agree to work in this feature and make only available only for 3.8, without maintaining the patched version of Python 3.7. So far the change is small, and my daily work with it is not impacted. But I would agree if we make this change easily reversible, in the case that after some time we agree that this was a bad idea, for implications that we are not aware of. Or maybe decide in favor of doing it only for certain uses cases. How python-devel can help on those decisions? -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
* Alberto Planas Dominguez
Hi,
As you know the Python packages are collecting the pyc/pyo precompiled binaries inside the RPM. This is mostly a good idea, as makes the first execution of the Python code faster, as is skipped the stage where the interpreter compile the .py code.
But this also makes the Python stack a bit fat. Most of the time this is not a problem, but things are changing.
Oh, deja-vu: https://hackweek.suse.com/projects/minimal-salt-packaging Klaus -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg) -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On Friday, October 5, 2018 8:25:09 AM CEST Klaus Kaempf wrote:
* Alberto Planas Dominguez
[Oct 04. 2018 16:52]: But this also makes the Python stack a bit fat. Most of the time this is not a problem, but things are changing.
Oh, deja-vu: https://hackweek.suse.com/projects/minimal-salt-packaging
Removing all the .py files will make the system a bit hard to debug, as the tracebacks will not point to the source line codes, and you loose the advantage of inspecting and changing the code in place. Cool project. -- SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nürnberg) Maxfeldstraße 5, 90409 Nürnberg, Germany -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
Am 05.10.18 um 09:59 schrieb Alberto Planas Dominguez:
Removing all the .py files will make the system a bit hard to debug, as the tracebacks will not point to the source line codes, and you loose the advantage of inspecting and changing the code in place.
The same argument applies to C, C++, whatever code. Just install python-foobarbaz-debugsource.rpm -- Stefan Seyfried "For a successful technology, reality must take precedence over public relations, for nature cannot be fooled." -- Richard Feynman -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
On 05/10/2018 10.17, Stefan Seyfried wrote:
Am 05.10.18 um 09:59 schrieb Alberto Planas Dominguez:
Removing all the .py files will make the system a bit hard to debug, as the tracebacks will not point to the source line codes, and you loose the advantage of inspecting and changing the code in place.
The same argument applies to C, C++, whatever code. Just install python-foobarbaz-debugsource.rpm
Yes, but one of the main reasons one decides to use an interpreted language is, well, it is interpreted. -- Cheers / Saludos, Carlos E. R. (from 42.3 x86_64 "Malachite" at Telcontar)
* Python 2.7 + 3.6 - pyc/pyc: 127M total - py: 109M total
* Python 3.6 only - pyc/pyc: 91M total - py: 70M total
For deployments where this space usage matters, I would imagine that a compressed filesystem will be used. So for the purpose of discussing what savings are possible and whether to keep the pyc/opyc or the py files we need the size after compression. I'd imagine that the py code compresses much more that the bytecode. -- To unsubscribe, e-mail: opensuse-factory+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-factory+owner@opensuse.org
participants (18)
-
Alberto Planas Dominguez
-
Brüns, Stefan
-
Carlos E. R.
-
Jan Engelhardt
-
Joachim Wagner
-
John Paul Adrian Glaubitz
-
Klaus Kaempf
-
Lars Marowsky-Bree
-
Ludwig Nussel
-
Matěj Cepl
-
Michael Schroeder
-
Michael Ströder
-
Neal Gompa
-
Richard Biener
-
Robert Schweikert
-
Stefan Seyfried
-
Stephan Kulow
-
Thorsten Kukuk