New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spawn_tree_locals, spawning_greenlet and spawning_stack to gevent.greenlet.Greenlet #1115

Merged
merged 7 commits into from Feb 22, 2018

Conversation

Projects
None yet
1 participant
@jamadden
Member

jamadden commented Feb 22, 2018

This partially addressed #755. I will address the ID portion in a separate PR.

This slowed down spawning of greenlets a fair amount (8-10x) so to get the speed back close to where it was, that module is now compiled with Cython.

Raw timing before:

 python -m perf timeit -s 'import gevent' 'gevent.Greenlet()'
 3.6.4       : Mean +- std dev: 1.08 us +- 0.05 us
 2.7.14      : Mean +- std dev: 1.44 us +- 0.06 us
 PyPy2 5.10.0: Mean +- std dev: 2.14 ns +- 0.08 ns

Current timing:

3.6.4        : Mean +- std dev: 3.63 us +- 0.14 us
2.7.14       : Mean +- std dev: 3.37 us +- 0.20 us
PyPy2 5.10.0 : Mean +- std dev: 4.44 us +- 0.28 us

So approximately 3x slower in relative terms, but still pretty fast in absolute terms. This is very artificial, of course. Slightly less artificial is bench_spawn.py. Here's timings for 3.6.4 before:

python bench_spawn.py eventlet --ignore-import-errors
spawning: 11.93 microseconds per greenlet

python bench_spawn.py gevent --ignore-import-errors
spawning: 3.39 microseconds per greenlet

python bench_spawn.py geventpool --ignore-import-errors
spawning: 8.71 microseconds per greenlet
 joining: 7.34 microseconds per greenlet

python bench_spawn.py geventraw --ignore-import-errors
spawning: 2.09 microseconds per greenlet

python bench_spawn.py --with-kwargs eventlet
spawning: 12.06 microseconds per greenlet

python bench_spawn.py --with-kwargs gevent
spawning: 4.62 microseconds per greenlet

python bench_spawn.py --with-kwargs geventpool
spawning: 10.25 microseconds per greenlet
 joining: 7.14 microseconds per greenlet

python bench_spawn.py --with-kwargs geventraw
spawning: 3.27 microseconds per greenlet

And now:

python ./bench_spawn.py eventlet 
spawning: 11.63 microseconds per greenlet

python ./bench_spawn.py gevent
spawning: 8.99 microseconds per greenlet

python ./bench_spawn.py geventpool 
spawning: 11.76 microseconds per greenlet
 joining: 5.37 microseconds per greenlet

python ./bench_spawn.py geventraw
spawning: 4.62 microseconds per greenlet

python ./bench_spawn.py --with-kwargs eventlet 
spawning: 12.15 microseconds per greenlet

python ./bench_spawn.py --with-kwargs gevent
spawning: 9.23 microseconds per greenlet

python ./bench_spawn.py --with-kwargs geventpool
spawning: 12.15 microseconds per greenlet
 joining: 5.35 microseconds per greenlet

python ./bench_spawn.py --with-kwargs geventraw
spawning: 5.24 microseconds per greenlet

Again, some slowdown, but that attenuates as you use more sophisticated methods. Overall the comparison looks reasonable to me based on the benefits. And joining got faster!

jamadden added some commits Feb 21, 2018

Add spawn_tree_locals, spawning_greenlet and spawning_stack to Greenlet
Based on #755.

A comment in the code goes into detail about the timing. Here it is
again:

 Timings taken Feb 21 2018 prior to integration of #755
 python -m perf timeit -s 'import gevent' 'gevent.Greenlet()'
 3.6.4       : Mean +- std dev: 1.08 us +- 0.05 us
 2.7.14      : Mean +- std dev: 1.44 us +- 0.06 us
 PyPy2 5.10.0: Mean +- std dev: 2.14 ns +- 0.08 ns

 After the integration of spawning_stack, spawning_greenlet,
 and spawn_tree_locals on that same date:
 3.6.4       : Mean +- std dev: 8.92 us +- 0.36 us ->  8.2x
 2.7.14      : Mean +- std dev: 14.8 us +- 0.5 us  -> 10.2x
 PyPy2 5.10.0: Mean +- std dev: 3.24 us +- 0.17 us ->  1.5x

Selected bench_spawn output on 3.6.4 before:

//gevent36/bin/python src/greentest/bench_spawn.py eventlet --ignore-import-errors
using eventlet from //gevent36/lib/python3.6/site-packages/eventlet/__init__.py
spawning: 11.93 microseconds per greenlet
sleep(0): 23.49 microseconds per greenlet

//gevent36/bin/python src/greentest/bench_spawn.py gevent --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 3.39 microseconds per greenlet
sleep(0): 17.59 microseconds per greenlet

//gevent36/bin/python src/greentest/bench_spawn.py geventpool --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 8.71 microseconds per greenlet

//gevent36/bin/python src/greentest/bench_spawn.py geventraw --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 2.09 microseconds per greenlet

//gevent36/bin/python src/greentest/bench_spawn.py none --ignore-import-errors
    noop: 0.33 microseconds per greenlet

And after:

//gevent36/bin/python bench_spawn.py gevent --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 12.99 microseconds per greenlet -> 3.8x

//gevent36/bin/python bench_spawn.py geventpool --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 19.49 microseconds per greenlet -> 2.2x

//gevent36/bin/python bench_spawn.py geventraw --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 4.57 microseconds per greenlet -> 2.2x

We're approximately the speed of eventlet now.

Refs #755
Compile greenlet with Cython to make up for most of the lost speed.
We're now only ~2x slower, instead of 10x.
More cython declarations for more speed.
Small improvements to creating the objects, somewhat larger
improvements to joining.

From bench_spawn on 3.6.4 before any work:

//gevent36/bin/python ./bench_spawn.py geventpool --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 8.71 microseconds per greenlet
sleep(0): 16.99 microseconds per greenlet
 joining: 7.34 microseconds per greenlet

//gevent36/bin/python ./bench_spawn.py --with-kwargs geventpool --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 10.25 microseconds per greenlet
sleep(0): 18.89 microseconds per greenlet
 joining: 7.14 microseconds per greenlet

And now:

//gevent36/bin/python ./bench_spawn.py geventpool --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 11.56 microseconds per greenlet
sleep(0): 16.76 microseconds per greenlet
 joining: 5.74 microseconds per greenlet

//gevent36/bin/python ./bench_spawn.py --with-kwargs geventpool --ignore-import-errors
using gevent from //src/gevent/__init__.py
spawning: 11.49 microseconds per greenlet
sleep(0): 17.16 microseconds per greenlet
 joining: 5.31 microseconds per greenlet

@jamadden jamadden merged commit 437eff3 into master Feb 22, 2018

0 of 2 checks passed

continuous-integration/appveyor/pr Waiting for AppVeyor build to complete
Details
continuous-integration/travis-ci/push The Travis CI build is in progress
Details

@jamadden jamadden deleted the issue755 branch Feb 22, 2018

@mahmoud mahmoud referenced this pull request Feb 23, 2018

Closed

Greenlet tree #755

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment