aboutsummaryrefslogtreecommitdiff
path: root/contrib/cortex-strings/scripts/plot.py
blob: aa2bb1adb5600e7f959350f47213c39aa89cb933 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Plot the results for each test.  Spits out a set of images into the
current directory.
"""

import libplot

import fileinput
import collections
import pprint

import pylab

Record = collections.namedtuple('Record', 'variant test size loops src_alignment dst_alignment run_id rawtime comment time bytes rate')

def unique(rows, name):
    """Takes a list of values, pulls out the named field, and returns
    a list of the unique values of this field.
    """
    return sorted(set(getattr(x, name) for x in rows))

def to_float(v):
    """Convert a string into a better type.

    >>> to_float('foo')
    'foo'
    >>> to_float('1.23')
    1.23
    >>> to_float('45')
    45
    """
    try:
        if '.' in v:
            return float(v)
        else:
            return int(v)
    except:
        return v

def parse():
    # Split the input up
    rows = [x.strip().split(':') for x in fileinput.input()]
    # Automatically turn numbers into the base type
    rows = [[to_float(y) for y in x] for x in rows]

    # Scan once to calculate the overhead
    r = [Record(*(x + [0, 0, 0])) for x in rows]
    bounces = pylab.array([(x.loops, x.rawtime) for x in r if x.test == 'bounce'])
    fit = pylab.polyfit(bounces[:,0], bounces[:,1], 1)

    records = []

    for row in rows:
        # Make a dummy record so we can use the names
        r1 = Record(*(row + [0, 0, 0]))

        bytes = r1.size * r1.loops
        # Calculate the bounce time
        delta = pylab.polyval(fit, [r1.loops])
        time = r1.rawtime - delta
        rate = bytes / time

        records.append(Record(*(row + [time, bytes, rate])))

    return records

def plot(records, field, scale, ylabel):
    variants = unique(records, 'variant')
    tests = unique(records, 'test')

    colours = libplot.make_colours()

    # A little hack.  We want the 'all' record to be drawn last so
    # that it's obvious on the graph.  Assume that no tests come
    # before it alphabetically
    variants.reverse()

    for test in tests:
        for variant in variants:
            v = [x for x in records if x.test==test and x.variant==variant]
            v.sort(key=lambda x: x.size)
            V = pylab.array([(x.size, getattr(x, field)) for x in v])

            # Ensure our results appear
            order = 1 if variant == 'this' else 0

            try:
                # A little hack.  We want the 'all' to be obvious on
                # the graph
                if variant == 'all':
                    pylab.scatter(V[:,0], V[:,1]/scale, label=variant)
                    pylab.plot(V[:,0], V[:,1]/scale)
                else:
                    pylab.plot(V[:,0], V[:,1]/scale, label=variant,
                            zorder=order, c = colours.next())

            except Exception, ex:
                # michaelh1 likes to run this script while the test is
                # still running which can lead to bad data
                print ex, 'on %s of %s' % (variant, test)

        pylab.legend(loc='lower right', ncol=2, prop={'size': 'small'})
        pylab.xlabel('Block size (B)')
        pylab.ylabel(ylabel)
        pylab.title('%s %s' % (test, field))
        pylab.grid()

        pylab.savefig('%s-%s.png' % (test, field), dpi=100)
        pylab.semilogx(basex=2)
        pylab.savefig('%s-%s-semilog.png' % (test, field), dpi=100)
        pylab.clf()

def test():
    import doctest
    doctest.testmod()

def main():
    records = parse()

    plot(records, 'rate', 1024**2, 'Rate (MB/s)')
    plot(records, 'time', 1, 'Total time (s)')

if __name__ == '__main__':
    main()