1 ''' 2 Created on May 16, 2011 3 4 @author: bungeman 5 ''' 6 import sys 7 import getopt 8 import re 9 10 def parse(lines): 11 """Takes iterable lines of bench output, returns {bench:{config:time}}.""" 12 13 benches = {} 14 current_bench = None 15 16 for line in lines: 17 #see if this line starts a new bench 18 new_bench = re.search('running bench \[\d+ \d+\] (.{28})', line) 19 if new_bench: 20 current_bench = new_bench.group(1) 21 22 #add configs on this line to the current bench 23 if current_bench: 24 for new_config in re.finditer(' (.{4}): msecs = (\d+\.\d+)', line): 25 current_config = new_config.group(1) 26 current_time = float(new_config.group(2)) 27 if current_bench in benches: 28 benches[current_bench][current_config] = current_time 29 else: 30 benches[current_bench] = {current_config : current_time} 31 32 return benches 33 34 def usage(): 35 """Prints simple usage information.""" 36 37 print '-o <file> the old bench output file.' 38 print '-n <file> the new bench output file.' 39 print '-h causes headers to be output.' 40 print '-f <fieldSpec> which fields to output and in what order.' 41 print ' Not specifying is the same as -f "bcondp".' 42 print ' b: bench' 43 print ' c: config' 44 print ' o: old time' 45 print ' n: new time' 46 print ' d: diff' 47 print ' p: percent diff' 48 49 50 def main(): 51 """Parses command line and writes output.""" 52 53 try: 54 opts, args = getopt.getopt(sys.argv[1:], "f:o:n:h") 55 except getopt.GetoptError, err: 56 print str(err) 57 usage() 58 sys.exit(2) 59 60 column_formats = { 61 'b' : '{bench: >28} ', 62 'c' : '{config: <4} ', 63 'o' : '{old_time: >10.2f} ', 64 'n' : '{new_time: >10.2f} ', 65 'd' : '{diff: >+10.2f} ', 66 'p' : '{diffp: >+7.1%} ', 67 } 68 header_formats = { 69 'b' : '{bench: >28} ', 70 'c' : '{config: <4} ', 71 'o' : '{old_time: >10} ', 72 'n' : '{new_time: >10} ', 73 'd' : '{diff: >10} ', 74 'p' : '{diffp: >7} ', 75 } 76 77 old = None 78 new = None 79 column_format = "" 80 header_format = "" 81 columns = 'bcondp' 82 header = False 83 84 for option, value in opts: 85 if option == "-o": 86 old = value 87 elif option == "-n": 88 new = value 89 elif option == "-h": 90 header = True 91 elif option == "-f": 92 columns = value 93 else: 94 usage() 95 assert False, "unhandled option" 96 97 if old is None or new is None: 98 usage() 99 sys.exit(2) 100 101 for column_char in columns: 102 if column_formats[column_char]: 103 column_format += column_formats[column_char] 104 header_format += header_formats[column_char] 105 else: 106 usage() 107 sys.exit(2) 108 109 if header: 110 print header_format.format( 111 bench='bench' 112 , config='conf' 113 , old_time='old' 114 , new_time='new' 115 , diff='diff' 116 , diffp='diffP' 117 ) 118 119 old_benches = parse(open(old, 'r')) 120 new_benches = parse(open(new, 'r')) 121 122 for old_bench, old_configs in old_benches.items(): 123 if old_bench in new_benches: 124 new_configs = new_benches[old_bench] 125 for old_config, old_time in old_configs.items(): 126 if old_config in new_configs: 127 new_time = new_configs[old_config] 128 old_time = old_configs[old_config] 129 print column_format.format( 130 bench=old_bench.strip() 131 , config=old_config.strip() 132 , old_time=old_time 133 , new_time=new_time 134 , diff=(old_time - new_time) 135 , diffp=((old_time-new_time)/old_time) 136 ) 137 138 139 if __name__ == "__main__": 140 main() 141