1 #!/usr/bin/env python 2 ''' 3 Created on May 16, 2011 4 5 @author: bungeman 6 ''' 7 import sys 8 import getopt 9 import bench_util 10 11 def usage(): 12 """Prints simple usage information.""" 13 14 print '-o <file> the old bench output file.' 15 print '-n <file> the new bench output file.' 16 print '-h causes headers to be output.' 17 print '-s <stat> the type of statistical analysis used' 18 print ' Not specifying is the same as -s "avg".' 19 print ' avg: average of all data points' 20 print ' min: minimum of all data points' 21 print ' med: median of all data points' 22 print ' 25th: twenty-fifth percentile for all data points' 23 print '-f <fieldSpec> which fields to output and in what order.' 24 print ' Not specifying is the same as -f "bctondp".' 25 print ' b: bench' 26 print ' c: config' 27 print ' t: time type' 28 print ' o: old time' 29 print ' n: new time' 30 print ' d: diff' 31 print ' p: percent diff' 32 print '-t use tab delimited format for output.' 33 print '--match <bench> only matches benches which begin with <bench>.' 34 35 class BenchDiff: 36 """A compare between data points produced by bench. 37 38 (BenchDataPoint, BenchDataPoint)""" 39 def __init__(self, old, new): 40 self.old = old 41 self.new = new 42 self.diff = old.time - new.time 43 diffp = 0 44 if old.time != 0: 45 diffp = self.diff / old.time 46 self.diffp = diffp 47 48 def __repr__(self): 49 return "BenchDiff(%s, %s)" % ( 50 str(self.new), 51 str(self.old), 52 ) 53 54 def main(): 55 """Parses command line and writes output.""" 56 57 try: 58 opts, _ = getopt.getopt(sys.argv[1:], "f:o:n:s:ht", ['match=']) 59 except getopt.GetoptError, err: 60 print str(err) 61 usage() 62 sys.exit(2) 63 64 old = None 65 new = None 66 column_format = "" 67 header_format = "" 68 columns = 'bctondp' 69 header = False 70 stat_type = "avg" 71 use_tabs = False 72 match_bench = None; 73 74 for option, value in opts: 75 if option == "-o": 76 old = value 77 elif option == "-n": 78 new = value 79 elif option == "-h": 80 header = True 81 elif option == "-f": 82 columns = value 83 elif option == "-s": 84 stat_type = value 85 elif option == "-t": 86 use_tabs = True 87 elif option == "--match": 88 match_bench = value 89 else: 90 usage() 91 assert False, "unhandled option" 92 93 if old is None or new is None: 94 usage() 95 sys.exit(2) 96 97 old_benches = bench_util.parse({}, open(old, 'r'), stat_type) 98 new_benches = bench_util.parse({}, open(new, 'r'), stat_type) 99 100 bench_diffs = [] 101 for old_bench in old_benches: 102 #filter benches by the match criteria 103 if match_bench and not old_bench.bench.startswith(match_bench): 104 continue 105 106 #filter new_benches for benches that match old_bench 107 new_bench_match = [bench for bench in new_benches 108 if old_bench.bench == bench.bench and 109 old_bench.config == bench.config and 110 old_bench.time_type == bench.time_type 111 ] 112 if (len(new_bench_match) < 1): 113 continue 114 bench_diffs.append(BenchDiff(old_bench, new_bench_match[0])) 115 116 if use_tabs: 117 column_formats = { 118 'b' : '{bench}\t', 119 'c' : '{config}\t', 120 't' : '{time_type}\t', 121 'o' : '{old_time: 0.2f}\t', 122 'n' : '{new_time: 0.2f}\t', 123 'd' : '{diff: 0.2f}\t', 124 'p' : '{diffp: 0.1%}\t', 125 } 126 header_formats = { 127 'b' : '{bench}\t', 128 'c' : '{config}\t', 129 't' : '{time_type}\t', 130 'o' : '{old_time}\t', 131 'n' : '{new_time}\t', 132 'd' : '{diff}\t', 133 'p' : '{diffp}\t', 134 } 135 else: 136 bench_max_len = max(map(lambda b: len(b.old.bench), bench_diffs)) 137 config_max_len = max(map(lambda b: len(b.old.config), bench_diffs)) 138 column_formats = { 139 'b' : '{bench: >%d} ' % (bench_max_len), 140 'c' : '{config: <%d} ' % (config_max_len), 141 't' : '{time_type: <4} ', 142 'o' : '{old_time: >10.2f} ', 143 'n' : '{new_time: >10.2f} ', 144 'd' : '{diff: >+10.2f} ', 145 'p' : '{diffp: >+8.1%} ', 146 } 147 header_formats = { 148 'b' : '{bench: >%d} ' % (bench_max_len), 149 'c' : '{config: <%d} ' % (config_max_len), 150 't' : '{time_type: <4} ', 151 'o' : '{old_time: >10} ', 152 'n' : '{new_time: >10} ', 153 'd' : '{diff: >10} ', 154 'p' : '{diffp: >8} ', 155 } 156 157 for column_char in columns: 158 if column_formats[column_char]: 159 column_format += column_formats[column_char] 160 header_format += header_formats[column_char] 161 else: 162 usage() 163 sys.exit(2) 164 165 if header: 166 print header_format.format( 167 bench='bench' 168 , config='conf' 169 , time_type='time' 170 , old_time='old' 171 , new_time='new' 172 , diff='diff' 173 , diffp='diffP' 174 ) 175 176 bench_diffs.sort(key=lambda d : [d.diffp, 177 d.old.bench, 178 d.old.config, 179 d.old.time_type, 180 ]) 181 for bench_diff in bench_diffs: 182 print column_format.format( 183 bench=bench_diff.old.bench.strip() 184 , config=bench_diff.old.config.strip() 185 , time_type=bench_diff.old.time_type 186 , old_time=bench_diff.old.time 187 , new_time=bench_diff.new.time 188 , diff=bench_diff.diff 189 , diffp=bench_diff.diffp 190 ) 191 192 if __name__ == "__main__": 193 main() 194