1*09a53ad8SAndrew Turner"""Plot the results for each test. Spits out a set of images into the 2*09a53ad8SAndrew Turnercurrent directory. 3*09a53ad8SAndrew Turner""" 4*09a53ad8SAndrew Turner 5*09a53ad8SAndrew Turnerimport libplot 6*09a53ad8SAndrew Turner 7*09a53ad8SAndrew Turnerimport fileinput 8*09a53ad8SAndrew Turnerimport collections 9*09a53ad8SAndrew Turnerimport pprint 10*09a53ad8SAndrew Turner 11*09a53ad8SAndrew Turnerimport pylab 12*09a53ad8SAndrew Turner 13*09a53ad8SAndrew TurnerRecord = collections.namedtuple('Record', 'variant test size loops src_alignment dst_alignment run_id rawtime comment time bytes rate') 14*09a53ad8SAndrew Turner 15*09a53ad8SAndrew Turnerdef unique(rows, name): 16*09a53ad8SAndrew Turner """Takes a list of values, pulls out the named field, and returns 17*09a53ad8SAndrew Turner a list of the unique values of this field. 18*09a53ad8SAndrew Turner """ 19*09a53ad8SAndrew Turner return sorted(set(getattr(x, name) for x in rows)) 20*09a53ad8SAndrew Turner 21*09a53ad8SAndrew Turnerdef to_float(v): 22*09a53ad8SAndrew Turner """Convert a string into a better type. 23*09a53ad8SAndrew Turner 24*09a53ad8SAndrew Turner >>> to_float('foo') 25*09a53ad8SAndrew Turner 'foo' 26*09a53ad8SAndrew Turner >>> to_float('1.23') 27*09a53ad8SAndrew Turner 1.23 28*09a53ad8SAndrew Turner >>> to_float('45') 29*09a53ad8SAndrew Turner 45 30*09a53ad8SAndrew Turner """ 31*09a53ad8SAndrew Turner try: 32*09a53ad8SAndrew Turner if '.' in v: 33*09a53ad8SAndrew Turner return float(v) 34*09a53ad8SAndrew Turner else: 35*09a53ad8SAndrew Turner return int(v) 36*09a53ad8SAndrew Turner except: 37*09a53ad8SAndrew Turner return v 38*09a53ad8SAndrew Turner 39*09a53ad8SAndrew Turnerdef parse(): 40*09a53ad8SAndrew Turner # Split the input up 41*09a53ad8SAndrew Turner rows = [x.strip().split(':') for x in fileinput.input()] 42*09a53ad8SAndrew Turner # Automatically turn numbers into the base type 43*09a53ad8SAndrew Turner rows = [[to_float(y) for y in x] for x in rows] 44*09a53ad8SAndrew Turner 45*09a53ad8SAndrew Turner # Scan once to calculate the overhead 46*09a53ad8SAndrew Turner r = [Record(*(x + [0, 0, 0])) for x in rows] 47*09a53ad8SAndrew Turner bounces = pylab.array([(x.loops, x.rawtime) for x in r if x.test == 'bounce']) 48*09a53ad8SAndrew Turner fit = pylab.polyfit(bounces[:,0], bounces[:,1], 1) 49*09a53ad8SAndrew Turner 50*09a53ad8SAndrew Turner records = [] 51*09a53ad8SAndrew Turner 52*09a53ad8SAndrew Turner for row in rows: 53*09a53ad8SAndrew Turner # Make a dummy record so we can use the names 54*09a53ad8SAndrew Turner r1 = Record(*(row + [0, 0, 0])) 55*09a53ad8SAndrew Turner 56*09a53ad8SAndrew Turner bytes = r1.size * r1.loops 57*09a53ad8SAndrew Turner # Calculate the bounce time 58*09a53ad8SAndrew Turner delta = pylab.polyval(fit, [r1.loops]) 59*09a53ad8SAndrew Turner time = r1.rawtime - delta 60*09a53ad8SAndrew Turner rate = bytes / time 61*09a53ad8SAndrew Turner 62*09a53ad8SAndrew Turner records.append(Record(*(row + [time, bytes, rate]))) 63*09a53ad8SAndrew Turner 64*09a53ad8SAndrew Turner return records 65*09a53ad8SAndrew Turner 66*09a53ad8SAndrew Turnerdef plot(records, field, scale, ylabel): 67*09a53ad8SAndrew Turner variants = unique(records, 'variant') 68*09a53ad8SAndrew Turner tests = unique(records, 'test') 69*09a53ad8SAndrew Turner 70*09a53ad8SAndrew Turner colours = libplot.make_colours() 71*09a53ad8SAndrew Turner 72*09a53ad8SAndrew Turner # A little hack. We want the 'all' record to be drawn last so 73*09a53ad8SAndrew Turner # that it's obvious on the graph. Assume that no tests come 74*09a53ad8SAndrew Turner # before it alphabetically 75*09a53ad8SAndrew Turner variants.reverse() 76*09a53ad8SAndrew Turner 77*09a53ad8SAndrew Turner for test in tests: 78*09a53ad8SAndrew Turner for variant in variants: 79*09a53ad8SAndrew Turner v = [x for x in records if x.test==test and x.variant==variant] 80*09a53ad8SAndrew Turner v.sort(key=lambda x: x.size) 81*09a53ad8SAndrew Turner V = pylab.array([(x.size, getattr(x, field)) for x in v]) 82*09a53ad8SAndrew Turner 83*09a53ad8SAndrew Turner # Ensure our results appear 84*09a53ad8SAndrew Turner order = 1 if variant == 'this' else 0 85*09a53ad8SAndrew Turner 86*09a53ad8SAndrew Turner try: 87*09a53ad8SAndrew Turner # A little hack. We want the 'all' to be obvious on 88*09a53ad8SAndrew Turner # the graph 89*09a53ad8SAndrew Turner if variant == 'all': 90*09a53ad8SAndrew Turner pylab.scatter(V[:,0], V[:,1]/scale, label=variant) 91*09a53ad8SAndrew Turner pylab.plot(V[:,0], V[:,1]/scale) 92*09a53ad8SAndrew Turner else: 93*09a53ad8SAndrew Turner pylab.plot(V[:,0], V[:,1]/scale, label=variant, 94*09a53ad8SAndrew Turner zorder=order, c = colours.next()) 95*09a53ad8SAndrew Turner 96*09a53ad8SAndrew Turner except Exception, ex: 97*09a53ad8SAndrew Turner # michaelh1 likes to run this script while the test is 98*09a53ad8SAndrew Turner # still running which can lead to bad data 99*09a53ad8SAndrew Turner print ex, 'on %s of %s' % (variant, test) 100*09a53ad8SAndrew Turner 101*09a53ad8SAndrew Turner pylab.legend(loc='lower right', ncol=2, prop={'size': 'small'}) 102*09a53ad8SAndrew Turner pylab.xlabel('Block size (B)') 103*09a53ad8SAndrew Turner pylab.ylabel(ylabel) 104*09a53ad8SAndrew Turner pylab.title('%s %s' % (test, field)) 105*09a53ad8SAndrew Turner pylab.grid() 106*09a53ad8SAndrew Turner 107*09a53ad8SAndrew Turner pylab.savefig('%s-%s.png' % (test, field), dpi=100) 108*09a53ad8SAndrew Turner pylab.semilogx(basex=2) 109*09a53ad8SAndrew Turner pylab.savefig('%s-%s-semilog.png' % (test, field), dpi=100) 110*09a53ad8SAndrew Turner pylab.clf() 111*09a53ad8SAndrew Turner 112*09a53ad8SAndrew Turnerdef test(): 113*09a53ad8SAndrew Turner import doctest 114*09a53ad8SAndrew Turner doctest.testmod() 115*09a53ad8SAndrew Turner 116*09a53ad8SAndrew Turnerdef main(): 117*09a53ad8SAndrew Turner records = parse() 118*09a53ad8SAndrew Turner 119*09a53ad8SAndrew Turner plot(records, 'rate', 1024**2, 'Rate (MB/s)') 120*09a53ad8SAndrew Turner plot(records, 'time', 1, 'Total time (s)') 121*09a53ad8SAndrew Turner 122*09a53ad8SAndrew Turnerif __name__ == '__main__': 123*09a53ad8SAndrew Turner main() 124