From: Michal Sojka Date: Sat, 11 Dec 2010 08:22:44 +0000 (+0100) Subject: Merge branch 'master' of rtime.felk.cvut.cz:/can-benchmark X-Git-Tag: fix-allnoconfig~233 X-Git-Url: http://rtime.felk.cvut.cz/gitweb/can-benchmark.git/commitdiff_plain/839937d2c18ad240ff87ba33d6ce144d5d8793a0?hp=3902410fec947e132f1830d1c39251373615c85a Merge branch 'master' of rtime.felk.cvut.cz:/can-benchmark --- diff --git a/gw-tests/Makefile b/gw-tests/Makefile index 2f1cf86..c0bb27f 100644 --- a/gw-tests/Makefile +++ b/gw-tests/Makefile @@ -1,18 +1,37 @@ -T=$(filter-out lib.sh,$(wildcard *.sh)) +T:=$(filter-out lib.sh,$(wildcard *.sh)) -.PHONY: $(T) +# Run slow test at the end +T:=$(filter-out filter%,$(T)) $(filter filter%,$(T)) -all: $(T) html +.PHONY: $(T:%=run-%) + +all: $(T:%=run-%) html @echo "Run 'make plot' to generate graphs" -TEST_FLAGS = -P -t all +TEST_FLAGS = -P -t all -l all + +$(T:%=run-%):run-%: + ./$* $(TEST_FLAGS) + +.PHONY: plot plotall + +PLOT_SCRIPTS=$(shell find results -name plot.sh) + +define plot_template +plot: $1/thumb +$1/thumb: $1/plot.sh $(notdir $1).sh $(wildcard $1/*.txt) + $1/plot.sh -X +endef -$(T):%: - ./$@ $(TEST_FLAGS) +define plotall_template +plotall: plot-$1 +.PHONY: plot-$1 +plot-$1: + $1/plot.sh -X +endef -.PHONY: plot -plot: - $(MAKE) TEST_FLAGS="-p -X" +$(foreach result_dir,$(PLOT_SCRIPTS:%/plot.sh=%),$(eval $(call plot_template,$(result_dir)))) +$(foreach result_dir,$(PLOT_SCRIPTS:%/plot.sh=%),$(eval $(call plotall_template,$(result_dir)))) .PHONY: html html: diff --git a/gw-tests/filter-sff.sh b/gw-tests/filter-sff.sh index 547bb10..f1c78e3 100755 --- a/gw-tests/filter-sff.sh +++ b/gw-tests/filter-sff.sh @@ -4,10 +4,13 @@ ids="0 $(seq 255 256 2047)" -main() { +prepare() { sshgw 'for i in `seq 0 2047`; do cangw -A -s can0 -d can1 -f $(printf %x $i):c00007ff; done' +} + +main() { for i in $ids; do - latester -d can0 -d can1 -d can2 -c $COUNT -i $i $(traffic_and_length 2) -h hist-$i.dat -f time-$i.dat + latester -d can0 -d can1 -d can2 -c $COUNT -i $i $(traffic_and_length 2) -n id-$i done } @@ -16,13 +19,13 @@ plot_cmds() { set title "2048 GW jobs (one per id, mask C00007FF), no modifications" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" plot [0:1500] [1:$COUNT] \\ EOF lt=1 for i in $ids; do - echo_plot "\"hist-$i.dat\" with lp lt $lt title \"Message id $i\"" + echo_plot "\"id-$i-hist.txt\" with lp lt $lt title \"Message id $i\"" lt=$((lt+1)) done echo diff --git a/gw-tests/filter.sh b/gw-tests/filter.sh index 91743c9..51a8114 100755 --- a/gw-tests/filter.sh +++ b/gw-tests/filter.sh @@ -4,10 +4,13 @@ ids="0 $(seq 255 256 2047)" -main() { +prepare() { sshgw 'for i in `seq 0 2047`; do cangw -A -s can0 -d can1 -f $(printf %x $i):7ff; done' +} + +main() { for i in $ids; do - latester -d can0 -d can1 -d can2 -c $COUNT -i $i $(traffic_and_length 2) -h hist-$i.dat -f time-$i.dat + latester -d can0 -d can1 -d can2 -c $COUNT -i $i $(traffic_and_length 2) -n id-$i done } @@ -16,13 +19,13 @@ plot_cmds() { set title "2048 GW jobs (one per id, mask 0x7FF), no modifications" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" -plot [0:1500] [1:$COUNT] \\ +plot [0:] [1:$COUNT] \\ EOF lt=1 for i in $ids; do - echo_plot "\"hist-$i.dat\" with lp lt $lt title \"Message id $i\"" + echo_plot "\"id-$i-hist.txt\" with lp lt $lt title \"Message id $i\"" lt=$((lt+1)) done } diff --git a/gw-tests/genhtml/Makefile b/gw-tests/genhtml/Makefile index 17e0f2b..8463982 100644 --- a/gw-tests/genhtml/Makefile +++ b/gw-tests/genhtml/Makefile @@ -1,2 +1,7 @@ +all: test results + test: ./wvtestrun ./wvtest.py genhtml-test.py + +results: + $(MAKE) -C .. html diff --git a/gw-tests/genhtml/genhtml-test.py b/gw-tests/genhtml/genhtml-test.py index 7d77fba..3bdf3e3 100644 --- a/gw-tests/genhtml/genhtml-test.py +++ b/gw-tests/genhtml/genhtml-test.py @@ -4,29 +4,29 @@ from genhtml import * @wvtest def Dimension_and_DimValue(): d = Dimension('kern', 'Kernel') - d.addValue('2.6.31') - d.addValue('2.6.30') + DimValue(d, '2.6.31') + DimValue(d, '2.6.30') l=[] for v in d: WVPASSEQ(v.__class__, DimValue) l.append(v.value) lsorted = ['2.6.30', '2.6.31'] WVPASSEQ(l, lsorted) - WVPASSEQ(v.htmlLabel(), '2.6.31') + WVPASSEQ(v.htmlTableHeading(), '2.6.31') WVPASSEQ(d['2.6.31'].value, '2.6.31') @wvtest def Two_Dimensions_in_Tests(): - t = Tests(None, DimensionTest(), DimensionKern()) - WVPASSEQ([(a.__class__.__name__, b.__class__.__name__) for a, b in t.iterDimensionPairs()], + t = Tests(None, Space(DimensionTest(), DimensionKern())) + WVPASSEQ([(a.__class__.__name__, b.__class__.__name__) for a, b in t.space.iterDimensionPairs()], [('DimensionTest', 'DimensionKern'), ('DimensionKern', 'DimensionTest')]) @wvtest def Three_Dimensions_in_Tests(): dt = DimensionTest() dk = DimensionKern() dd = Dimension('tmp', "Tmp") - t = Tests(None, dt, dk, dd) - pairs = [(a.__class__.__name__, b.__class__.__name__) for a, b in t.iterDimensionPairs()] + t = Tests(None, Space(dt, dk, dd)) + pairs = [(a.__class__.__name__, b.__class__.__name__) for a, b in t.space.iterDimensionPairs()] WVPASSEQ(pairs[0], ('DimensionTest', 'DimensionKern')) WVPASSEQ(pairs[1], ('DimensionKern', 'DimensionTest')) WVPASSEQ(pairs[2], ('DimensionTest', 'Dimension')) @@ -34,33 +34,51 @@ def Three_Dimensions_in_Tests(): WVPASSEQ(pairs[4], ('DimensionKern', 'Dimension')) WVPASSEQ(pairs[5], ('Dimension', 'DimensionKern')) WVPASSEQ(len(pairs), 6) - WVEXCEPT(KeyError, t.addTest, None, [1, 2]) - WVEXCEPT(KeyError, t.addTest, None, [1, 2, 3, 4]) +# WVEXCEPT(KeyError, t.addTest, None, [1, 2]) +# WVEXCEPT(KeyError, t.addTest, None, [1, 2, 3, 4]) - class MyTest(Test): - pass +# class MyTest(Test): +# pass - t.addTest(MyTest, [1, 'a', 'A']); +# t.addTest(MyTest, [1, 'a', 'A']); - WVPASSEQ(dt.keys(), [1]) - WVPASSEQ(dk.keys(), ['a']) - WVPASSEQ(dd.keys(), ['A']) +# WVPASSEQ(dt.keys(), [1]) +# WVPASSEQ(dk.keys(), ['a']) +# WVPASSEQ(dd.keys(), ['A']) - v1 = dt[1] - v2 = dk['a'] - v3 = dd['A'] +# v1 = dt[1] +# v2 = dk['a'] +# v3 = dd['A'] - WVPASSEQ(t.getTest((v1, v2, v3)), MyTest) - WVPASSEQ(t.getTest((v1, v3, v2)), MyTest) - WVPASSEQ(t.getTest((v3, v2, v1)), MyTest) - WVEXCEPT(KeyError, t.getTest, (v1, v1, v1)) - WVEXCEPT(KeyError, t.getTest, (v1, v2)) - WVEXCEPT(TypeError, t.getTest, v1) +# WVPASSEQ(t.getTest((v1, v2, v3)), MyTest) +# WVPASSEQ(t.getTest((v1, v3, v2)), MyTest) +# WVPASSEQ(t.getTest((v3, v2, v1)), MyTest) +# WVEXCEPT(KeyError, t.getTest, (v1, v1, v1)) +# WVEXCEPT(KeyError, t.getTest, (v1, v2)) +# WVEXCEPT(Exception, t.getTest, v1) - WVPASSEQ([d.__class__.__name__ for d in t.iterRemainingDimensions([dt])], ['DimensionKern', 'Dimension']) - WVPASSEQ([d.__class__.__name__ for d in t.iterRemainingDimensions([dt, dd])], ['DimensionKern']) +# WVPASSEQ([d.__class__.__name__ for d in t.space.iterRemainingDimensions([dt])], ['DimensionKern', 'Dimension']) +# WVPASSEQ([d.__class__.__name__ for d in t.space.iterRemainingDimensions([dt, dd])], ['DimensionKern']) - WVPASSEQ(str([v for v in iterDimValues([dt, dk])]), str([[1,'a']])) - dt.addValue(2) - dk.addValue('b') - WVPASSEQ(str([v for v in iterDimValues([dt, dk])]), str([[1, 'a'], [2, 'a'], [1, 'b'], [2, 'b']])) +# WVPASSEQ(str([v for v in Space(dt, dk).iterValues()]), "[[DimValue(Dimension(test), 1), DimValue(Dimension(gwkern), 'a')]]") +# DimValue(dt, 2) +# DimValue(dk, 'b') +# WVPASSEQ(str([v for v in Space(dt, dk).iterValues()]), "[[DimValue(Dimension(test), 1), DimValue(Dimension(gwkern), 'a')], [DimValue(Dimension(test), 2), DimValue(Dimension(gwkern), 'a')], [DimValue(Dimension(test), 1), DimValue(Dimension(gwkern), 'b')], [DimValue(Dimension(test), 2), DimValue(Dimension(gwkern), 'b')]]") + +@wvtest +def SpaceTests(): + d1 = Dimension(1) + d2 = Dimension(2) + d3 = Dimension(3) + s = Space(d1, d2, d3) + WVPASSEQ(str(s), "[Dimension(1), Dimension(2), Dimension(3)]") + v11 = DimValue(d1, 'one-one') + v12 = DimValue(d1, 'one-two') + v21 = DimValue(d2, 'two-one') + v22 = DimValue(d2, 'two-two') + v31 = DimValue(d3, 'three-one') + WVPASSEQ(str(DimValues([v11, v21])), "[DimValue(Dimension(1), 'one-one'), DimValue(Dimension(2), 'two-one')]") + WVPASSEQ(str(DimValues([v11, v21]) - d1), "[DimValue(Dimension(2), 'two-one')]") + WVPASSEQ(str(DimValues([v11, v21]) - d2), "[DimValue(Dimension(1), 'one-one')]") + WVPASSEQ(str(DimValues([v21, v31]) + v11), "[DimValue(Dimension(2), 'two-one'), DimValue(Dimension(3), 'three-one'), DimValue(Dimension(1), 'one-one')]") + WVPASSEQ(str(s.reorder(DimValues([v21, v31, v11]))), "[DimValue(Dimension(1), 'one-one'), DimValue(Dimension(2), 'two-one'), DimValue(Dimension(3), 'three-one')]") diff --git a/gw-tests/genhtml/genhtml.py b/gw-tests/genhtml/genhtml.py index 70e918f..fc7620b 100755 --- a/gw-tests/genhtml/genhtml.py +++ b/gw-tests/genhtml/genhtml.py @@ -4,15 +4,42 @@ import os; import dircache; import sys; import urllib +import traceback -class DimValue: +class DimValue(object): + def __new__(cls, dim, value): + if value in dim: + return dim[value] + else: + return super(DimValue, cls).__new__(cls, dim, value) def __init__(self, dim, value): self.dim = dim self.value = value + self.dim.addValue(self) + def __str__(self): + return self.dim.val2str(self.value) def __repr__(self): - return repr(self.value) - def htmlLabel(self): - return self.dim.htmlLabel(self.value) + return "DimValue(%s, %s)" % (repr(self.dim), repr(self.value)) + def htmlTableHeading(self): + return self.dim.htmlTableHeading(self.value) + +class DimValues(list): + def replace(self, val): + for i in xrange(len(self)): + if self[i].dim == val.dim: + self[i] = val + def __add__(self, val): + ret = DimValues(self) + ret.append(val) + return ret + def __sub__(self, dim): + result = DimValues(self) + for v in self: + if v.dim == dim: + result.remove(v) + return result + def key(self): + return tuple([v.value for v in self]) class Dimension(dict): def __init__(self, atype, name=None): @@ -21,24 +48,36 @@ class Dimension(dict): self.name = name else: self.name = atype + self.sortedKeys = [] def __iter__(self): - keys = self.keys() - keys.sort() - for k in keys: - yield self[k] - - def addValue(self, *values): - for value in values: - if value not in self: - self[value] = DimValue(self, value) - def htmlLabel(self, v): - return v + for i in xrange(len(self)): + yield self.getValue(i) + def getValue(self, index): + return self[self.sortedKeys[index]] + + def addValue(self, value): + if value not in self: + if isinstance(value, DimValue): + self[value.value] = value + else: + raise Exception("Unsupported usage of addValue") + #self[value] = DimValue(self, value) + self.sortedKeys = self.keys() + self.sortedKeys.sort() + def val2str(self, v): + return str(v) + def htmlTableHeading(self, v): + return self.val2str(v) + def __str__(self): + return self.name + def __repr__(self): + return "Dimension(%s)"%self.type class DimensionKern(Dimension): def __init__(self): Dimension.__init__(self, 'gwkern', 'GW kernel') - def htmlLabel(self, v): + def htmlTableHeading(self, v): i=v.find(":") if i>0: kver=v[:i] else: kver=v @@ -53,10 +92,12 @@ class DimensionKern(Dimension): class DimensionHostKern(Dimension): def __init__(self): Dimension.__init__(self, 'hostkern', 'Host kernel') - def htmlLabel(self, v): + def val2str(self, v): if v.find("host-") == 0: v = v[5:] - # TODO: remove host- prefix + return v + def htmlTableHeading(self, v): + v = self.val2str(v) i = v.find(":") if i>0: kver = v[:i] else: kver = v @@ -71,145 +112,245 @@ class DimensionHostKern(Dimension): class DimensionTest(Dimension): def __init__(self): Dimension.__init__(self, 'test', 'Test') - def htmlLabel(self, v): + def htmlTableHeading(self, v): return v+"
source"%(urllib.quote(v)) +class DimensionLoad(Dimension): + def __init__(self): + Dimension.__init__(self, 'load', 'Load') + class DimensionTraffic(Dimension): def __init__(self): Dimension.__init__(self, 'traf', 'Traffic') - def htmlLabel(self, v): - return v - -class Test: + def val2str(self, v): + if v == "50": + return "50%" + elif v == "oneatatime": + return "one message at a time" + else: + return v + def htmlTableHeading(self, v): + return self.val2str(v) +class Test(object): @classmethod def isOnPath(cls, path): - f = os.path.join(path, 'plot.gp') + f = os.path.join(path, '.results') return os.path.isfile(f) - def __init__(self, path): + def __init__(self, path, values, tests=None): self.path = path + self.name = os.path.basename(path) + self.values = values + self.tests = tests def printThumbLink(self, file): - for img in dircache.listdir(self.path+'/thumb'): - print >>file, "" % \ - (urllib.quote(self.path), img, urllib.quote(self.path), img) - -def iterDimValues(dimensions): - idx = [0 for i in xrange(len(dimensions))] - done=False - while not done: - values=[] - for i in xrange(len(dimensions)): - values.append(dimensions[i].values()[idx[i]]) - yield values - done=True - for i in xrange(len(dimensions)): - idx[i] += 1 - if idx[i] < len(dimensions[i]): - done=False - break - idx[i] = 0 + thumb = self.path+'/thumb' + try: + imgs = [img for img in dircache.listdir(thumb)] + except OSError: + imgs = [ self.name + ".png" ] + for img in imgs: + print >>file, "" % \ + (urllib.quote(self.path), urllib.quote(self.path), img) + def generateHtml(self): + html = open(os.path.join(self.path, 'results.html'), "w") + title = "CAN gateway timing analysis" + cdup = "../"*len(self.values) + print >> html, """ + + + +%s + + + +

%s

""" % (title, cdup, title) + params = ["%s %s" % (v.dim, v) for v in self.values] + print >>html, "Results for:", ", ".join(params) + print >>html, "

Other results

" + for d in self.tests.space: + links = [] + for v in d: + if v in self.values: + links.append("%s"%str(v)) + else: + vv = DimValues(self.values) + vv.replace(v) + try: + href = cdup + urllib.quote(self.tests[vv.key()].path+"/results.html") + links.append("%s"%(href, str(v))) + except KeyError: + links.append("%s"%str(v)) + print >>html, "" + + print >>html, "
%s" % d, " ".join(links), "
" + print >>html, "
" % (self.name+".png") + print >>html, "Raw data
" + print >>html, "Script source
" % (cdup+self.name+".sh.html") + print >>html, "Back to top
" % cdup + + html.close() + +class Space(list): + """List of Dimensions()s (order matters)""" + def __init__(self, *dimensions): + self.extend(list(dimensions)) + def path2dimValues(self, path): + coordinates = path.split("/") + if len(coordinates) != len(self): + raise KeyError("The number coordinates do not match the number of dimensions: " + str(coordinates)) + + dv = DimValues([DimValue(self[i], coordinates[i]) \ + for i in xrange(len(coordinates))]) + return dv + + def iterValues(self): + idx = [0 for i in xrange(len(self))] + done=False + while not done: + values=DimValues() + for i in xrange(len(self)): + values.append(self[i].values()[idx[i]]) + yield values + done=True + for i in xrange(len(self)): + idx[i] += 1 + if idx[i] < len(self[i]): + done=False + break + idx[i] = 0 + def reorder(self, dimValues): + reordered = DimValues() + for d in self: + for v in dimValues: + if v.dim == d: + reordered.append(v) + return reordered + def iterDimensionPairs(self): + for i in xrange(len(self)): + for j in xrange(i+1, len(self)): + yield (self[i], self[j]) + yield (self[j], self[i]) + def iterRemainingDimensions(self, dimensionPair): + for d in self: + if d not in dimensionPair: + yield d + class Tests(dict): """Represents all tests organized along several dimensions""" - def __init__(self, rootpath, *dimensions): + def __init__(self, rootpath, space): dict.__init__(self) - self.dimensions = dimensions + self.space = space if (rootpath): self.populate(rootpath) def getTest(self, key): - realkey=[] - for d in self.dimensions: - for i in key: - if i.dim == d: - realkey.append(i.value) - if len(realkey) != len(self.dimensions): - raise KeyError("The coordinates in key do not match dimensions") - return self[tuple(realkey)] - - def addTest(self, test, coordinates): - if len(coordinates) != len(self.dimensions): - raise KeyError("The number coordinates do not match the number of dimensions: " + str(coordinates)) - self[tuple(coordinates)] = test - for i in xrange(len(coordinates)): - self.dimensions[i].addValue(coordinates[i]) + if len(key) != len(self.space): + raise KeyError("The coordinates in key do not match the dimension of the space") + realkey = self.space.reorder(key) + return self[realkey.key()] + def addTest(self, test): + self[test.values.key()] = test + def populate(self, rootpath): for root, dirs, files in os.walk(rootpath): if (root.find(rootpath) == 0): - coordinates = root[len(rootpath):] + path = root[len(rootpath):] else: - coordinates = rootpath + path = rootpath if Test.isOnPath(root): - self.addTest(Test(root), coordinates.split("/")) - def iterDimensionPairs(self): - for i in xrange(len(self.dimensions)): - for j in xrange(i+1, len(self.dimensions)): - yield (self.dimensions[i], self.dimensions[j]) - yield (self.dimensions[j], self.dimensions[i]) - def iterRemainingDimensions(self, dimensionPair): - for d in self.dimensions: - if d not in dimensionPair: - yield d + dv = self.space.path2dimValues(path) + self.addTest(Test(root, dv, self)) def generateHtml(self): - for pair in self.iterDimensionPairs(): - remdims = [d for d in self.iterRemainingDimensions(pair)] - for vals in iterDimValues(remdims): - page = Page(pair, remdims, vals, self) + for pair in self.space.iterDimensionPairs(): + remDims = Space(*tuple([d for d in self.space.iterRemainingDimensions(pair)])) + for vals in remDims.iterValues(): + page = Page(pair, vals, self) + print page.getName() page.generate() try: os.remove("index.html") except OSError: pass os.symlink(page.getName(), "index.html") + css = open("style.css", "w") + print >>css, """img { border: 0; } +table { border-collapse: collapse; } +th, td { border: 1px solid lightgray; padding: 4px;} +h4 { margin: 0; } +.otherview { margin: 1ex 0} +.otherview .value { color: black; padding: 0ex 1ex; -moz-border-radius: 1ex; border-radius: 1ex;} +.otherview .value a { color: inherit; text-decoration: none; } +.otherview .other:hover { background: #eee; } +.otherview .missing { color: gray; } +.otherview .current { background: #ccc; } +""" + css.close() + for test in self.values(): + print test.path + test.generateHtml() - os.system("source-highlight -d --output-dir=. ../*.sh") + os.system("source-highlight -d --output-dir=. ../*.sh > /dev/null") -class Page: - def __init__(self, dimPair, dimOther, valsOther, tests): +class Page(object): + def __init__(self, dimPair, valsOther, tests): self.dimy, self.dimx = dimPair - self.dimOther = dimOther - self.valsOther = valsOther + self.dimOther = [v.dim for v in valsOther] + self.valsOther = tests.space.reorder(valsOther) self.tests = tests def getName(self): - return "%s-vs-%s-%s.html"%(self.dimy.type, self.dimx.type, "-".join([v.value for v in self.valsOther])) + return "%s-vs-%s-for-%s.html"%(self.dimy.type, self.dimx.type, + "-".join([v.value for v in self.valsOther])) def generate(self): html = open(self.getName(), "w") - title = "CAN gateway timing analysis" + ", ".join([v.dim.name+" "+v.value for v in self.valsOther]) - print >> html, """ - + title = "CAN gateway timing analysis" + print >> html, """ + + %s - +

%s

""" % (title, title) + params = ["%s %s" % (v.dim, v) for v in self.valsOther] + print >>html, "

Results for ", ", ".join(params), "

" + print >>html, "

Other views

" + print >>html, "" for d in self.dimOther: - pass -# print >>html, "View for %s: " % str(ps.pageclass.name) -# for v in ps.values: -# print >>html, "%s | "%(ps.values.type, urllib.quote(v), v) -# print >>html, "
" -# try: -# print >>html, d.htmlPreamble() -# except Exception: -# pass - - print >>html, "
" + print >>html, "" % d + print >>html, "" % \ + Page((d, self.dimx), self.valsOther - d + self.dimy.getValue(0), self.tests).getName() + links = [] + print >>html, "" + print >>html, "
%s " % \ + Page((self.dimy, d), self.valsOther - d + self.dimx.getValue(0), self.tests).getName() + print >>html, "" + for v in d: + if v in self.valsOther: + links.append("%s"%str(v)) + else: + vv = DimValues(self.valsOther) + vv.replace(v) + links.append("%s"%(urllib.quote(Page((self.dimy, self.dimx), vv, self.tests).getName()), str(v))) + print >>html, " ".join(links) + print >>html, "
" + + print >>html, "" % (self.dimx.name, self.dimy.name) for x in self.dimx: - print >>html, "" % x.htmlLabel() + print >>html, "" % x.htmlTableHeading() print >>html, "" for y in self.dimy: - print >>html, "" % y.htmlLabel() + print >>html, "" % y.htmlTableHeading() for x in self.dimx: print >>html, "" + try: + test = tests.getTest(idx) + test.printThumbLink(html) + except KeyError: + print >>html, "N/A" + print >>html, "" print >>html, "" print >> html, """
%s →
%s ↓
%s%s
%s
%s" idx = [x,y] idx.extend(self.valsOther) - test = tests.getTest(idx) - test.printThumbLink(html) - print >>html, "
@@ -220,6 +361,7 @@ th, td { border: 1px solid lightgray; padding: 4px;} if __name__ == "__main__": os.chdir(sys.argv[1]) - tests = Tests("./", DimensionHostKern(), DimensionKern(), DimensionTraffic(), DimensionTest()) + os.system("rm *.html") + tests = Tests("./", Space(DimensionHostKern(), DimensionKern(), DimensionTraffic(), DimensionLoad(), DimensionTest())) tests.generateHtml() sys.exit(0) diff --git a/gw-tests/lib.sh b/gw-tests/lib.sh index da31988..739333c 100644 --- a/gw-tests/lib.sh +++ b/gw-tests/lib.sh @@ -3,6 +3,7 @@ set -e COUNT=10000 OPT_TRAFFIC=oneatatime +OPT_LOAD=none error() { echo $1 >&2 @@ -11,14 +12,19 @@ error() { while [ $# -gt 0 ]; do case "$1" in - -P) OPT_PLOT_DISABLE=1; shift;; - -p) OPT_PLOT_ONLY=1; shift;; + -P|--no-plot) OPT_PLOT_DISABLE=1; shift;; + -p|--plot) OPT_PLOT_ONLY=1; shift;; -X|--no-x11-plot) OPT_NO_X11=1; shift;; -t) case "$2" in all|flood|50|oneatatime) OPT_TRAFFIC=$2;; *) error "Unknown traffic specification: $2";; esac; shift 2;; + -l) case "$2" in + all|none|cpu|eth|can) OPT_LOAD=$2;; + *) error "Unknown load specification: $2";; + esac; + shift 2;; esac done @@ -29,9 +35,7 @@ sshgw() { if [[ ! -S $socket ]] || ! ssh -x -a -S $socket root@192.168.2.3 true; then # Create master connection to speed up subsequenct command. - # The ssh is put into background and the connection is closed - # after 10 minutes) - ssh -f -M -S $socket root@192.168.2.3 sleep 600 > /dev/null 2>&1 + ssh -N -f -M -S $socket root@192.168.2.3 >/dev/null 2>&1 fi ssh -x -a -S $socket root@192.168.2.3 "$@" } @@ -43,7 +47,7 @@ cleanupgw() { _plot() { local testname=`basename $0 .sh` - plot_cmds | sed -e "/set title/ s/[\"']\(.*\)[\"']/\"\1\\\\n($kvers)\"/" > plot.gp + plot_cmds | sed -e "/set title/ s/[\"']\(.*\)[\"']/\"\1\\\\n(GW kernel $kvers, Traffic $traffic, Load $load)\"/" > plot.gp if [[ ! -s plot.gp ]]; then return; fi if [ -z "$OPT_NO_X11" ]; then echo "set terminal x11 enhanced; $(< plot.gp)" | gnuplot -persist @@ -69,54 +73,100 @@ echo_plot() { traffic_and_length() { local opts - case $OPT_TRAFFIC in + case $traffic in flood) opts='';; 50) opts="-p $((2*(44+$1*8)))";; oneatatime) opts="-o";; - *) error "Unknown traffic specification" + *) error "Unknown traffic specification: $traffic" esac echo $opts -l $1 } +start_load() { + case $load in + none) ;; + cpu) sshgw 'hackbench -g 3 -l 10000' & loadpid=$!;; + eth) ping -f -s 60000 -q 192.168.2.3 & loadpid=$!;; # TODO: Generate eth load from another computer + can) latester -q -d can1 -i 0x7ff & loadpid=$!;; + *) error "Unknown load specification: $load" + esac +} + +kill_load() { + case $load in + none) ;; + cpu) kill $loadpid; sshgw "killall -q hackbench || :";; + eth) kill $loadpid;; + can) kill $loadpid;; + *) error "Unknown load specification: $load" + esac +} + +_measure() { + # Remove data from the last measurement + rm -rf * + touch .results + cat > plot.sh <<-EOF + #!/bin/bash + export kvers=$kvers + export hostkvers=$hostkvers + export traffic=$traffic + export load=$load + cd \$(dirname \$0)/$(dirname $script) + exec ./$(basename $script) --plot "\$@" + EOF + chmod +x plot.sh + # Kill load generators left possibly from the past runs + killall -q ping || : + killall -q latester || : + sshgw 'killall -q hackbench || :' + # Set can interfaces up + sshgw 'for i in 0 1; do ip link show dev can$i|grep -q UP || ip link set can$i up type can bitrate 1000000; done' + # Delete all vcan interfaces + sshgw 'for dev in $(ip l|grep -o vcan[^:]\\+); do ip link del dev $dev; done' + # Reset priorities + sshgw 'if pid=`pidof irq/145-can0`; then chrt -p -f 50 $pid > /dev/null; fi' + sshgw 'if pid=`pidof irq/146-can1`; then chrt -p -f 50 $pid > /dev/null; fi' + sshgw 'if pid=`pidof sirq-net-rx/0`; then chrt -p -f 49 $pid > /dev/null; fi' + sshgw 'if pid=`pidof sirq-net-tx/0`; then chrt -p -f 49 $pid > /dev/null; fi' + # Set the length of qdisc queue to avoid ENOBUFS errors + ifconfig can0 txqueuelen 200 + ifconfig can1 txqueuelen 200 + cleanupgw + + type prepare >/dev/null 2>&1 && prepare || : + start_load + main + kill_load +} + + _run() { - if [[ ! "$OPT_PLOT_ONLY" ]] - then kernel_versions=$(sshgw uname -r) - else kernel_versions= # TODO $(ls results/by-kern) - fi if [[ $OPT_TRAFFIC = all ]] then traffics="flood 50 oneatatime" - else traffics=$OPT_TRAFFIC + else traffics=${traffic:-$OPT_TRAFFIC} + fi + if [[ $OPT_LOAD = all ]] + then loads="none cpu eth" # TODO: can + else loads=${load:-$OPT_LOAD} fi - for OPT_TRAFFIC in $traffics; do - for kvers in $kernel_versions; do - dir="results/host-$(uname -r)/$kvers/$OPT_TRAFFIC/$(basename $0 .sh)" + hostkvers=${hostkvers:-host-$(uname -r)} + kvers=${kvers:-$(sshgw uname -r)} + test=$(basename $0 .sh) + for load in $loads; do + for traffic in $traffics; do + dir="results/$hostkvers/$kvers/$traffic/$load/$test" mkdir -p $dir - script=$PWD/$0 + script=$(echo $dir | sed -e 's/[^/]*/../g')/${test}.sh cd $dir - echo "Working directory: $dir" if [[ ! "$OPT_PLOT_ONLY" ]]; then - # Remove data from the last measurement - rm -rf * - # Set can interfaces up - sshgw 'for i in 0 1; do ip link show dev can$i|grep -q UP || ip link set can$i up type can bitrate 1000000; done' - # Delete all vcan interfaces - sshgw 'for dev in $(ip l|grep -o vcan[^:]\\+); do ip link del dev $dev; done' - # Reset priorities - sshgw 'if pid=`pidof irq/145-can0`; then chrt -p -f 50 $pid > /dev/null; fi' - sshgw 'if pid=`pidof irq/146-can1`; then chrt -p -f 50 $pid > /dev/null; fi' - sshgw 'if pid=`pidof sirq-net-rx/0`; then chrt -p -f 49 $pid > /dev/null; fi' - sshgw 'if pid=`pidof sirq-net-tx/0`; then chrt -p -f 49 $pid > /dev/null; fi' - # Set the length of qdisc queue to avoid ENOBUFS errors - ifconfig can0 txqueuelen 200 - cleanupgw - - main - cp $script . + echo "Working directory: $dir" + _measure fi if [[ ! "$OPT_PLOT_DISABLE" ]]; then _plot fi - cd - + cd - > /dev/null done done } diff --git a/gw-tests/mod.sh b/gw-tests/mod.sh index ea6a62b..6a870e6 100755 --- a/gw-tests/mod.sh +++ b/gw-tests/mod.sh @@ -7,19 +7,19 @@ main() { LATESTER_OPTS="-d can0 -d can1 -d can2 $(traffic_and_length 8) -c $COUNT" sshgw cangw -A -s can0 -d can1 - latester $LATESTER_OPTS -h hist.dat -f time.dat + latester $LATESTER_OPTS -n nop cleanupgw sshgw cangw -A -s can0 -d can1 -m OR:D:0.0.0000123400000000 \ -m SET:IL:123.8.0000000000000000 - latester $LATESTER_OPTS -h hist-mod.dat -f time-mod.dat + latester $LATESTER_OPTS -n mod cleanupgw sshgw cangw -A -s can0 -d can1 -m AND:ID:0.0.ffff000000000000 \ -m OR:D:0.0.0000123400000000 \ -m XOR:D:0.0.0000000012345678 \ -m SET:IL:123.8.0000000000000000 - latester $LATESTER_OPTS -h hist-mod2.dat -f time-mod2.dat + latester $LATESTER_OPTS -n mod2 cleanupgw sshgw cangw -A -s can0 -d can1 -m AND:ID:0.0.ffff000000000000 \ @@ -27,14 +27,14 @@ main() { -m XOR:D:0.0.0000000012345678 \ -m SET:IL:123.8.0000000000000000 \ -x 0:6:7:0 - latester $LATESTER_OPTS -h hist-modcsxor.dat -f time-modcsxor.dat + latester $LATESTER_OPTS -n modcsxor cleanupgw sshgw cangw -A -s can0 -d can1 -m AND:ID:0.0.ffff000000000000 \ -m OR:D:0.0.0000123400000000 \ -m XOR:D:0.0.0000000012345678 \ -m SET:IL:123.8.0000000000000000 \ -p 3 -c 0:6:7:0:0:00D013C326F635E54C9C5F8F6ABA79A998488B5BBE6EAD7DD404C717F222E13183539040A575B666CF1FDC0CE939FA2A1BCB08D83DED2EFE5787449471A162B2B565A67693438050F929EA3ADF0FCC1C2DFD3EEE0BDB18C861B172A24797548436E625F510C003D37AAA69B95C8C4F9FAE7EBD6D88589B4BE232F121C414D707D909CA1AFF2FEC3C95458656B363A0704191528267B774A40DDD1ECE2BFB38E85A8A49997CAC6FBF16C605D530E023F3C212D101E434F7278E5E9D4DA878BB6B6CBC7FAF4A9A598920F033E306D615C5F424E737D202C111B868AB7B9E4E8D5DEF3FFC2CC919DA0AA373B0608555964677A764B4518142923BEB28F81DCD0EDE - latester $LATESTER_OPTS -h hist-modcscrc8.dat -f time-modcscrc8.dat + latester $LATESTER_OPTS -n modcscrc8 } plot_cmds() { @@ -42,14 +42,14 @@ plot_cmds() { set title "Single GW job for all messages with modifications, 8 byte messages" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" plot [0:600] [1:$COUNT] \ - "hist.dat" with lp lt 1 title "No modifications", \ - "hist-mod.dat" with lp lt 2 title "Two modifications", \ - "hist-mod2.dat" with lp lt 3 title "Four modifications", \ - "hist-modcsxor.dat" with lp lt 4 title "Four modifications and XOR checksum",\ - "hist-modcscrc8.dat" with lp lt 5 title "Four modifications and CRC8 checksum" + "nop-hist.txt" with lp lt 1 title "No modifications", \ + "mod-hist.txt" with lp lt 2 title "Two modifications", \ + "mod2-hist.txt" with lp lt 3 title "Four modifications", \ + "modcsxor-hist.txt" with lp lt 4 title "Four modifications and XOR checksum",\ + "modcscrc8-hist.txt" with lp lt 5 title "Four modifications and CRC8 checksum" EOF } diff --git a/gw-tests/nop-highprio-time.sh b/gw-tests/nop-highprio-time.sh index f3cca21..953835c 100755 --- a/gw-tests/nop-highprio-time.sh +++ b/gw-tests/nop-highprio-time.sh @@ -3,7 +3,7 @@ . lib.sh main() { - : + ln -s ../nop-highprio/*.txt . } plot_cmds() { @@ -11,12 +11,12 @@ plot_cmds() { set title "Single GW job for all messages, no modifications, high (soft)irq task priority" set grid set xlabel "Time [s]" -set ylabel "Latency [{/Symbol m}s]" +set ylabel "Latency [ms]" plot [:] [:500] \ - "../nop-highprio/time2.dat" using 2:(1000000*$14) with points title "2 byte messages", \ - "../nop-highprio/time4.dat" using 2:(1000000*$14) with points title "4 byte messages", \ - "../nop-highprio/time6.dat" using 2:(1000000*$14) with points title "6 byte messages", \ - "../nop-highprio/time8.dat" using 2:(1000000*$14) with points title "8 byte messages" + "len2-msgs.txt" using 2:(1000*$14) with points title "2 byte messages", \ + "len4-msgs.txt" using 2:(1000*$14) with points title "4 byte messages", \ + "len6-msgs.txt" using 2:(1000*$14) with points title "6 byte messages", \ + "len8-msgs.txt" using 2:(1000*$14) with points title "8 byte messages" EOF } diff --git a/gw-tests/nop-highprio.sh b/gw-tests/nop-highprio.sh index e8dc865..271d64e 100755 --- a/gw-tests/nop-highprio.sh +++ b/gw-tests/nop-highprio.sh @@ -4,14 +4,20 @@ main() { sshgw cangw -A -s can0 -d can1 - sshgw 'chrt -p -f 99 `pidof irq/145-can0` || :' - sshgw 'chrt -p -f 99 `pidof irq/146-can1` || :' - sshgw 'chrt -p -f 98 `pidof sirq-net-rx/0` || :' - sshgw 'chrt -p -f 98 `pidof sirq-net-tx/0` || :' - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 2) -h hist2.dat -f time2.dat - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 4) -h hist4.dat -f time4.dat - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 6) -h hist6.dat -f time6.dat - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 8) -h hist8.dat -f time8.dat + sshgw 'if pid=`pidof irq/145-can0`; then chrt -p -f 99 $pid; fi' + sshgw 'if pid=`pidof irq/146-can1`; then chrt -p -f 99 $pid; fi' + + # Unfortunately, we must also increase FEC (Ethernet) IRQ priority + # to be above softirq. Otherwise the system crashes with eth load. + sshgw 'if pid=`pidof irq/192-mpc52xx`; then chrt -p -f 99 $pid; fi' + sshgw 'if pid=`pidof irq/193-mpc52xx`; then chrt -p -f 99 $pid; fi' + + sshgw 'if pid=`pidof sirq-net-rx/0`; then chrt -p -f 98 $pid; fi' + sshgw 'if pid=`pidof sirq-net-tx/0`; then chrt -p -f 98 $pid; fi' + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 2) -n len2 + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 4) -n len4 + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 6) -n len6 + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 8) -n len8 } plot_cmds() { @@ -19,13 +25,13 @@ plot_cmds() { set title "Single GW job for all messages, no modifications, high (soft)irq task priority" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" plot [0:600] [1:$COUNT] \ - "hist2.dat" with lp lt 1 title "2 byte messages", \ - "hist4.dat" with lp lt 2 title "4 byte messages", \ - "hist6.dat" with lp lt 3 title "6 byte messages", \ - "hist8.dat" with lp lt 4 title "8 byte messages" + "len2-hist.txt" with lp lt 1 title "2 byte messages", \ + "len4-hist.txt" with lp lt 2 title "4 byte messages", \ + "len6-hist.txt" with lp lt 3 title "6 byte messages", \ + "len8-hist.txt" with lp lt 4 title "8 byte messages" EOF } diff --git a/gw-tests/nop-time.sh b/gw-tests/nop-time.sh index 4065a35..4d3152d 100755 --- a/gw-tests/nop-time.sh +++ b/gw-tests/nop-time.sh @@ -3,7 +3,7 @@ . lib.sh main() { - : + ln -s ../nop-highprio/*.txt . } plot_cmds() { @@ -11,12 +11,12 @@ plot_cmds() { set title "Single GW job for all messages, no modifications" set grid set xlabel "Time [s]" -set ylabel "Latency [{/Symbol m}s]" +set ylabel "Latency [ms]" plot [:] [:500] \ - "../nop/time2.dat" using 2:(1000000*$14) with points title "2 byte messages", \ - "../nop/time4.dat" using 2:(1000000*$14) with points title "4 byte messages", \ - "../nop/time6.dat" using 2:(1000000*$14) with points title "6 byte messages", \ - "../nop/time8.dat" using 2:(1000000*$14) with points title "8 byte messages" + "len2-msgs.txt" using 2:(1000*$14) with points title "2 byte messages", \ + "len4-msgs.txt" using 2:(1000*$14) with points title "4 byte messages", \ + "len6-msgs.txt" using 2:(1000*$14) with points title "6 byte messages", \ + "len8-msgs.txt" using 2:(1000*$14) with points title "8 byte messages" EOF } diff --git a/gw-tests/nop.sh b/gw-tests/nop.sh index f5804e6..341124f 100755 --- a/gw-tests/nop.sh +++ b/gw-tests/nop.sh @@ -4,10 +4,10 @@ main() { sshgw cangw -A -s can0 -d can1 - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 2) -h hist2.dat -f time2.dat - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 4) -h hist4.dat -f time4.dat - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 6) -h hist6.dat -f time6.dat - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 8) -h hist8.dat -f time8.dat + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 2) -n len2 + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 4) -n len4 + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 6) -n len6 + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 8) -n len8 } plot_cmds() { @@ -15,13 +15,13 @@ plot_cmds() { set title "Single GW job for all messages, no modifications" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" plot [0:600] [1:$COUNT] \ - "hist2.dat" with lp lt 1 title "2 byte messages", \ - "hist4.dat" with lp lt 2 title "4 byte messages", \ - "hist6.dat" with lp lt 3 title "6 byte messages", \ - "hist8.dat" with lp lt 4 title "8 byte messages" + "len2-hist.txt" with lp lt 1 title "2 byte messages", \ + "len4-hist.txt" with lp lt 2 title "4 byte messages", \ + "len6-hist.txt" with lp lt 3 title "6 byte messages", \ + "len8-hist.txt" with lp lt 4 title "8 byte messages" EOF } diff --git a/gw-tests/pc.sh b/gw-tests/pc.sh index 62180f0..477b13c 100755 --- a/gw-tests/pc.sh +++ b/gw-tests/pc.sh @@ -3,10 +3,10 @@ . lib.sh main() { - latester -d can0 -d can1 -c $COUNT $(traffic_and_length 2) -h hist2.dat -f time2.dat - latester -d can0 -d can1 -c $COUNT $(traffic_and_length 4) -h hist4.dat -f time4.dat - latester -d can0 -d can1 -c $COUNT $(traffic_and_length 6) -h hist6.dat -f time6.dat - latester -d can0 -d can1 -c $COUNT $(traffic_and_length 8) -h hist8.dat -f time8.dat + latester -d can0 -d can1 -c $COUNT $(traffic_and_length 2) -n len2 + latester -d can0 -d can1 -c $COUNT $(traffic_and_length 4) -n len4 + latester -d can0 -d can1 -c $COUNT $(traffic_and_length 6) -n len6 + latester -d can0 -d can1 -c $COUNT $(traffic_and_length 8) -n len8 } plot_cmds() { @@ -14,13 +14,13 @@ plot_cmds() { set title "No GW, two interfaces in PC" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" -plot [0:600] [1:$COUNT] \ - "hist2.dat" with lp lt 1 title "2 byte messages", \ - "hist4.dat" with lp lt 2 title "4 byte messages", \ - "hist6.dat" with lp lt 3 title "6 byte messages", \ - "hist8.dat" with lp lt 4 title "8 byte messages" +plot [0:] [1:$COUNT] \ + "len2-hist.txt" with lp lt 1 title "2 byte messages", \ + "len4-hist.txt" with lp lt 2 title "4 byte messages", \ + "len6-hist.txt" with lp lt 3 title "6 byte messages", \ + "len8-hist.txt" with lp lt 4 title "8 byte messages" EOF } diff --git a/gw-tests/user.sh b/gw-tests/user.sh index a8f3498..18e6730 100755 --- a/gw-tests/user.sh +++ b/gw-tests/user.sh @@ -4,12 +4,12 @@ main() { pid=$(sshgw 'chrt -f 90 candump -s2 -b can1 can0 & echo $!') - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 2) -h uhist2.dat -f utime2.dat - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 8) -h uhist8.dat -f utime8.dat + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 2) -n user2 + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 8) -n user8 sshgw kill $pid sshgw cangw -A -s can0 -d can1 - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 2) -h khist2.dat -f ktime2.dat - latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 8) -h khist8.dat -f ktime8.dat + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 2) -n kern2 + latester -d can0 -d can1 -d can2 -c $COUNT $(traffic_and_length 8) -n kern8 } plot_cmds() { @@ -17,13 +17,13 @@ plot_cmds() { set title "Kernel vs. userspace GW, no modifications" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" plot [0:] [1:$COUNT] \ - "khist2.dat" with lp lt 1 title "Kernel GW, 2 byte messages", \ - "khist8.dat" with lp lt 2 title "Kernel GW, 8 byte messages", \ - "uhist2.dat" with lp lt 1 title "Userspace GW, 2 byte messages", \ - "uhist8.dat" with lp lt 2 title "Userspace GW, 8 byte messages" + "kern2-hist.txt" with lp lt 1 title "Kernel GW, 2 byte messages", \ + "kern8-hist.txt" with lp lt 2 title "Kernel GW, 8 byte messages", \ + "user2-hist.txt" with lp lt 1 title "Userspace GW, 2 byte messages", \ + "user8-hist.txt" with lp lt 2 title "Userspace GW, 8 byte messages" EOF } diff --git a/gw-tests/vcan.sh b/gw-tests/vcan.sh index 9ddbeea..7002bfc 100755 --- a/gw-tests/vcan.sh +++ b/gw-tests/vcan.sh @@ -14,7 +14,7 @@ main() { done sshgw cangw -A -s vcan0 -d can1 -f $(printf %x:C00007FF $i) - latester -d can0 -d can1 -d can2 -c $COUNT -i 0 -h hist-$i.dat -f time-$i.dat + latester -d can0 -d can1 -d can2 -c $COUNT -i 0 -n hops$i done sshgw ip link del dev vcan0 } @@ -24,13 +24,13 @@ plot_cmds() { set title "Chained GW jobs on a signle VCAN interface" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" plot [0:10000] [1:$COUNT] \\ EOF lt=2 for i in $numjobs; do - echo_plot "\"hist-$i.dat\" with lp lt $lt title \"$((i+2)) GW jobs, 1 vcan\"" + echo_plot "\"hops$i-hist.txt\" with lp lt $lt title \"$((i+2)) GW jobs, 1 vcan\"" lt=$((lt+1)) done } diff --git a/gw-tests/vcans.sh b/gw-tests/vcans.sh index 08160a9..d73165f 100755 --- a/gw-tests/vcans.sh +++ b/gw-tests/vcans.sh @@ -15,7 +15,7 @@ main() { done sshgw cangw -A -s $lastif -d can1 -f $(printf %x:C00007FF $((i-1))) - latester -d can0 -d can1 -d can2 -c $COUNT -i 0 $(traffic_and_length 2) -h hist-$i.dat -f time-$i.dat + latester -d can0 -d can1 -d can2 -c $COUNT -i 0 $(traffic_and_length 2) -n hops$i done } @@ -24,13 +24,13 @@ plot_cmds() { set title "Chained GW jobs on multiple VCAN interfaces" set logscale y set grid -set xlabel "Time [{/Symbol m}s]" +set xlabel "Time [ms]" set ylabel "Latency profile [messages]" plot [0:1000] [1:$COUNT] \\ EOF lt=1 for i in $numjobs; do - echo_plot "\"hist-$i.dat\" with lp lt $lt title \"$i GW jobs, $((i-1)) vcans\"" + echo_plot "\"hops$i-hist.txt\" with lp lt $lt title \"$i GW jobs, $((i-1)) vcans\"" lt=$((lt+1)) done } diff --git a/latester/histogram.h b/latester/histogram.h index ad7591c..4a9aade 100644 --- a/latester/histogram.h +++ b/latester/histogram.h @@ -40,10 +40,7 @@ void histogram_fprint(struct histogram *h, FILE *f) cum = sum; for (i = 0; i < h->allocated; i++) { if (h->data[i] != 0) { - if (!getenv("CANPING_MS")) - fprintf(f, "%d %lld\n", i*h->resolution, cum); - else - fprintf(f, "%g %lld\n", 1e-3*(i*h->resolution), cum); + fprintf(f, "%g %lld\n", 1e-3*(i*h->resolution), cum); } cum -= h->data[i]; } diff --git a/latester/latester.c b/latester/latester.c index 619c258..bdd539c 100644 --- a/latester/latester.c +++ b/latester/latester.c @@ -59,10 +59,15 @@ struct options { unsigned timeout_ms; unsigned count; unsigned oneattime; - FILE *file; - FILE *histogram; + char *name; int length; int userhist; + int quiet; + + /* Temporary variables */ + FILE *f_msgs; + FILE *f_hist; + FILE *f_stat; }; struct options opt = { @@ -76,6 +81,8 @@ struct { unsigned enobufs; unsigned overrun; unsigned lost; + struct timespec tic, tac; + unsigned timeouts; } stats; int num_interfaces = 0; @@ -158,12 +165,14 @@ void msg_info_print(FILE *f, struct msg_info *mi) #define S(ts) tstamp_str(local, &ts) #define DIFF(a, b) (timespec_subtract(&diff, &b, &a), S(diff)) - if (num_interfaces == 2) + switch (num_interfaces) { + case 2: fprintf(f, "%ld: %s %s -> %s (%s) %s = %s (%s)\n", num, S(mi->ts_sent), sent, S(mi->ts_rx_final_kern), S(mi->ts_rx_final), received, DIFF(mi->ts_sent, mi->ts_rx_final_kern), DIFF(mi->ts_sent, mi->ts_rx_final)); - else + break; + case 3: fprintf(f, "%ld: %s %s -> %s (%s) -> %s (%s) %s = %s (%s), %s (%s)\n", num, S(mi->ts_sent), sent, S(mi->ts_rx_onwire_kern), S(mi->ts_rx_onwire), @@ -172,35 +181,14 @@ void msg_info_print(FILE *f, struct msg_info *mi) DIFF(mi->ts_sent, mi->ts_rx_onwire), DIFF(mi->ts_rx_onwire_kern, mi->ts_rx_final_kern), DIFF(mi->ts_rx_onwire, mi->ts_rx_final)); + break; + } #undef S #undef DIFF num++; talloc_free (local); } -int msg_info_store(FILE *f, struct msg_info *mi) -{ - struct timespec diff; - void *local = talloc_new (NULL); - static long num = 0; - -#define S(ts) tstamp_str(local, &ts) -#define DIFF(a, b) (timespec_subtract(&diff, &b, &a), S(diff)) - - if (num_interfaces == 2) - fprintf(f, "%ld %d %d %s\n", - num, mi->id, mi->length, - DIFF(mi->ts_sent, mi->ts_rx_final_kern)); - else - fprintf(f, "%ld %d %d %s\n", - num, mi->id, mi->length, - DIFF(mi->ts_rx_onwire_kern, mi->ts_rx_final_kern)); -#undef S -#undef DIFF - talloc_free (local); -} - - /* Subtract the `struct timespec' values X and Y, storing the result in RESULT. Return 1 if the difference is negative, otherwise 0. */ @@ -237,16 +225,22 @@ void dbg_print_timespec(char *msg, struct timespec *tv) static inline unsigned get_msg_latency_us(struct msg_info *mi) { struct timespec diff; - if (num_interfaces == 3) + switch (num_interfaces) { + case 3: if (opt.userhist) timespec_subtract(&diff, &mi->ts_rx_final, &mi->ts_rx_onwire); else timespec_subtract(&diff, &mi->ts_rx_final_kern, &mi->ts_rx_onwire_kern); - else + break; + case 2: if (opt.userhist) timespec_subtract(&diff, &mi->ts_rx_final, &mi->ts_sent); else timespec_subtract(&diff, &mi->ts_rx_final_kern, &mi->ts_sent); + break; + default: + return 0; + } return diff.tv_sec * 1000000 + diff.tv_nsec/1000; } @@ -383,7 +377,7 @@ int send_frame(int socket) ret = write(socket, &frame, sizeof(frame)); trace_off(ret); - if (ret == -1) + if (ret == -1 || num_interfaces == 1) msg_info_free(mi); return ret; } @@ -503,8 +497,7 @@ void process_final_rx(int s) mi->ts_rx_final = ts_user; mi->received = frame; - if (opt.histogram) - histogram_add(&histogram, get_msg_latency_us(mi)); + histogram_add(&histogram, get_msg_latency_us(mi)); ret = write(completion_pipe[1], &mi, sizeof(mi)); if (ret == -1) @@ -518,6 +511,7 @@ void *measure_thread(void *arg) struct timespec timeout; struct sockaddr_can addr; sigset_t set; + int consecutive_timeouts = 0; MEMSET_ZERO(pfd); @@ -564,6 +558,8 @@ void *measure_thread(void *arg) if (opt.oneattime) SEND(); + get_tstamp(&stats.tic); + while (!finish_flag && (opt.count == 0 || count < opt.count || msg_in_progress != 0)) { @@ -582,7 +578,13 @@ void *measure_thread(void *arg) SEND(); } } else { - error(1, 0, "poll timeout"); + /* Lost message - send a new one */ + stats.timeouts++; + consecutive_timeouts++; + if (consecutive_timeouts < 10) + SEND(); + else /* Something is really broken */ + finish_flag = 1; } break; default: // Event @@ -602,6 +604,7 @@ void *measure_thread(void *arg) i = (num_interfaces == 2) ? 1 : 2; if (pfd[i].revents != 0) { + consecutive_timeouts = 0; process_final_rx(pfd[i].fd); msg_in_progress--; pfd[i].revents = 0; @@ -613,6 +616,8 @@ void *measure_thread(void *arg) } } + get_tstamp(&stats.tac); + for (i=0; i"); @@ -649,16 +655,6 @@ int parse_options(int argc, const char *argv[]) case 'd': num_interfaces++; break; - case 'f': - opt.file = fopen(poptGetOptArg(optCon), "w"); - if (!opt.file) - error(1, errno, "fopen: %s", poptGetOptArg(optCon)); - break; - case 'h': - opt.histogram = fopen(poptGetOptArg(optCon), "w"); - if (!opt.histogram) - error(1, errno, "fopen: %s", poptGetOptArg(optCon)); - break; } } if (c < -1) @@ -666,21 +662,47 @@ int parse_options(int argc, const char *argv[]) poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c)); - if (num_interfaces < 2 || num_interfaces > 3) - error(1, 0, "-d option must be given exactly 2 or 3 times"); + if (num_interfaces < 1 || num_interfaces > 3) + error(1, 0, "-d option must only be given one, two or three times"); if (opt.oneattime && opt.period_us) error(1, 0, "oneattime and period cannot be specified at the same time"); - poptFreeContext(optCon); + if (opt.name) { + char *f = talloc_asprintf(local, "%s-msgs.txt", opt.name); + opt.f_msgs = fopen(f, "w"); + if (!opt.f_msgs) + error(1, errno, "fopen: %s", f); + } + + if (opt.name) { + char *f = talloc_asprintf(local, "%s-hist.txt", opt.name); + opt.f_hist = fopen(f, "w"); + if (!opt.f_hist) + error(1, errno, "fopen: %s", f); + } + if (opt.name) { + char *f = talloc_asprintf(local, "%s-stat.txt", opt.name); + opt.f_stat = fopen(f, "w"); + if (!opt.f_stat) + error(1, errno, "fopen: %s", f); + } + + poptFreeContext(optCon); + talloc_free(local); return 0; } void print_progress() { - printf("\rSent %5d, in progress %5d", count, msg_in_progress); - fflush(stdout); + if (! opt.quiet) { + if (num_interfaces > 1) + printf("\rSent %5d, in progress %5d", count, msg_in_progress); + else + printf("\rSent %5d", count); + fflush(stdout); + } } int main(int argc, const char *argv[]) @@ -699,9 +721,7 @@ int main(int argc, const char *argv[]) for (i=0; i +#include +#include + +/* we need a termios structure to clear the HUPCL bit */ +struct termios tio; + +int main(int argc, char *argv[]) +{ + int fd; + int status; + + if (argc != 4) + { + printf("Usage: setSerialSignal port DTR RTS\n"); + printf("Usage: setSerialSignal /dev/ttyS0|/dev/ttyS1 0|1 0|1\n"); + exit( 1 ); + } + + if ((fd = open(argv[1],O_RDWR)) < 0) + { + printf("Couldn't open %s\n",argv[1]); + exit(1); + } + tcgetattr(fd, &tio); /* get the termio information */ + tio.c_cflag &= ~HUPCL; /* clear the HUPCL bit */ + tcsetattr(fd, TCSANOW, &tio); /* set the termio information */ + + ioctl(fd, TIOCMGET, &status); /* get the serial port status */ + + if ( argv[2][0] == '1' ) /* set the DTR line */ + status &= ~TIOCM_DTR; + else + status |= TIOCM_DTR; + + if ( argv[3][0] == '1' ) /* set the RTS line */ + status &= ~TIOCM_RTS; + else + status |= TIOCM_RTS; + + ioctl(fd, TIOCMSET, &status); /* set the serial port status */ + + close(fd); /* close the device file */ +} +