Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Levin Zimmermann
neoppod
Commits
f5fec740
Commit
f5fec740
authored
Mar 02, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
X switch node info to labels; start adding that to plot
parent
28d00786
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
169 additions
and
47 deletions
+169
-47
go/neo/t/benchlib.py
go/neo/t/benchlib.py
+98
-15
go/neo/t/benchplot
go/neo/t/benchplot
+41
-4
go/neo/t/neotest
go/neo/t/neotest
+30
-28
No files found.
go/neo/t/benchlib.py
View file @
f5fec740
...
...
@@ -27,6 +27,7 @@ from __future__ import print_function
import
re
,
io
,
numpy
as
np
from
collections
import
OrderedDict
from
cStringIO
import
StringIO
# Benchmark is a collection of benchmark lines.
...
...
@@ -87,24 +88,28 @@ class Stats(object):
# ----------------------------------------
# '<key>: <value>'
_label_re
=
re
.
compile
(
r'(?P<key>\
w+):
\s*'
)
_sp_re
=
re
.
compile
(
r'\
s
')
# parse_label tries to parse line as label.
#
# returns (key, value).
# if line does not match - (None, None) is returned.
def parse_label(line):
m
=
_label_re
.
match
(
line
)
if
m
is
None
:
colon = line.find('
:
')
if colon == -1:
return None, None
key, value = line[:colon], line[colon+1:]
# key must not contain space
if _sp_re.search(key):
return None, None
# FIXME key must be unicode lower
# FIXME key must not contain upper or space
key
=
m
.
group
(
'key'
)
value
=
line
[
m
.
end
():]
value
=
value
.
rstrip
()
# XXX or rstrip only \n ?
# XXX also support '
WARNING
'
value = value.strip() # leading and traling
\
s XXX
f
or trailing - rstrip only
\
n
?
return key, value
...
...
@@ -155,7 +160,8 @@ def _parse_benchline(linev):
#
# r is required to implement `.readlines()`.
#
# returns -> Benchmark.
# returns -> Benchmark, exit_labels.
# (exit_labels is ordered {} with labels state at end of reading)
def
load
(
r
):
labels
=
OrderedDict
()
benchv
=
Benchmark
()
# of BenchLine
...
...
@@ -166,6 +172,10 @@ def load(r):
if
key
is
not
None
:
labels
=
labels
.
copy
()
if
value
:
if
key
==
'WARNING'
:
# warnings accumulate, not replace previous ones
labels
[
key
]
=
labels
.
get
(
key
,
())
+
(
value
,)
else
:
labels
[
key
]
=
value
else
:
labels
.
pop
(
key
,
None
)
# discard
...
...
@@ -178,18 +188,92 @@ def load(r):
benchv
.
append
(
bl
)
continue
# XXX also extract warnings?
return
benchv
return
benchv
,
labels
# load_file loads benchmark data from file @ path.
#
# returns -> Benchmark.
# returns -> Benchmark
, exit_labels
.
def
load_file
(
path
):
with
io
.
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
return
load
(
f
)
# xload loads benchmark data from a reader with neotest extensions handling.
#
# neotest extensions:
#
# - a line starting with `*** neotest:` denotes start of neotest extension block.
# The block consists of labels describing hardware and software on that node. XXX
# The block ends with a blank line.
# Labels in the block are not added to benchmarking lines from main stream.
# The block itself should not contain benchmark lines.
#
# returns -> Benchmark, exit_labels, []extlab.
# (extlab is ordered {} with labels from an extension block)
def
xload
(
r
):
xr
=
_neotestExtReader
(
r
)
b
,
l
=
load
(
xr
)
extv
=
[]
for
lineno
,
text
in
xr
.
extblockv
:
bext
,
lext
=
load
(
StringIO
(
text
.
encode
(
'utf-8'
)))
if
len
(
bext
)
!=
0
:
raise
RuntimeError
(
"%s:%d: neotest extension block contains benchmark line"
\
%
(
getattr
(
r
,
name
,
'?'
),
lineno
))
extv
.
append
(
lext
)
return
b
,
l
,
extv
# _neotestExtReader is a reader that splits neotest extension data from
# benchmarking data stream.
#
# A reader reading from _neotestExtReader sees original data stream with
# extensions filtered-out. The list of extension blocks found can be accessed
# at .extblockv.
class
_neotestExtReader
(
object
):
def
__init__
(
self
,
r
):
self
.
r
=
r
self
.
extblockv
=
[]
# of (lineno, text)
self
.
_lineno
=
0
def
_readline
(
self
):
l
=
self
.
r
.
readline
()
if
l
:
self
.
_lineno
+=
1
return
l
def
readline
(
self
):
l
=
self
.
_readline
()
if
not
l
.
startswith
(
'*** neotest:'
):
return
l
# EOF='' so also match here
# new extension block - read up to empty line or EOF
lineno
,
ext
=
self
.
_lineno
,
[
l
]
while
1
:
l
=
self
.
_readline
()
if
l
.
strip
()
==
""
:
break
ext
.
append
(
l
)
self
.
extblockv
.
append
((
lineno
,
''
.
join
(
ext
)))
return
l
def
readlines
(
self
):
while
1
:
l
=
self
.
readline
()
yield
l
if
not
l
:
break
# EOF
# xload_file loads benchmark data from file @ path with neotest extensions.
#
# returns -> Benchmark, exit_labels, []extlab.
def
xload_file
(
path
):
with
io
.
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
return
xload
(
f
)
# method decorator allows to define methods separate from class.
def
method
(
cls
):
...
...
@@ -198,7 +282,6 @@ def method(cls):
return
deco
# bylabel splits Benchmark into several groups of Benchmarks with specified
# labels having same values across a given group.
#
...
...
@@ -386,7 +469,7 @@ def main():
p
.
add_argument
(
"--split"
,
default
=
""
,
help
=
"split benchmarks by labels (default no split)"
)
args
=
p
.
parse_args
()
B
=
load_file
(
args
.
file
)
B
,
_
=
load_file
(
args
.
file
)
benchstat
(
sys
.
stdout
,
B
,
split
=
args
.
split
.
split
(
","
))
if
__name__
==
'__main__'
:
...
...
go/neo/t/benchplot
View file @
f5fec740
...
...
@@ -22,13 +22,15 @@
import
sys
,
re
from
collections
import
OrderedDict
from
benchlib
import
load_file
,
Unit
from
benchlib
import
x
load_file
,
Unit
import
matplotlib.pyplot
as
plt
from
matplotlib.patches
import
Rectangle
from
mpl_toolkits.axes_grid1.inset_locator
import
zoomed_inset_axes
,
mark_inset
,
\
TransformedBbox
,
BboxPatch
,
BboxConnectorPatch
from
pprint
import
pprint
# BenchSeries represents several runs of a benchmark with different "-<n>".
#
...
...
@@ -257,15 +259,41 @@ def plotlat1(ax, S):
def
main
():
B
=
load_file
(
sys
.
argv
[
1
])
B
,
_
,
extv
=
xload_file
(
sys
.
argv
[
1
])
# extv -> node {}, date
nodemap
=
OrderedDict
()
date
=
None
for
ext
in
extv
:
if
'xnode'
not
in
ext
:
textv
=
[
'%s: %s'
%
(
k
,
v
)
for
k
,
v
in
ext
.
items
()]
raise
RuntimeError
(
'ext block without xnode:
\
n
%s'
%
(
'
\
n
'
.
join
(
textv
),))
xnode
=
ext
[
'xnode'
]
# kirr@deco.navytux.spb.ru (... XXX vvv hacky, not robust
_
=
xnode
.
split
()[
0
]
# kirr@deco.navytux.spb.ru
_
=
_
.
split
(
'@'
)[
1
]
# deco.navytux.spb.ru
node
=
_
.
split
(
'.'
)[
0
]
nodemap
[
node
]
=
ext
if
'date'
in
ext
:
date
=
ext
[
'date'
]
# XXX if date = None -> warning "no date found"
if
date
is
None
:
date
=
"date: ?"
splitby
=
[
'dataset'
,
'cluster'
]
Bl
=
B
.
bylabel
(
splitby
)
for
labkey
in
Bl
:
print
labkey
# FIXME hack
if
labkey
==
():
# cpu benchmarks
continue
Bu
=
Bl
[
labkey
].
byunit
()
fig
=
plt
.
figure
(
figsize
=
(
2
*
7.5
,
10
))
# XXX figsize - temp?
...
...
@@ -315,14 +343,23 @@ def main():
plt
.
text
(
"xxx not found"
)
#fig.legend()
fig
.
legend
([
r0
,
r0
],
[
"aaa"
,
"bbb"
])
# legend showing labels from labkey
# https://matplotlib.org/tutorials/intermediate/legend_guide.html#multiple-legends-on-the-same-axes
lh
=
[
r0
]
*
len
(
labkey
)
ltext
=
[
'%s: %s'
%
(
k
,
v
)
for
k
,
v
in
labkey
]
fig
.
legend
(
lh
,
ltext
,
handlelength
=
0
,
handletextpad
=
0
,
loc
=
"upper right"
)
#fig.tight_layout()
fig
.
subplots_adjust
(
left
=
0.05
,
# no big marging on the left
#wspace=0.1
)
# date
fig
.
text
(
0.003
,
0.995
,
date
,
ha
=
'left'
,
va
=
'top'
)
plt
.
show
()
return
# XXX temp to show only first
...
...
go/neo/t/neotest
View file @
f5fec740
...
...
@@ -498,7 +498,7 @@ else:
local
gitver
=
$(
git
-C
$loc
describe
--long
--dirty
2>/dev/null
)
local
ver
test
"
$gitver
"
!=
""
&&
ver
=
"
$gitver
"
||
ver
=
"
$pyver
"
printf
"
# %-16s: %s
\n
"
"
$showas
"
"
$ver
"
printf
"
sw/%-16s %s
\n
"
"
${
showas
}
:
"
"
$ver
"
}
# proginfo <prog> ... - run `prog ...` or print that prog is missing
...
...
@@ -532,21 +532,21 @@ xhostname() {
# show information about local system (os, hardware, versions, ...)
system_info
()
{
echo
-n
"#
"
;
date
--rfc-2822
echo
-n
"#
`
whoami
`
@
`
hostname
--fqdn
2>/dev/null
||
hostname
`
("
echo
-n
e
"date:
\t
"
;
date
--rfc-2822
echo
-n
e
"xnode:
\t
`
whoami
`
@
`
hostname
--fqdn
2>/dev/null
||
hostname
`
("
echo
-n
"
${
myaddr6v
[0]
}
"
test
"
${#
myaddr6v
[@]
}
"
-eq
1
||
echo
-n
" (+
$((${#
myaddr6v
[@]
}
-
1
))
·ipv6)"
echo
-n
"
${
myaddr4v
[0]
}
"
test
"
${#
myaddr4v
[@]
}
"
-eq
1
||
echo
-n
" (+
$((${#
myaddr4v
[@]
}
-
1
))
·ipv4)"
echo
")"
echo
-n
"# "
;
uname
-a
echo
-n
e
"uname:
\t
"
;
uname
-a
# XXX key name
# cpu
echo
-n
"# cpu:
"
;
grep
"^model name"
/proc/cpuinfo |head
-1
|sed
-e
's/model name\s*: //'
echo
-n
e
"cpu:
\t
"
;
grep
"^model name"
/proc/cpuinfo |head
-1
|sed
-e
's/model name\s*: //'
syscpu
=
/sys/devices/system/cpu
sysidle
=
$syscpu
/cpuidle
cpuvabbrev
()
{
# cpuvabbrev cpu0 cpu1 cpu2 ... cpuN -> cpu[0-N]
cpuvabbrev
()
{
# cpuvabbrev cpu0 cpu1 cpu2 ... cpuN -> cpu
/
[0-N]
test
$#
-le
1
&&
echo
"
$@
"
&&
return
min
=
""
...
...
@@ -562,14 +562,14 @@ system_info() {
fi
max
=
$n
done
echo
"cpu[
$min
-
$max
]"
echo
"cpu
/
[
$min
-
$max
]"
}
freqcpuv
=()
# [] of cpu
freqstr
=
""
# text about cpufreq for cpus in ^^^
freqdump
()
{
test
"
${#
freqcpuv
[@]
}
"
=
0
&&
return
echo
"
#
`
cpuvabbrev
${
freqcpuv
[*]
}
`
:
$freqstr
"
echo
"
`
cpuvabbrev
${
freqcpuv
[*]
}
`
/freq
:
$freqstr
"
freqcpuv
=()
freqstr
=
""
}
...
...
@@ -578,7 +578,7 @@ system_info() {
idlestr
=
""
idledump
()
{
test
"
${#
idlecpuv
[@]
}
"
=
0
&&
return
echo
"
#
`
cpuvabbrev
${
idlecpuv
[*]
}
`
:
$idlestr
"
echo
"
`
cpuvabbrev
${
idlecpuv
[*]
}
`
/idle
:
$idlestr
"
idlecpuv
=()
idlestr
=
""
}
...
...
@@ -588,7 +588,7 @@ system_info() {
f
=
"
$cpu
/cpufreq"
fmin
=
`
fkghz
$f
/scaling_min_freq
`
fmax
=
`
fkghz
$f
/scaling_max_freq
`
fs
=
"
freq:
`
cat
$f
/scaling_driver
`
/
`
cat
$f
/scaling_governor
`
[
$fmin
-
$fmax
]"
fs
=
"
`
cat
$f
/scaling_driver
`
/
`
cat
$f
/scaling_governor
`
[
$fmin
-
$fmax
]"
if
[
"
$fs
"
!=
"
$freqstr
"
]
;
then
freqdump
freqstr
=
"
$fs
"
...
...
@@ -601,7 +601,7 @@ system_info() {
latmax
=
0
while
read
cpu
;
do
is
=
"
idle:
`
cat
$sysidle
/current_driver
`
/
`
cat
$sysidle
/current_governor_ro
`
:"
is
=
"
`
cat
$sysidle
/current_driver
`
/
`
cat
$sysidle
/current_governor_ro
`
:"
while
read
state
;
do
# XXX add target residency?
is+
=
" "
...
...
@@ -620,8 +620,8 @@ system_info() {
< <
(
ls
-vd
$syscpu
/cpu[0-9]
*
)
idledump
test
"
$freqstable
"
=
y
||
echo
"
# cpu: WARNING
: frequency not fixed - benchmark timings won't be stable"
test
"
$latmax
"
-le
10
||
echo
"
# cpu: WARNING
: C-state exit-latency is max
${
latmax
}
μs - up to that can add to networked and IPC request-reply latency"
test
"
$freqstable
"
=
y
||
echo
"
WARNING: cpu
: frequency not fixed - benchmark timings won't be stable"
test
"
$latmax
"
-le
10
||
echo
"
WARNING: cpu
: C-state exit-latency is max
${
latmax
}
μs - up to that can add to networked and IPC request-reply latency"
# disk under .
...
...
@@ -636,14 +636,14 @@ system_info() {
blkdev
=
$1
blkdev1
=
`
basename
$blkdev
`
# /dev/sda -> sda
# XXX lsblk: tmpfs: not a block device
echo
"#
$blkdev1
:
`
lsblk
-dn
-o
MODEL
$blkdev
`
rev
`
lsblk
-dn
-o
REV,SIZE
$blkdev
`
"
printf
"disk/%s: %s
\n
"
"
$blkdev1
"
"
`
lsblk
-dn
-o
MODEL
$blkdev
`
rev
`
lsblk
-dn
-o
REV,SIZE
$blkdev
`
"
}
case
"
$blkdev1
"
in
md
*
)
# software raid
slavev
=
`
ls
-x
/sys/class/block/
$blkdev1
/slaves
`
echo
"#
$blkdev1
(
`
cat
/sys/class/block/
$blkdev1
/md/level
`
) ->
$slavev
"
printf
"disk/%s:
\t
%s
\n
"
"
$blkdev1
"
"
(
`
cat
/sys/class/block/
$blkdev1
/md/level
`
) ->
$slavev
"
# XXX dup wrt dm-*; move recursion to common place
for
s
in
$slavev
;
do
s
=
`
echo
$s
|sed
-e
's/[0-9]*$//'
`
# sda3 -> sda
...
...
@@ -653,7 +653,7 @@ system_info() {
dm-
*
)
# device mapper
slavev
=
`
ls
-x
/sys/class/block/
$blkdev1
/slaves
`
echo
"#
$blkdev1
(
`
cat
/sys/class/block/
$blkdev1
/dm/name
`
) ->
$slavev
"
printf
"disk/%s:
\t
%s
\n
"
"
$blkdev1
"
"
(
`
cat
/sys/class/block/
$blkdev1
/dm/name
`
) ->
$slavev
"
# XXX dup wrt md*; move recursion to common place
for
s
in
$slavev
;
do
s
=
`
echo
$s
|sed
-e
's/[0-9]*$//'
`
# sda3 -> sda
...
...
@@ -671,7 +671,7 @@ system_info() {
find /sys/class/net
-type
l
-not
-lname
'*virtual*'
|sort |
\
while
read
nic
;
do
nicname
=
`
basename
$nic
`
# /sys/class/net/eth0 -> eth0
echo
-n
"
#
$nicname
: "
echo
-n
"
nic/
$nicname
: "
nicdev
=
`
realpath
$nic
/device
`
# /sys/class/net/eth0 -> /sys/devices/pci0000:00/0000:00:1f.6
case
"
$nicdev
"
in
...
...
@@ -700,7 +700,7 @@ system_info() {
featok
=
y
feat
=
`
ethtool
-k
$nicname
2>/dev/null
`
||
featok
=
n
if
[
$featok
!=
y
]
;
then
echo
"
#
$nicname
:
features: ?"
echo
"
nic/
$nicname
/
features: ?"
else
# feat1 name abbrev -> abbrev. value (e.g. "tx" or "!tx")
feat1
()
{
...
...
@@ -719,7 +719,7 @@ system_info() {
esac
}
s
=
"
#
$nicname
:
features:"
s
=
"
nic/
$nicname
/
features:"
# NOTE feature abbrevs are those used by `ethtool -K` to set them
s+
=
"
`
feat1 rx-checksumming rx
`
"
s+
=
"
`
feat1 tx-checksumming tx
`
"
...
...
@@ -748,7 +748,7 @@ system_info() {
# show rx/tx coalescing latency
echo
-n
"
#
$nicname
:
coalesce:"
echo
-n
"
nic/
$nicname
/
coalesce:"
coalok
=
y
coal
=
`
ethtool
-c
$nicname
2>/dev/null
`
||
coalok
=
n
if
[
$coalok
!=
y
]
;
then
...
...
@@ -779,7 +779,7 @@ system_info() {
fi
# show main parameters + GRO flush time
s
=
"
#
$nicname
:
"
s
=
"
nic/
$nicname
/status:
"
s+
=
"
`
cat
$nic
/operstate
`
"
speed
=
`
cat
$nic
/speed 2>/dev/null
`
||
speed
=
?
# returns EINVAL for wifi
s+
=
", speed=
$speed
"
...
...
@@ -798,15 +798,16 @@ system_info() {
# emit NIC warnings
for
warn
in
"
${
nicwarnv
[@]
}
"
;
do
echo
"
#
$nicname
: WARNING
:
$warn
"
echo
"
WARNING: nic/
$nicname
:
$warn
"
done
done
echo
-n
"# "
;
proginfo python
--version
2>&1
# https://bugs.python.org/issue18338
echo
-n
"# "
;
proginfo go version
echo
-n
"# "
;
proginfo python
-c
'import sqlite3 as s; print "sqlite %s (py mod %s)" % (s.sqlite_version, s.version)'
echo
-n
"# "
;
proginfo mysqld
--version
printf
"%-20s"
"sw/python:"
;
proginfo python
--version
2>&1
# https://bugs.python.org/issue18338
printf
"%-20s"
"sw/go:"
;
proginfo go version
printf
"%-20s"
"sw/sqlite:"
;
proginfo python
-c
\
'import sqlite3 as s; print "sqlite %s (py mod %s)" % (s.sqlite_version, s.version)'
printf
"%-20s"
"sw/mysqld:"
;
proginfo mysqld
--version
pyver neoppod neo
pyver zodb
...
...
@@ -1101,6 +1102,7 @@ zbench_go() {
# command: benchmark when client and storage are on the same computer
cmd_bench-local
()
{
echo
-e
">>> bench-local"
echo
-e
"
\n
*** neotest: node"
system_info
echo
-e
"
\n
*** cpu:
\n
"
bench_cpu
...
...
@@ -1195,9 +1197,9 @@ cmd_bench-cluster() {
test
-z
"
$url
"
&&
die
"Usage: neotest bench-cluster [user@]<host>:<path>"
echo
-e
">>> bench-cluster
$url
"
echo
-e
"
\n
#
server:
"
echo
-e
"
\n
#
*** neotest: node: (server)
"
system_info
echo
-e
"
\n
#
client:
"
echo
-e
"
\n
#
*** neotest: node: (client)
"
on
$url
./neotest info-local
echo
-e
"
\n
*** server cpu:"
...
...
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