o3-pipeview.py revision 9188
18471SGiacomo.Gabrielli@arm.com#! /usr/bin/env python 28471SGiacomo.Gabrielli@arm.com 38471SGiacomo.Gabrielli@arm.com# Copyright (c) 2011 ARM Limited 48471SGiacomo.Gabrielli@arm.com# All rights reserved 58471SGiacomo.Gabrielli@arm.com# 68471SGiacomo.Gabrielli@arm.com# The license below extends only to copyright in the software and shall 78471SGiacomo.Gabrielli@arm.com# not be construed as granting a license to any other intellectual 88471SGiacomo.Gabrielli@arm.com# property including but not limited to intellectual property relating 98471SGiacomo.Gabrielli@arm.com# to a hardware implementation of the functionality of the software 108471SGiacomo.Gabrielli@arm.com# licensed hereunder. You may use the software subject to the license 118471SGiacomo.Gabrielli@arm.com# terms below provided that you ensure that this notice is replicated 128471SGiacomo.Gabrielli@arm.com# unmodified and in its entirety in all distributions of the software, 138471SGiacomo.Gabrielli@arm.com# modified or unmodified, in source code or in binary form. 148471SGiacomo.Gabrielli@arm.com# 158471SGiacomo.Gabrielli@arm.com# Redistribution and use in source and binary forms, with or without 168471SGiacomo.Gabrielli@arm.com# modification, are permitted provided that the following conditions are 178471SGiacomo.Gabrielli@arm.com# met: redistributions of source code must retain the above copyright 188471SGiacomo.Gabrielli@arm.com# notice, this list of conditions and the following disclaimer; 198471SGiacomo.Gabrielli@arm.com# redistributions in binary form must reproduce the above copyright 208471SGiacomo.Gabrielli@arm.com# notice, this list of conditions and the following disclaimer in the 218471SGiacomo.Gabrielli@arm.com# documentation and/or other materials provided with the distribution; 228471SGiacomo.Gabrielli@arm.com# neither the name of the copyright holders nor the names of its 238471SGiacomo.Gabrielli@arm.com# contributors may be used to endorse or promote products derived from 248471SGiacomo.Gabrielli@arm.com# this software without specific prior written permission. 258471SGiacomo.Gabrielli@arm.com# 268471SGiacomo.Gabrielli@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 278471SGiacomo.Gabrielli@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 288471SGiacomo.Gabrielli@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 298471SGiacomo.Gabrielli@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 308471SGiacomo.Gabrielli@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 318471SGiacomo.Gabrielli@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 328471SGiacomo.Gabrielli@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 338471SGiacomo.Gabrielli@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 348471SGiacomo.Gabrielli@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 358471SGiacomo.Gabrielli@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 368471SGiacomo.Gabrielli@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 378471SGiacomo.Gabrielli@arm.com# 388471SGiacomo.Gabrielli@arm.com# Authors: Giacomo Gabrielli 398471SGiacomo.Gabrielli@arm.com 408471SGiacomo.Gabrielli@arm.com# Pipeline activity viewer for the O3 CPU model. 418471SGiacomo.Gabrielli@arm.com 428471SGiacomo.Gabrielli@arm.comimport optparse 438471SGiacomo.Gabrielli@arm.comimport os 448471SGiacomo.Gabrielli@arm.comimport sys 458471SGiacomo.Gabrielli@arm.com 468471SGiacomo.Gabrielli@arm.com 478471SGiacomo.Gabrielli@arm.comdef process_trace(trace, outfile, cycle_time, width, color, timestamps, 488471SGiacomo.Gabrielli@arm.com start_tick, stop_tick, start_sn, stop_sn): 498471SGiacomo.Gabrielli@arm.com line = None 508471SGiacomo.Gabrielli@arm.com fields = None 518471SGiacomo.Gabrielli@arm.com # Skip lines up to region of interest 528471SGiacomo.Gabrielli@arm.com if start_tick != 0: 538471SGiacomo.Gabrielli@arm.com while True: 548471SGiacomo.Gabrielli@arm.com line = trace.readline() 558471SGiacomo.Gabrielli@arm.com if not line: return 568471SGiacomo.Gabrielli@arm.com fields = line.split(':') 578471SGiacomo.Gabrielli@arm.com if fields[0] != 'O3PipeView': continue 588471SGiacomo.Gabrielli@arm.com if int(fields[2]) >= start_tick: break 598471SGiacomo.Gabrielli@arm.com elif start_sn != 0: 608471SGiacomo.Gabrielli@arm.com while True: 618471SGiacomo.Gabrielli@arm.com line = trace.readline() 628471SGiacomo.Gabrielli@arm.com if not line: return 638471SGiacomo.Gabrielli@arm.com fields = line.split(':') 648471SGiacomo.Gabrielli@arm.com if fields[0] != 'O3PipeView': continue 658471SGiacomo.Gabrielli@arm.com if fields[1] == 'fetch' and int(fields[5]) >= start_sn: break 668471SGiacomo.Gabrielli@arm.com else: 678471SGiacomo.Gabrielli@arm.com line = trace.readline() 688471SGiacomo.Gabrielli@arm.com if not line: return 698471SGiacomo.Gabrielli@arm.com fields = line.split(':') 708471SGiacomo.Gabrielli@arm.com # Skip lines up to next instruction fetch 718471SGiacomo.Gabrielli@arm.com while fields[0] != 'O3PipeView' or fields[1] != 'fetch': 728471SGiacomo.Gabrielli@arm.com line = trace.readline() 738471SGiacomo.Gabrielli@arm.com if not line: return 748471SGiacomo.Gabrielli@arm.com fields = line.split(':') 758471SGiacomo.Gabrielli@arm.com # Print header 768471SGiacomo.Gabrielli@arm.com outfile.write('// f = fetch, d = decode, n = rename, p = dispatch, ' 778471SGiacomo.Gabrielli@arm.com 'i = issue, c = complete, r = retire\n\n') 788471SGiacomo.Gabrielli@arm.com outfile.write(' ' + 'timeline'.center(width) + 798471SGiacomo.Gabrielli@arm.com ' ' + 'tick'.center(15) + 808471SGiacomo.Gabrielli@arm.com ' ' + 'pc.upc'.center(12) + 818471SGiacomo.Gabrielli@arm.com ' ' + 'disasm'.ljust(25) + 828471SGiacomo.Gabrielli@arm.com ' ' + 'seq_num'.center(15)) 838471SGiacomo.Gabrielli@arm.com if timestamps: 848471SGiacomo.Gabrielli@arm.com outfile.write('timestamps'.center(25)) 858471SGiacomo.Gabrielli@arm.com outfile.write('\n') 868471SGiacomo.Gabrielli@arm.com # Region of interest 878471SGiacomo.Gabrielli@arm.com curr_inst = {} 888471SGiacomo.Gabrielli@arm.com while True: 898471SGiacomo.Gabrielli@arm.com if fields[0] == 'O3PipeView': 908471SGiacomo.Gabrielli@arm.com curr_inst[fields[1]] = int(fields[2]) 918471SGiacomo.Gabrielli@arm.com if fields[1] == 'fetch': 928471SGiacomo.Gabrielli@arm.com if ((stop_tick > 0 and int(fields[2]) > stop_tick) or 938471SGiacomo.Gabrielli@arm.com (stop_sn > 0 and int(fields[5]) > stop_sn)): 948471SGiacomo.Gabrielli@arm.com return 958471SGiacomo.Gabrielli@arm.com (curr_inst['pc'], curr_inst['upc']) = fields[3:5] 968471SGiacomo.Gabrielli@arm.com curr_inst['sn'] = int(fields[5]) 978471SGiacomo.Gabrielli@arm.com curr_inst['disasm'] = ' '.join(fields[6][:-1].split()) 988471SGiacomo.Gabrielli@arm.com elif fields[1] == 'retire': 998471SGiacomo.Gabrielli@arm.com print_inst(outfile, curr_inst, cycle_time, width, color, 1008471SGiacomo.Gabrielli@arm.com timestamps) 1018471SGiacomo.Gabrielli@arm.com line = trace.readline() 1028471SGiacomo.Gabrielli@arm.com if not line: return 1038471SGiacomo.Gabrielli@arm.com fields = line.split(':') 1048471SGiacomo.Gabrielli@arm.com 1058471SGiacomo.Gabrielli@arm.com 1068471SGiacomo.Gabrielli@arm.comdef print_inst(outfile, inst, cycle_time, width, color, timestamps): 1078471SGiacomo.Gabrielli@arm.com if color: 1088471SGiacomo.Gabrielli@arm.com from m5.util.terminal import termcap 1098471SGiacomo.Gabrielli@arm.com else: 1108471SGiacomo.Gabrielli@arm.com from m5.util.terminal import no_termcap as termcap 1118471SGiacomo.Gabrielli@arm.com # Pipeline stages 1128471SGiacomo.Gabrielli@arm.com stages = [{'name': 'fetch', 1138471SGiacomo.Gabrielli@arm.com 'color': termcap.Blue + termcap.Reverse, 1148471SGiacomo.Gabrielli@arm.com 'shorthand': 'f'}, 1158471SGiacomo.Gabrielli@arm.com {'name': 'decode', 1168471SGiacomo.Gabrielli@arm.com 'color': termcap.Yellow + termcap.Reverse, 1178471SGiacomo.Gabrielli@arm.com 'shorthand': 'd'}, 1188471SGiacomo.Gabrielli@arm.com {'name': 'rename', 1198471SGiacomo.Gabrielli@arm.com 'color': termcap.Magenta + termcap.Reverse, 1208471SGiacomo.Gabrielli@arm.com 'shorthand': 'n'}, 1218471SGiacomo.Gabrielli@arm.com {'name': 'dispatch', 1228471SGiacomo.Gabrielli@arm.com 'color': termcap.Green + termcap.Reverse, 1238471SGiacomo.Gabrielli@arm.com 'shorthand': 'p'}, 1248471SGiacomo.Gabrielli@arm.com {'name': 'issue', 1258471SGiacomo.Gabrielli@arm.com 'color': termcap.Red + termcap.Reverse, 1268471SGiacomo.Gabrielli@arm.com 'shorthand': 'i'}, 1278471SGiacomo.Gabrielli@arm.com {'name': 'complete', 1288471SGiacomo.Gabrielli@arm.com 'color': termcap.Cyan + termcap.Reverse, 1298471SGiacomo.Gabrielli@arm.com 'shorthand': 'c'}, 1308471SGiacomo.Gabrielli@arm.com {'name': 'retire', 1318471SGiacomo.Gabrielli@arm.com 'color': termcap.Blue + termcap.Reverse, 1328471SGiacomo.Gabrielli@arm.com 'shorthand': 'r'}] 1338471SGiacomo.Gabrielli@arm.com # Print 1348471SGiacomo.Gabrielli@arm.com time_width = width * cycle_time 1358471SGiacomo.Gabrielli@arm.com base_tick = (inst['fetch'] / time_width) * time_width 1369188SDjordje.Kovacevic@arm.com # Timeline shorter then time_width is printed in compact form where 1379188SDjordje.Kovacevic@arm.com # the print continues at the start of the same line. 1389188SDjordje.Kovacevic@arm.com if ((inst['retire'] - inst['fetch']) < time_width): 1399188SDjordje.Kovacevic@arm.com num_lines = 1 # compact form 1409188SDjordje.Kovacevic@arm.com else: 1419188SDjordje.Kovacevic@arm.com num_lines = ((inst['retire'] - base_tick) / time_width) + 1 1429188SDjordje.Kovacevic@arm.com 1438471SGiacomo.Gabrielli@arm.com curr_color = termcap.Normal 1448471SGiacomo.Gabrielli@arm.com for i in range(num_lines): 1458471SGiacomo.Gabrielli@arm.com start_tick = base_tick + i * time_width 1468471SGiacomo.Gabrielli@arm.com end_tick = start_tick + time_width 1478471SGiacomo.Gabrielli@arm.com if num_lines == 1: # compact form 1488471SGiacomo.Gabrielli@arm.com end_tick += (inst['fetch'] - base_tick) 1498471SGiacomo.Gabrielli@arm.com events = [] 1508471SGiacomo.Gabrielli@arm.com for stage_idx in range(len(stages)): 1518471SGiacomo.Gabrielli@arm.com tick = inst[stages[stage_idx]['name']] 1528471SGiacomo.Gabrielli@arm.com if tick >= start_tick and tick < end_tick: 1538471SGiacomo.Gabrielli@arm.com events.append((tick % time_width, 1548471SGiacomo.Gabrielli@arm.com stages[stage_idx]['name'], 1558471SGiacomo.Gabrielli@arm.com stage_idx)) 1568471SGiacomo.Gabrielli@arm.com events.sort() 1578471SGiacomo.Gabrielli@arm.com outfile.write('[') 1588471SGiacomo.Gabrielli@arm.com pos = 0 1598471SGiacomo.Gabrielli@arm.com if num_lines == 1 and events[0][2] != 0: # event is not fetch 1608471SGiacomo.Gabrielli@arm.com curr_color = stages[events[0][2] - 1]['color'] 1618471SGiacomo.Gabrielli@arm.com for event in events: 1628471SGiacomo.Gabrielli@arm.com if (stages[event[2]]['name'] == 'dispatch' and 1638471SGiacomo.Gabrielli@arm.com inst['dispatch'] == inst['issue']): 1648471SGiacomo.Gabrielli@arm.com continue 1658471SGiacomo.Gabrielli@arm.com outfile.write(curr_color + '.' * ((event[0] / cycle_time) - pos)) 1668471SGiacomo.Gabrielli@arm.com outfile.write(stages[event[2]]['color'] + 1678471SGiacomo.Gabrielli@arm.com stages[event[2]]['shorthand']) 1688471SGiacomo.Gabrielli@arm.com if event[2] != len(stages) - 1: # event is not retire 1698471SGiacomo.Gabrielli@arm.com curr_color = stages[event[2]]['color'] 1708471SGiacomo.Gabrielli@arm.com else: 1718471SGiacomo.Gabrielli@arm.com curr_color = termcap.Normal 1728471SGiacomo.Gabrielli@arm.com pos = (event[0] / cycle_time) + 1 1738471SGiacomo.Gabrielli@arm.com outfile.write(curr_color + '.' * (width - pos) + termcap.Normal + 1748471SGiacomo.Gabrielli@arm.com ']-(' + str(base_tick + i * time_width).rjust(15) + ') ') 1758471SGiacomo.Gabrielli@arm.com if i == 0: 1768471SGiacomo.Gabrielli@arm.com outfile.write('%s.%s %s [%s]' % ( 1778471SGiacomo.Gabrielli@arm.com inst['pc'].rjust(10), 1788471SGiacomo.Gabrielli@arm.com inst['upc'], 1798471SGiacomo.Gabrielli@arm.com inst['disasm'].ljust(25), 1808471SGiacomo.Gabrielli@arm.com str(inst['sn']).rjust(15))) 1818471SGiacomo.Gabrielli@arm.com if timestamps: 1828471SGiacomo.Gabrielli@arm.com outfile.write(' f=%s, r=%s' % (inst['fetch'], inst['retire'])) 1838471SGiacomo.Gabrielli@arm.com outfile.write('\n') 1848471SGiacomo.Gabrielli@arm.com else: 1858471SGiacomo.Gabrielli@arm.com outfile.write('...'.center(12) + '\n') 1868471SGiacomo.Gabrielli@arm.com 1878471SGiacomo.Gabrielli@arm.com 1888471SGiacomo.Gabrielli@arm.comdef validate_range(my_range): 1898471SGiacomo.Gabrielli@arm.com my_range = [int(i) for i in my_range.split(':')] 1908471SGiacomo.Gabrielli@arm.com if (len(my_range) != 2 or 1918471SGiacomo.Gabrielli@arm.com my_range[0] < 0 or 1928471SGiacomo.Gabrielli@arm.com my_range[1] > 0 and my_range[0] >= my_range[1]): 1938471SGiacomo.Gabrielli@arm.com return None 1948471SGiacomo.Gabrielli@arm.com return my_range 1958471SGiacomo.Gabrielli@arm.com 1968471SGiacomo.Gabrielli@arm.com 1978471SGiacomo.Gabrielli@arm.comdef main(): 1988471SGiacomo.Gabrielli@arm.com # Parse options 1998471SGiacomo.Gabrielli@arm.com usage = ('%prog [OPTION]... TRACE_FILE') 2008471SGiacomo.Gabrielli@arm.com parser = optparse.OptionParser(usage=usage) 2018471SGiacomo.Gabrielli@arm.com parser.add_option( 2028471SGiacomo.Gabrielli@arm.com '-o', 2038471SGiacomo.Gabrielli@arm.com dest='outfile', 2048471SGiacomo.Gabrielli@arm.com default=os.path.join(os.getcwd(), 'o3-pipeview.out'), 2058471SGiacomo.Gabrielli@arm.com help="output file (default: '%default')") 2068471SGiacomo.Gabrielli@arm.com parser.add_option( 2078471SGiacomo.Gabrielli@arm.com '-t', 2088471SGiacomo.Gabrielli@arm.com dest='tick_range', 2098471SGiacomo.Gabrielli@arm.com default='0:-1', 2108471SGiacomo.Gabrielli@arm.com help="tick range (default: '%default'; -1 == inf.)") 2118471SGiacomo.Gabrielli@arm.com parser.add_option( 2128471SGiacomo.Gabrielli@arm.com '-i', 2138471SGiacomo.Gabrielli@arm.com dest='inst_range', 2148471SGiacomo.Gabrielli@arm.com default='0:-1', 2158471SGiacomo.Gabrielli@arm.com help="instruction range (default: '%default'; -1 == inf.)") 2168471SGiacomo.Gabrielli@arm.com parser.add_option( 2178471SGiacomo.Gabrielli@arm.com '-w', 2188471SGiacomo.Gabrielli@arm.com dest='width', 2198471SGiacomo.Gabrielli@arm.com type='int', default=80, 2208471SGiacomo.Gabrielli@arm.com help="timeline width (default: '%default')") 2218471SGiacomo.Gabrielli@arm.com parser.add_option( 2228471SGiacomo.Gabrielli@arm.com '--color', 2238471SGiacomo.Gabrielli@arm.com action='store_true', default=False, 2248471SGiacomo.Gabrielli@arm.com help="enable colored output (default: '%default')") 2258471SGiacomo.Gabrielli@arm.com parser.add_option( 2268471SGiacomo.Gabrielli@arm.com '-c', '--cycle-time', 2278471SGiacomo.Gabrielli@arm.com type='int', default=1000, 2288471SGiacomo.Gabrielli@arm.com help="CPU cycle time in ticks (default: '%default')") 2298471SGiacomo.Gabrielli@arm.com parser.add_option( 2308471SGiacomo.Gabrielli@arm.com '--timestamps', 2318471SGiacomo.Gabrielli@arm.com action='store_true', default=False, 2328471SGiacomo.Gabrielli@arm.com help="print fetch and retire timestamps (default: '%default')") 2338471SGiacomo.Gabrielli@arm.com (options, args) = parser.parse_args() 2348471SGiacomo.Gabrielli@arm.com if len(args) != 1: 2358471SGiacomo.Gabrielli@arm.com parser.error('incorrect number of arguments') 2368471SGiacomo.Gabrielli@arm.com sys.exit(1) 2378471SGiacomo.Gabrielli@arm.com tick_range = validate_range(options.tick_range) 2388471SGiacomo.Gabrielli@arm.com if not tick_range: 2398471SGiacomo.Gabrielli@arm.com parser.error('invalid range') 2408471SGiacomo.Gabrielli@arm.com sys.exit(1) 2418471SGiacomo.Gabrielli@arm.com inst_range = validate_range(options.inst_range) 2428471SGiacomo.Gabrielli@arm.com if not inst_range: 2438471SGiacomo.Gabrielli@arm.com parser.error('invalid range') 2448471SGiacomo.Gabrielli@arm.com sys.exit(1) 2458471SGiacomo.Gabrielli@arm.com # Process trace 2468471SGiacomo.Gabrielli@arm.com print 'Processing trace... ', 2478471SGiacomo.Gabrielli@arm.com with open(args[0], 'r') as trace: 2488471SGiacomo.Gabrielli@arm.com with open(options.outfile, 'w') as out: 2498471SGiacomo.Gabrielli@arm.com process_trace(trace, out, options.cycle_time, options.width, 2508471SGiacomo.Gabrielli@arm.com options.color, options.timestamps, 2518471SGiacomo.Gabrielli@arm.com *(tick_range + inst_range)) 2528471SGiacomo.Gabrielli@arm.com print 'done!' 2538471SGiacomo.Gabrielli@arm.com 2548471SGiacomo.Gabrielli@arm.com 2558471SGiacomo.Gabrielli@arm.comif __name__ == '__main__': 2568471SGiacomo.Gabrielli@arm.com sys.path.append(os.path.join( 2578471SGiacomo.Gabrielli@arm.com os.path.dirname(os.path.abspath(__file__)), 2588471SGiacomo.Gabrielli@arm.com '..', 'src', 'python')) 2598471SGiacomo.Gabrielli@arm.com main() 260