Commit 2114a560 authored by Kirill Smelkov's avatar Kirill Smelkov

golang: Add benchmarks for nogil go and channels

on i7@2.6GHz it looks like:

thread runtime:

    name              time/op
    pyx_select_nogil  2.70µs ±13%
    pyx_go_nogil      15.9µs ± 1%
    pyx_chan_nogil    2.79µs ± 2%
    go                17.6µs ± 0%
    chan              3.05µs ± 4%
    select            3.62µs ± 4%

gevent runtime (gevent-1.4.0):

    name              time/op
    pyx_select_nogil  9.39µs ± 1%
    pyx_go_nogil      15.1µs ± 2%
    pyx_chan_nogil    7.10µs ± 1%
    go                16.6µs ± 1%
    chan              7.47µs ± 1%
    select            10.7µs ± 0%
parent 874371e2
......@@ -342,3 +342,77 @@ cdef nogil:
pych.chan_double().send(obj)
void _pychan_double_close(pychan pych) except +topyexc:
pych.chan_double().close()
# ---- benchmarks ----
# bench_go_nogil mirrors golang_test.py:bench_go
def bench_go_nogil(b):
cdef int N = b.N
with nogil:
_bench_go_nogil(N)
cdef void _bench_go_nogil(int N) nogil except +topyexc:
cdef chan[int] done = makechan[int]()
for i in range(N):
go(_bench_go_nogil__func1, done)
done.recv()
cdef void _bench_go_nogil__func1(chan[int] done) nogil:
done.send(1)
# bench_chan_nogil mirrors golang_test.py:bench_chan
def bench_chan_nogil(b):
cdef int N = b.N
with nogil:
_bench_chan_nogil(N)
cdef void _bench_chan_nogil(int N) nogil except +topyexc:
cdef chan[int] ch = makechan[int]()
cdef chan[structZ] done = makechan[structZ]()
go(_bench_chan_nogil__func1, ch, done)
for i in range(N):
ch.send(1)
ch.close()
done.recv()
cdef void _bench_chan_nogil__func1(chan[int] ch, chan[structZ] done) nogil:
while 1:
_, ok = recv_(ch)
if not ok:
done.close()
return
# bench_select_nogil mirrors golang_test.py:bench_select
def bench_select_nogil(b):
cdef int N = b.N
with nogil:
_bench_select_nogil(N)
cdef void _bench_select_nogil(int N) nogil except +topyexc:
cdef chan[int] ch1 = makechan[int]()
cdef chan[int] ch2 = makechan[int]()
cdef chan[structZ] done = makechan[structZ]()
go(_bench_select_nogil__func1, ch1, ch2, done)
for i in range(N):
if i&1: ch1.send(1)
else: ch2.send(1)
ch1.close()
done.recv()
cdef void _bench_select_nogil__func1(chan[int] ch1, chan[int] ch2, chan[structZ] done) nogil:
cdef int i
cdef cbool ok
while 1:
_ = select([
ch1.recvs(&i, &ok), # 0
ch2.recvs(&i, &ok), # 1
])
if _ == 0:
if not ok:
done.close()
return
......@@ -32,23 +32,34 @@ from subprocess import Popen, PIPE
import six
from six.moves import range as xrange
import gc, weakref, warnings
import re
from golang import _golang_test
from golang._golang_test import pywaitBlocked as waitBlocked, pylen_recvq as len_recvq, \
pylen_sendq as len_sendq, pypanicWhenBlocked as panicWhenBlocked
# pyx/c/c++ tests -> test_pyx_* in caller's globals.
# pyx/c/c++ tests/benchmarks -> {test,bench}_pyx_* in caller's globals.
def import_pyx_tests(modpath):
mod = importlib.import_module(modpath)
callf = inspect.currentframe().f_back # caller's frame
callg = callf.f_globals # caller's globals
tbre = re.compile("(test|bench)_(.+)")
for f in dir(mod):
if f.startswith('test_'):
gf = 'test_pyx_' + f[len('test_'):] # test_chan_nogil -> test_pyx_chan_nogil
m = tbre.match(f)
if m is not None:
kind, name = m.group(1), m.group(2)
gf = kind + "_pyx_" + name # test_chan_nogil -> test_pyx_chan_nogil
# define a python function with gf name (if we use f directly pytest
# will say "cannot collect 'test_pyx_chan_nogil' because it is not a function")
def _(func=getattr(mod, f)):
func()
if kind == "test":
def _(func=getattr(mod, f)):
func()
elif kind == "bench":
def _(b, func=getattr(mod, f)):
func(b)
else:
panic("unreachable")
_.__name__ = gf
callg[gf] = _
......@@ -61,6 +72,7 @@ def test_go_leaked():
pyrun([dirname(__file__) + "/testprog/golang_test_goleaked.py"])
# benchmark go+join a thread/coroutine.
# pyx/nogil mirror is in _golang_test.pyx
def bench_go(b):
done = chan()
def _():
......@@ -317,6 +329,7 @@ def test_chan_sendrecv_2way():
# benchmark sync chan send/recv.
# pyx/nogil mirror is in _golang_test.pyx
def bench_chan(b):
ch = chan()
done = chan()
......@@ -698,6 +711,7 @@ def test_select_refleak():
# benchmark sync chan send vs recv on select side.
# pyx/nogil mirror is in _golang_test.pyx
def bench_select(b):
ch1 = chan()
ch2 = chan()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment