Commit 3c55ca59 authored by Kirill Smelkov's avatar Kirill Smelkov

golang: Add benchmarks for chan, select, @func and defer

Start adding benchmarks to pygolang.

Measure how much sync chan send/recv take and how much select takes for
synchronous channels. Also measure how much overhead @func adds at both
def and call times, and the overhead of defer compared to try/finally.
For std (non-gevent'ed) Python2.7 we are currently at:

	name         time/op
	go           91.6µs ± 1%
	chan         13.7µs ± 3%
	select       30.1µs ± 4%
	def          55.0ns ± 0%
	func_def     43.6µs ± 0%
	call         63.0ns ± 0%
	func_call    1.06µs ± 0%
	try_finally   136ns ± 1%
	defer        2.33µs ± 0%
parent c3ea8f51
......@@ -24,6 +24,7 @@ from golang import go, chan, select, default, nilchan, _PanicError, func, panic,
from pytest import raises
from os.path import dirname
import os, sys, time, threading, inspect, subprocess
from six.moves import range as xrange
import golang
from golang import _chan_recv, _chan_send
......@@ -47,6 +48,16 @@ def test_go():
subprocess.check_call([sys.executable, dir_golang + "/testprog/golang_test_goleaked.py"],
env=env)
# benchmark go+join a thread/coroutine.
def bench_go(b):
done = chan()
def _():
done.send(1)
for i in xrange(b.N):
go(_)
done.recv()
# waitBlocked waits till a receive or send channel operation blocks waiting on the channel.
#
......@@ -162,6 +173,24 @@ def test_chan():
assert done.recv() == 'b'
# benchmark sync chan send/recv.
def bench_chan(b):
ch = chan()
done = chan()
def _():
while 1:
_, ok = ch.recv_()
if not ok:
done.close()
return
go(_)
for i in xrange(b.N):
ch.send(1)
ch.close()
done.recv()
def test_select():
N = 1000 # times to do repeated select/chan or select/select interactions
......@@ -453,6 +482,33 @@ def test_select():
assert len(ch2._sendq) == len(ch2._recvq) == 0
# benchmark sync chan send vs recv on select side.
def bench_select(b):
ch1 = chan()
ch2 = chan()
done = chan()
def _():
while 1:
_, _rx = select(
ch1.recv_, # 0
ch2.recv_, # 1
)
if _ == 0:
_, ok = _rx
if not ok:
done.close()
return
go(_)
_ = (ch1, ch2)
for i in xrange(b.N):
ch = _[i%2]
ch.send(1)
ch1.close()
done.recv()
# BlocksForever is used in "blocks forever" tests where golang._blockforever
# is patched to raise instead of block.
class BlocksForever(Exception):
......@@ -535,6 +591,28 @@ def test_func():
assert MyClass.mcls.__name__ == 'mcls'
# @func overhead at def time.
def bench_def(b):
for i in xrange(b.N):
def _(): pass
def bench_func_def(b):
for i in xrange(b.N):
@func
def _(): pass
# @func overhead at call time.
def bench_call(b):
def _(): pass
for i in xrange(b.N):
_()
def bench_func_call(b):
@func
def _(): pass
for i in xrange(b.N):
_()
def test_deferrecover():
# regular defer calls
......@@ -735,3 +813,25 @@ def test_deferrecover():
MyClass.mcls()
assert v == [7, 2, 1]
# defer overhead.
def bench_try_finally(b):
def fin(): pass
def _():
try:
pass
finally:
fin()
for i in xrange(b.N):
_()
def bench_defer(b):
def fin(): pass
@func
def _():
defer(fin)
for i in xrange(b.N):
_()
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