]> rtime.felk.cvut.cz Git - can-benchmark.git/commitdiff
Merge branch 'master' of rtime.felk.cvut.cz:/can-benchmark
authorMichal Sojka <sojkam1@fel.cvut.cz>
Sat, 11 Dec 2010 08:22:44 +0000 (09:22 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Sat, 11 Dec 2010 08:22:44 +0000 (09:22 +0100)
19 files changed:
gw-tests/Makefile
gw-tests/filter-sff.sh
gw-tests/filter.sh
gw-tests/genhtml/Makefile
gw-tests/genhtml/genhtml-test.py
gw-tests/genhtml/genhtml.py
gw-tests/lib.sh
gw-tests/mod.sh
gw-tests/nop-highprio-time.sh
gw-tests/nop-highprio.sh
gw-tests/nop-time.sh
gw-tests/nop.sh
gw-tests/pc.sh
gw-tests/user.sh
gw-tests/vcan.sh
gw-tests/vcans.sh
latester/histogram.h
latester/latester.c
utils/dtrrts.c [new file with mode: 0644]

index 2f1cf862cb9e92d54275999a92ed037eca2927b2..c0bb27f19083e4a822030733f1133497b89349db 100644 (file)
@@ -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:
index 547bb1029bc0b717825e930ff21d76d06d6122d6..f1c78e316fdcf05ad4ae6c8f81e31d48291e3a3d 100755 (executable)
@@ -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
index 91743c972b17a44f6af4d2d45052ada565f106bd..51a8114decfdbae514dda9dc3c4fd3a675462a4f 100755 (executable)
@@ -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
 }
index 17e0f2b0f0bae45254a5cb2ffe1e6d30449241e2..846398276c6c595e24b5b6266dd7e253c895f119 100644 (file)
@@ -1,2 +1,7 @@
+all: test results
+
 test:
        ./wvtestrun ./wvtest.py genhtml-test.py
+
+results:
+       $(MAKE) -C .. html
index 7d77fba7589a16e301a9c33dcdce288b5dde7972..3bdf3e321a6d4eaf72d8a3091977c5430039e516 100644 (file)
@@ -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')]")
index 70e918fba48dfd1a021fa5a3c99857d33d3bd557..fc7620bbcf392aeb3d735a8eb929ce6f4875aa08 100755 (executable)
@@ -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+"<br><a href='%s.sh.html'>source</a>"%(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, "<a href='%s/%s'><img src='%s/thumb/%s'></a>" % \
-               (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, "<a href='%s/results.html'><img src='%s/thumb/%s'></a>" % \
+                  (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, """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<title>%s</title>
+<link rel="stylesheet" href="%sstyle.css" type="text/css" /> 
+</head>
+<body>
+<h1>%s</h1>"""  % (title, cdup, title)
+        params = ["%s %s" % (v.dim, v) for v in self.values]
+        print >>html, "Results for:", ", ".join(params)
+        print >>html, "<div class='otherview'><h4>Other results</h4><table>"
+       for d in self.tests.space:
+            links = []
+            for v in d:
+                if v in self.values:
+                    links.append("<span class='value current'>%s</span>"%str(v))
+                else:
+                    vv = DimValues(self.values)
+                    vv.replace(v)
+                    try:
+                        href = cdup + urllib.quote(self.tests[vv.key()].path+"/results.html")
+                        links.append("<span class='value other'><a href='%s'>%s</a></span>"%(href, str(v)))
+                    except KeyError:
+                        links.append("<span class='value missing'>%s</span>"%str(v))
+            print >>html, "<tr><th>%s</th><td>" % d, " ".join(links), "</td></tr>"
+
+        print >>html, "</table></div>"
+        print >>html, "<div><img src='%s' /></div>" % (self.name+".png")
+        print >>html, "<a href='./'>Raw data</a><br />"
+        print >>html, "<a href='%s'>Script source</a><br />" % (cdup+self.name+".sh.html")
+        print >>html, "<a href='%s'>Back to top</a><br />" % 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, """<html>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+       title = "CAN gateway timing analysis" 
+       print >> html, """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
 <title>%s</title>
-<style>
-img { border: 0; }
-table { border-collapse: collapse; }
-th, td { border: 1px solid lightgray; padding: 4px;}
-</style>
+<link rel="stylesheet" href="style.css" type="text/css" /> 
 </head>
 <body>
 <h1>%s</h1>"""  % (title, title)
+        params = ["%s %s" % (v.dim, v) for v in self.valsOther]
+        print >>html, "<h3>Results for ", ", ".join(params), "</h3>"
+        print >>html, "<div class='otherview'><h4>Other views</h4>"
+        print >>html, "<table><tr>"
        for d in self.dimOther:
-           pass
-#             print >>html, "View for %s: " % str(ps.pageclass.name)
-#             for v in ps.values:
-#                 print >>html, "<a href='%s-%s.html'>%s</a> | "%(ps.values.type, urllib.quote(v), v)
-#             print >>html, "<br>"
-#             try:
-#                 print >>html, d.htmlPreamble()
-#             except Exception:
-#                 pass
-
-       print >>html, "<table><thead><tr><td> </td>"
+            print >>html, "<th>%s</th>" % d
+            print >>html, "<td><a href='%s'>&rarr;</a> " % \
+                Page((self.dimy, d), self.valsOther - d + self.dimx.getValue(0), self.tests).getName()
+            print >>html, "<a href='%s'>&darr;</a></td>" % \
+                Page((d, self.dimx), self.valsOther - d + self.dimy.getValue(0), self.tests).getName()
+            links = []
+            print >>html, "<td>"
+            for v in d:
+                if v in self.valsOther:
+                    links.append("<span class='value current'>%s</span>"%str(v))
+                else:
+                    vv = DimValues(self.valsOther)
+                    vv.replace(v)
+                    links.append("<span class='value other'><a href='%s'>%s</a></span>"%(urllib.quote(Page((self.dimy, self.dimx), vv, self.tests).getName()), str(v)))
+            print >>html, " ".join(links)
+            print >>html, "</td></tr>"
+        print >>html, "</table></div>"
+
+       print >>html, "<table><thead><tr><td>%s &rarr; <br />%s &darr;</td>" % (self.dimx.name, self.dimy.name)
        for x in self.dimx:
-           print >>html, "<th>%s</th>" % x.htmlLabel()
+           print >>html, "<th>%s</th>" % x.htmlTableHeading()
        print >>html, "</tr></thead>"
        for y in self.dimy:
-           print >>html, "<tr><th>%s</th>" % y.htmlLabel()
+           print >>html, "<tr><th>%s</th>" % y.htmlTableHeading()
 
            for x in self.dimx:
                print >>html, "<td>"
                idx = [x,y]
                idx.extend(self.valsOther)
-               test = tests.getTest(idx)
-               test.printThumbLink(html)
-               print >>html, "</td>"
+                try:
+                    test = tests.getTest(idx)
+                    test.printThumbLink(html)
+                except KeyError:
+                    print >>html, "N/A"
+                print >>html, "</td>"
            print >>html, "</tr>"
        print >> html, """
 </table>
@@ -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)
index da31988a62fa2e19b0d46b24da41a3485e8a21f9..739333c2227e353b387d5e01fb51e0a8e902a526 100644 (file)
@@ -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
 }
index ea6a62befe2464b9ca3491cedd80d69a868785c8..6a870e6b9fa3b26aeb90eb1b295cb32121a021e5 100755 (executable)
@@ -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
 }
     
index f3cca219669ba25ccbf2b6377e92ef86fbe59f4e..953835ce5f09b48355226a045217ef2f7494cde2 100755 (executable)
@@ -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
 }
     
index e8dc865f281449b57a0238f3b09be01cdaf966d1..271d64e539bbab8bb345c2f7657f5725902e0fb5 100755 (executable)
@@ -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
 }
     
index 4065a35fdb7ad3dc6e3b4635cd27cca89b83d6a6..4d3152d9a66b69f0edc4502a6b327238cf04965c 100755 (executable)
@@ -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
 }
     
index f5804e673dce7fc47d5427cf9ff05488b12a6474..341124f790f2d131b82fcb1e680c65596d5b151d 100755 (executable)
@@ -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
 }
     
index 62180f0ed4b20d1a6adc17d36779e17a2e89dc20..477b13c26807d4923e402ba9bd040ebbcf374334 100755 (executable)
@@ -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
 }
     
index a8f3498cea87f9f124f96d8d80c591f0739ed638..18e673088317a08f5e2d2aae280f611903b75e26 100755 (executable)
@@ -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
 }
     
index 9ddbeea92d275c11f3be74f78dbe5fd8fabff7c9..7002bfc8f381e272e8acbec50087d5f40dfa96f9 100755 (executable)
@@ -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
 }
index 08160a9e2c73bf09f659afe879ba9a44dfdd8478..d73165fc4d9f5374b9d9328ea300f9c89fa0306e 100755 (executable)
@@ -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
 }
index ad7591ccccf7f1220f80d3488307ff6560da0cd5..4a9aade0bc67c793cc89d22491eca22d8a90844b 100644 (file)
@@ -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];
        }
index 619c2582838a59a86959dd035b16485c4597d383..bdd539c2ebebdafaf4609a5ded90607998e8d1ef 100644 (file)
@@ -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<num_interfaces; i++)
                close(pfd[i].fd);
 
@@ -627,10 +632,10 @@ struct poptOption optionsTable[] = {
        { "timeout",'t', POPT_ARG_INT|POPT_ARGFLAG_SHOW_DEFAULT,  &opt.timeout_ms,0, "Timeout when period is zero", "ms"},
        { "oneattime",'o', POPT_ARG_NONE,                         &opt.oneattime,0,  "Send the next message only when the previous was finally received"},
        { "verbose",'v', POPT_ARG_NONE,                           NULL, 'v',         "Send the next message only when the previous was finally received"},
-       { "file",   'f', POPT_ARG_STRING,                         NULL, 'f',         "File where to store results", "filename"},
-       { "histogram", 'h', POPT_ARG_STRING,                      NULL, 'h',         "Store histogram in file", "filename"},
+       { "name",   'n', POPT_ARG_STRING,                         &opt.name, 0,      "Prefix of the generated files"},
        { "length", 'l', POPT_ARG_INT|POPT_ARGFLAG_SHOW_DEFAULT,  &opt.length, 0,    "The length of generated messages", "bytes"},
        { "userhist", 'u', POPT_ARG_NONE,                         &opt.userhist, 0,  "Generate histogram from userspace timestamps"},
+       { "quiet",  'q', POPT_ARG_NONE,                           &opt.quiet, 0,     "Do not print progress and statistics"},
        POPT_AUTOHELP
        { NULL, 0, 0, NULL, 0 }
 };
@@ -639,6 +644,7 @@ int parse_options(int argc, const char *argv[])
 {
        int c;
        poptContext optCon;   /* context for parsing command-line options */
+       void *local = talloc_new (NULL);
 
        optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
        //poptSetOtherOptionHelp(optCon, "[OPTIONS]* <port>");
@@ -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<MAX_INFOS; i++)
                msg_infos[i].id = -1;
 
-       if (opt.histogram) {
-               histogram_init(&histogram, 5000000, 1);
-       }
+       histogram_init(&histogram, 5000000, 1);
 
        ret = pipe(completion_pipe);
        if (ret == -1)
@@ -730,8 +750,7 @@ int main(int argc, const char *argv[])
                        ret = read(completion_pipe[0], &mi, sizeof(mi));
                        if (ret < sizeof(mi))
                                error(1, errno, "read completion returned %d", ret);
-                       if (opt.file)
-                               msg_info_print(opt.file, mi);
+                       msg_info_print(opt.f_msgs, mi);
                        msg_info_free(mi);
                        completed++;
                }
@@ -754,7 +773,8 @@ int main(int argc, const char *argv[])
                }
        }
        print_progress();
-       printf("\n");
+       if (!opt.quiet)
+               printf("\n");
 
        stats.lost = msg_in_progress;
 
@@ -763,19 +783,34 @@ int main(int argc, const char *argv[])
        close(completion_pipe[0]);
        close(completion_pipe[1]);
 
-       if (opt.histogram) {
-               histogram_fprint(&histogram, opt.histogram);
-               fclose(opt.histogram);
-       }
-       if (opt.file)
-               fclose(opt.file);
+       histogram_fprint(&histogram, opt.f_hist);
+       fclose(opt.f_hist);
+       fclose(opt.f_msgs);
+
 
-       if (stats.overrun)
+       fprintf(opt.f_stat, "cmdline='");
+       for (i=0; i<argc; i++)
+               fprintf(opt.f_stat, "%s%s", argv[i], i < argc-1 ? " " : "");
+       fprintf(opt.f_stat, "'\n");
+
+       timespec_subtract(&diff, &stats.tac, &stats.tic);
+       fprintf(opt.f_stat, "duration=%s # seconds\n", tstamp_str(NULL, &diff));
+       
+       fprintf(opt.f_stat, "sent=%d\n", count);
+       fprintf(opt.f_stat, "overrun=%d\n", stats.overrun);
+       if (stats.overrun && !opt.quiet)
                printf("overrun=%d\n", stats.overrun);
-       if (stats.enobufs)
+       fprintf(opt.f_stat, "enobufs=%d\n", stats.enobufs);
+       if (stats.enobufs && !opt.quiet)
                printf("enobufs=%d\n", stats.enobufs);
-       if (stats.lost)
+       fprintf(opt.f_stat, "lost=%d\n", stats.lost);
+       if (stats.lost && !opt.quiet)
                printf("lost=%d\n", stats.lost);
+       fprintf(opt.f_stat, "timeouts=%d\n", stats.timeouts);
+       if (stats.timeouts && !opt.quiet)
+               printf("timeouts=%d\n", stats.timeouts);
+
+       fclose(opt.f_stat);
 
        return 0;
 }
diff --git a/utils/dtrrts.c b/utils/dtrrts.c
new file mode 100644 (file)
index 0000000..ca22929
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * setSerialSignal v0.1 9/13/01
+ * www.embeddedlinuxinterfacing.com
+ *
+ *
+ * The original location of this source is
+ * http://www.embeddedlinuxinterfacing.com/chapters/06/setSerialSignal.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* setSerialSignal
+ * setSerialSignal sets the DTR and RTS serial port control signals.
+ * This program queries the serial port status then sets or clears
+ * the DTR or RTS bits based on user supplied command line setting.
+ *
+ * setSerialSignal clears the HUPCL bit. With the HUPCL bit set,
+ * when you close the serial port, the Linux serial port driver
+ * will drop DTR (assertion level 1, negative RS-232 voltage). By
+ * clearing the HUPCL bit, the serial port driver leaves the
+ * assertion level of DTR alone when the port is closed.
+ */
+
+/*
+gcc -o setSerialSignal setSerialSignal.c
+*/
+
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <termios.h>
+
+/* 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 */
+}
+