Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
W
wendelin.core
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Joshua
wendelin.core
Commits
7d1e1568
Commit
7d1e1568
authored
6 years ago
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into t
* master: py.bench: Move it to -> pygolang
parents
077ccb9d
318efce0
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
3 additions
and
276 deletions
+3
-276
Makefile
Makefile
+2
-2
setup.py
setup.py
+1
-1
t/py.bench
t/py.bench
+0
-273
No files found.
Makefile
View file @
7d1e1568
...
...
@@ -21,7 +21,7 @@ all :
PYTHON
?=
python
PYTEST
?=
$(PYTHON)
-m
pytest
PYBENCH
?=
$(PYTHON)
t/py.
bench
PYBENCH
?=
$(PYTHON)
-m
golang.cmd.py
bench
VALGRIND
?=
valgrind
GO
?=
go
...
...
@@ -202,4 +202,4 @@ bench : bench.t bench.py
bench.t
:
$(BENCHV.C:%=%.trun)
bench.py
:
bigfile/_bigfile.so wcfs/wcfs
$(PYBENCH)
$(PYTEST_IGNORE)
$(PYBENCH)
--count
=
3
--forked
$(PYTEST_IGNORE)
This diff is collapsed.
Click to expand it.
setup.py
View file @
7d1e1568
...
...
@@ -251,7 +251,7 @@ setup(
],
extras_require
=
{
'test'
:
[
'pytest'
],
'test'
:
[
'pytest'
,
'pygolang >= 0.0.0.dev4'
],
},
cmdclass
=
{
'build_ext'
:
build_ext
,
...
...
This diff is collapsed.
Click to expand it.
t/py.bench
deleted
100755 → 0
View file @
077ccb9d
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# benchmarking via py.test
# Copyright (C) 2014-2015 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
#
# TODO intro
from
__future__
import
print_function
import
pytest
import
_pytest.runner
from
_pytest.terminal
import
TerminalReporter
as
_pytest_TerminalReporter
from
time
import
time
from
math
import
ceil
,
log10
from
py.process
import
ForkedFunc
import
sys
from
six.moves
import
range
as
xrange
# XXX hack for ForkedFunc not to capture stdout/stderr.
# so that test prints could be seen when run under --capture=no
# otoh, py.test captures stdout/stderr fds so here we don't have to.
import
py._process.forkedfunc
class
XForkedFunc
(
ForkedFunc
):
def
_child
(
self
,
nice
,
on_start
,
on_exit
):
# we are monkeypatching only in child, so no effect on parent =safe
py
.
_process
.
forkedfunc
.
get_unbuffered_io
=
self
.
_fake_get_unbuffered_io
return
ForkedFunc
.
_child
(
self
,
nice
,
on_start
,
on_exit
)
@
staticmethod
def
_fake_get_unbuffered_io
(
fd
,
_
):
if
fd
==
1
:
return
sys
.
stdout
if
fd
==
2
:
return
sys
.
stderr
raise
RuntimeError
(
"only stdout/stderr expected"
)
# B is benchmarking timer/request passed to benchmarks as fixture
# similar to https://golang.org/pkg/testing/#B.
class
B
:
def
__init__
(
self
):
self
.
N
=
1
# default when func does not accept `b` arg
self
.
_t_start
=
None
# t of timer started; None if timer is currently stopped
self
.
reset_timer
()
def
reset_timer
(
self
):
self
.
_t_total
=
0.
def
start_timer
(
self
):
if
self
.
_t_start
is
not
None
:
return
self
.
_t_start
=
time
()
def
stop_timer
(
self
):
if
self
.
_t_start
is
None
:
return
t
=
time
()
self
.
_t_total
+=
t
-
self
.
_t_start
self
.
_t_start
=
None
def
total_time
(
self
):
return
self
.
_t_total
# plugin to collect & run benchmarks
class
BenchPlugin
:
# redirect python collector to bench_*.py and bench_*()
def
pytest_configure
(
self
,
config
):
# XXX a bit hacky
ini
=
config
.
inicfg
ini
[
'python_files'
]
=
'bench_*.py'
ini
[
'python_classes'
]
=
'Bench'
ini
[
'python_functions'
]
=
'bench_'
config
.
_inicache
.
clear
()
def
pytest_addoption
(
self
,
parser
):
g
=
parser
.
getgroup
(
'benchmarking'
)
g
.
addoption
(
'--benchruns'
,
action
=
'store'
,
type
=
int
,
dest
=
'benchruns'
,
default
=
3
,
help
=
"number of time to run each benchmark"
)
g
.
addoption
(
'--dontfork'
,
action
=
'store_true'
,
dest
=
'dontfork'
,
default
=
False
,
help
=
"run all benchmarks in the same process"
)
# create b for every item to run and make it available to b fixture via item.request
def
pytest_runtest_setup
(
self
,
item
):
b
=
B
()
b
.
_used_by_func
=
False
item
.
_request
.
_bench_b
=
b
# make created b be available as `b` func arg
@
pytest
.
fixture
(
scope
=
"function"
)
def
b
(
self
,
request
):
"""Provides access to benchmarking timer"""
# NOTE here request is subrequest of item._request in pytest_runtest_setup
b
=
request
.
_parent_request
.
_bench_b
b
.
_used_by_func
=
True
return
b
# run benchmark several times, and get best timing
# each benchmark run is executed in separate process (if not told otherwise)
def
pytest_runtest_call
(
self
,
item
):
b
=
item
.
_request
.
_bench_b
def
run
():
b
.
N
=
0
t
=
0.
ttarget
=
1.
while
t
<
(
ttarget
*
0.9
):
if
b
.
N
==
0
:
b
.
N
=
1
else
:
n
=
b
.
N
*
(
ttarget
/
t
)
# exact how to adjust b.N to reach ttarget
order
=
int
(
log10
(
n
))
# n = k·10^order, k ∈ [1,10)
k
=
float
(
n
)
/
(
10
**
order
)
k
=
ceil
(
k
)
# lift up k to nearest int
b
.
N
=
int
(
k
*
10
**
order
)
# b.N = int([1,10))·10^order
b
.
reset_timer
()
b
.
start_timer
()
item
.
runtest
()
b
.
stop_timer
()
t
=
b
.
total_time
()
#print((b.N, t))
# break if func does not accept b as arg
if
not
b
.
_used_by_func
:
break
return
(
b
.
N
,
t
)
rv
=
[]
for
i
in
xrange
(
item
.
config
.
option
.
benchruns
):
if
item
.
config
.
option
.
dontfork
:
r
=
run
()
else
:
runf
=
XForkedFunc
(
run
)
result
=
runf
.
waitfinish
()
if
result
.
exitstatus
==
XForkedFunc
.
EXITSTATUS_EXCEPTION
:
print
(
result
.
err
,
file
=
sys
.
stderr
)
# XXX vs runf doesn't capture stderr
1
/
0
# TODO re-raise properly
elif
result
.
exitstatus
!=
0
:
print
(
result
.
err
,
file
=
sys
.
stderr
)
# XXX vs runf doesn't capture stderr
1
/
0
# TODO handle properly
r
=
result
.
retval
rv
.
append
(
r
)
#print ('RET', rv)
return
rv
# set benchmarking time in report, if run ok
def
pytest_runtest_makereport
(
self
,
item
,
call
):
report
=
_pytest
.
runner
.
pytest_runtest_makereport
(
item
,
call
)
if
call
.
when
==
'call'
and
not
call
.
excinfo
:
# in pytest3 there is no way to mark pytest_runtest_call as 'firstresult'
# let's emulate firstresult logic here
assert
len
(
call
.
result
)
==
1
report
.
bench_resv
=
call
.
result
[
0
]
return
report
# colors to use when printing !passed
# XXX somewhat dup from _pytest/terminal.py
def
report_markup
(
report
):
m
=
{}
if
report
.
failed
:
m
=
{
'red'
:
True
,
'bold'
:
True
}
elif
report
.
skipeed
:
m
=
{
'yellow'
:
True
}
return
m
# max(seq) or 0 if !seq
def
max0
(
seq
):
seq
=
list
(
seq
)
# if generator -> generate
if
not
seq
:
return
0
else
:
return
max
(
seq
)
# benchname(nodeid) returns name of a benchmark from a function nodeid
def
benchname
(
nodeid
):
pyname
=
nodeid
.
split
(
"::"
,
1
)[
1
]
# everything after fspath
# replace 'bench_' with 'Benchmark' prefix so that benchmark output matches
# golang format
if
pyname
.
startswith
(
'bench_'
):
pyname
=
pyname
[
len
(
'bench_'
):]
return
'Benchmark'
+
pyname
# Adjujsted terminal reporting to benchmarking needs
class
XTerminalReporter
(
_pytest_TerminalReporter
):
# determine largest item name (to ralign timings)
def
pytest_collection_finish
(
self
,
session
):
_pytest_TerminalReporter
.
pytest_collection_finish
(
self
,
session
)
self
.
benchname_maxlen
=
max0
(
len
(
benchname
(
_
.
nodeid
))
for
_
in
session
.
items
)
def
pytest_runtest_logstart
(
self
,
nodeid
,
location
):
# print `pymod: ...` header for every module
fspath
=
self
.
config
.
rootdir
.
join
(
nodeid
.
split
(
"::"
)[
0
])
if
fspath
==
self
.
currentfspath
:
return
first
=
(
self
.
currentfspath
==
None
)
self
.
currentfspath
=
fspath
fspath
=
self
.
startdir
.
bestrelpath
(
fspath
)
self
.
_tw
.
line
()
# vskip in between modules
if
not
first
:
self
.
_tw
.
line
()
self
.
write
(
"pymod: %s"
%
fspath
)
def
pytest_runtest_logreport
(
self
,
report
):
_
=
self
.
config
.
hook
.
pytest_report_teststatus
(
report
=
report
)
cat
,
letter
,
word
=
_
self
.
stats
.
setdefault
(
cat
,
[]).
append
(
report
)
# XXX needed for bench?
if
not
letter
and
not
word
:
# passed setup/teardown
return
def
printname
():
self
.
_tw
.
line
()
self
.
_tw
.
write
(
'%-*s
\
t
'
%
(
self
.
benchname_maxlen
,
benchname
(
report
.
nodeid
)))
if
not
report
.
passed
:
printname
()
self
.
_tw
.
write
(
'[%s]'
%
word
,
**
report_markup
(
report
))
return
# TODO ralign timing
for
niter
,
t
in
report
.
bench_resv
:
printname
()
self
.
_tw
.
write
(
'%d
\
t
%.3f µs/op'
%
(
niter
,
t
*
1E6
/
niter
))
# there is no way to override it otherwise - it is hardcoded in
# _pytest.terminal's pytest_configure()
_pytest
.
terminal
.
TerminalReporter
=
XTerminalReporter
def
main
():
pytest
.
main
(
plugins
=
[
BenchPlugin
()])
if
__name__
==
'__main__'
:
main
()
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment