xref: /freebsd/contrib/cortex-strings/scripts/plot-sizes.py (revision f0cfa1b168014f56c02b83e5f28412cc5f78d117)
1#!/usr/bin/env python
2
3"""Plot the performance for different block sizes of one function across
4variants.
5"""
6
7import libplot
8
9import pylab
10import pdb
11import math
12
13def pretty_kb(v):
14    if v < 1024:
15        return '%d' % v
16    else:
17        if v % 1024 == 0:
18            return '%d k' % (v//1024)
19        else:
20            return '%.1f k' % (v/1024)
21
22def plot(records, function, alignment=None, scale=1):
23    variants = libplot.unique(records, 'variant', prefer='this')
24    records = [x for x in records if x.function==function]
25
26    if alignment != None:
27        records = [x for x in records if x.src_alignment==alignment[0] and
28                   x.dst_alignment==alignment[1]]
29
30    alignments = libplot.unique(records, ('src_alignment', 'dst_alignment'))
31    if len(alignments) != 1:
32        return False
33    if libplot.alignments_equal(alignments):
34        aalignment = alignments[0][0]
35    else:
36        aalignment = "%s:%s" % (alignments[0][0], alignments[0][1])
37
38    bytes = libplot.unique(records, 'bytes')[0]
39
40    colours = libplot.make_colours()
41    all_x = []
42
43    pylab.figure(1).set_size_inches((6.4*scale, 4.8*scale))
44    pylab.clf()
45
46    if 'str' in function:
47        # The harness fills out to 16k.  Anything past that is an
48        # early match
49        top = 16384
50    else:
51        top = 2**31
52
53    for variant in variants:
54        matches = [x for x in records if x.variant==variant and x.bytes <= top]
55        matches.sort(key=lambda x: x.bytes)
56
57        X = sorted(list(set([x.bytes for x in matches])))
58        Y = []
59        Yerr = []
60        for xbytes in X:
61            vals = [x.bytes*x.loops/x.elapsed/(1024*1024) for x in matches if x.bytes == xbytes]
62            if len(vals) > 1:
63                mean = sum(vals)/len(vals)
64                Y.append(mean)
65                if len(Yerr) == 0:
66                    Yerr = [[], []]
67                err1 = max(vals) - mean
68                assert err1 >= 0
69                err2 = min(vals) - mean
70                assert err2 <= 0
71                Yerr[0].append(abs(err2))
72                Yerr[1].append(err1)
73            else:
74                Y.append(vals[0])
75
76        all_x.extend(X)
77        colour = colours.next()
78
79        if X:
80            pylab.plot(X, Y, c=colour)
81            if len(Yerr) > 0:
82                pylab.errorbar(X, Y, yerr=Yerr, c=colour, label=variant, fmt='o')
83            else:
84                pylab.scatter(X, Y, c=colour, label=variant, edgecolors='none')
85
86    pylab.legend(loc='upper left', ncol=3, prop={'size': 'small'})
87    pylab.grid()
88    pylab.title('%(function)s of %(aalignment)s byte aligned blocks' % locals())
89    pylab.xlabel('Size (B)')
90    pylab.ylabel('Rate (MB/s)')
91
92    # Figure out how high the range goes
93    top = max(all_x)
94
95    power = int(round(math.log(max(all_x)) / math.log(2)))
96
97    pylab.semilogx()
98
99    pylab.axes().set_xticks([2**x for x in range(0, power+1)])
100    pylab.axes().set_xticklabels([pretty_kb(2**x) for x in range(0, power+1)])
101    pylab.xlim(0, top)
102    pylab.ylim(0, pylab.ylim()[1])
103    return True
104
105def main():
106    records = libplot.parse()
107
108    functions = libplot.unique(records, 'function')
109    alignments = libplot.unique(records, ('src_alignment', 'dst_alignment'))
110
111    for function in functions:
112        for alignment in alignments:
113            for scale in [1, 2.5]:
114                if plot(records, function, alignment, scale):
115                    pylab.savefig('sizes-%s-%02d-%02d-%.1f.png' % (function, alignment[0], alignment[1], scale), dpi=72)
116
117    pylab.show()
118
119if __name__ == '__main__':
120    main()
121