m5stats2streamline.py revision 9935
19935Sdam.sunwoo@arm.com#!/usr/bin/env python 29935Sdam.sunwoo@arm.com 39935Sdam.sunwoo@arm.com# Copyright (c) 2012 ARM Limited 49935Sdam.sunwoo@arm.com# All rights reserved 59935Sdam.sunwoo@arm.com# 69935Sdam.sunwoo@arm.com# The license below extends only to copyright in the software and shall 79935Sdam.sunwoo@arm.com# not be construed as granting a license to any other intellectual 89935Sdam.sunwoo@arm.com# property including but not limited to intellectual property relating 99935Sdam.sunwoo@arm.com# to a hardware implementation of the functionality of the software 109935Sdam.sunwoo@arm.com# licensed hereunder. You may use the software subject to the license 119935Sdam.sunwoo@arm.com# terms below provided that you ensure that this notice is replicated 129935Sdam.sunwoo@arm.com# unmodified and in its entirety in all distributions of the software, 139935Sdam.sunwoo@arm.com# modified or unmodified, in source code or in binary form. 149935Sdam.sunwoo@arm.com# 159935Sdam.sunwoo@arm.com# Redistribution and use in source and binary forms, with or without 169935Sdam.sunwoo@arm.com# modification, are permitted provided that the following conditions are 179935Sdam.sunwoo@arm.com# met: redistributions of source code must retain the above copyright 189935Sdam.sunwoo@arm.com# notice, this list of conditions and the following disclaimer; 199935Sdam.sunwoo@arm.com# redistributions in binary form must reproduce the above copyright 209935Sdam.sunwoo@arm.com# notice, this list of conditions and the following disclaimer in the 219935Sdam.sunwoo@arm.com# documentation and/or other materials provided with the distribution; 229935Sdam.sunwoo@arm.com# neither the name of the copyright holders nor the names of its 239935Sdam.sunwoo@arm.com# contributors may be used to endorse or promote products derived from 249935Sdam.sunwoo@arm.com# this software without specific prior written permission. 259935Sdam.sunwoo@arm.com# 269935Sdam.sunwoo@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 279935Sdam.sunwoo@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 289935Sdam.sunwoo@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 299935Sdam.sunwoo@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 309935Sdam.sunwoo@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 319935Sdam.sunwoo@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 329935Sdam.sunwoo@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 339935Sdam.sunwoo@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 349935Sdam.sunwoo@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 359935Sdam.sunwoo@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 369935Sdam.sunwoo@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 379935Sdam.sunwoo@arm.com# 389935Sdam.sunwoo@arm.com# Author: Dam Sunwoo 399935Sdam.sunwoo@arm.com# 409935Sdam.sunwoo@arm.com 419935Sdam.sunwoo@arm.com# This script converts gem5 output to ARM DS-5 Streamline .apc project file 429935Sdam.sunwoo@arm.com# (Requires the gem5 runs to be run with ContextSwitchStatsDump enabled and 439935Sdam.sunwoo@arm.com# some patches applied to target Linux kernel.) 449935Sdam.sunwoo@arm.com# Visit http://www.gem5.org/Streamline for more details. 459935Sdam.sunwoo@arm.com# 469935Sdam.sunwoo@arm.com# Usage: 479935Sdam.sunwoo@arm.com# m5stats2streamline.py <stat_config.ini> <gem5 run folder> <dest .apc folder> 489935Sdam.sunwoo@arm.com# 499935Sdam.sunwoo@arm.com# <stat_config.ini>: .ini file that describes which stats to be included 509935Sdam.sunwoo@arm.com# in conversion. Sample .ini files can be found in 519935Sdam.sunwoo@arm.com# util/streamline. 529935Sdam.sunwoo@arm.com# NOTE: this is NOT the gem5 config.ini file. 539935Sdam.sunwoo@arm.com# 549935Sdam.sunwoo@arm.com# <gem5 run folder>: Path to gem5 run folder (must contain config.ini, 559935Sdam.sunwoo@arm.com# stats.txt[.gz], and system.tasks.txt.) 569935Sdam.sunwoo@arm.com# 579935Sdam.sunwoo@arm.com# <dest .apc folder>: Destination .apc folder path 589935Sdam.sunwoo@arm.com# 599935Sdam.sunwoo@arm.com# APC project generation based on Gator v12 (DS-5 v5.13) 609935Sdam.sunwoo@arm.com# Subsequent versions should be backward compatible 619935Sdam.sunwoo@arm.com 629935Sdam.sunwoo@arm.comimport re, sys, os 639935Sdam.sunwoo@arm.comfrom ConfigParser import ConfigParser 649935Sdam.sunwoo@arm.comimport gzip 659935Sdam.sunwoo@arm.comimport xml.etree.ElementTree as ET 669935Sdam.sunwoo@arm.comimport xml.dom.minidom as minidom 679935Sdam.sunwoo@arm.comimport shutil 689935Sdam.sunwoo@arm.comimport zlib 699935Sdam.sunwoo@arm.com 709935Sdam.sunwoo@arm.comimport argparse 719935Sdam.sunwoo@arm.com 729935Sdam.sunwoo@arm.comparser = argparse.ArgumentParser( 739935Sdam.sunwoo@arm.com formatter_class=argparse.RawDescriptionHelpFormatter, 749935Sdam.sunwoo@arm.com description=""" 759935Sdam.sunwoo@arm.com Converts gem5 runs to ARM DS-5 Streamline .apc project file. 769935Sdam.sunwoo@arm.com (NOTE: Requires gem5 runs to be run with ContextSwitchStatsDump 779935Sdam.sunwoo@arm.com enabled and some patches applied to the target Linux kernel.) 789935Sdam.sunwoo@arm.com 799935Sdam.sunwoo@arm.com Visit http://www.gem5.org/Streamline for more details. 809935Sdam.sunwoo@arm.com 819935Sdam.sunwoo@arm.com APC project generation based on Gator v12 (DS-5 v5.13) 829935Sdam.sunwoo@arm.com Subsequent versions should be backward compatible 839935Sdam.sunwoo@arm.com """) 849935Sdam.sunwoo@arm.com 859935Sdam.sunwoo@arm.comparser.add_argument("stat_config_file", metavar="<stat_config.ini>", 869935Sdam.sunwoo@arm.com help=".ini file that describes which stats to be included \ 879935Sdam.sunwoo@arm.com in conversion. Sample .ini files can be found in \ 889935Sdam.sunwoo@arm.com util/streamline. NOTE: this is NOT the gem5 config.ini \ 899935Sdam.sunwoo@arm.com file.") 909935Sdam.sunwoo@arm.com 919935Sdam.sunwoo@arm.comparser.add_argument("input_path", metavar="<gem5 run folder>", 929935Sdam.sunwoo@arm.com help="Path to gem5 run folder (must contain config.ini, \ 939935Sdam.sunwoo@arm.com stats.txt[.gz], and system.tasks.txt.)") 949935Sdam.sunwoo@arm.com 959935Sdam.sunwoo@arm.comparser.add_argument("output_path", metavar="<dest .apc folder>", 969935Sdam.sunwoo@arm.com help="Destination .apc folder path") 979935Sdam.sunwoo@arm.com 989935Sdam.sunwoo@arm.comparser.add_argument("--num-events", action="store", type=int, 999935Sdam.sunwoo@arm.com default=1000000, 1009935Sdam.sunwoo@arm.com help="Maximum number of scheduling (context switch) \ 1019935Sdam.sunwoo@arm.com events to be processed. Set to truncate early. \ 1029935Sdam.sunwoo@arm.com Default=1000000") 1039935Sdam.sunwoo@arm.com 1049935Sdam.sunwoo@arm.comparser.add_argument("--gzipped-bmp-not-supported", action="store_true", 1059935Sdam.sunwoo@arm.com help="Do not use gzipped .bmp files for visual annotations. \ 1069935Sdam.sunwoo@arm.com This option is only required when using Streamline versions \ 1079935Sdam.sunwoo@arm.com older than 5.14") 1089935Sdam.sunwoo@arm.com 1099935Sdam.sunwoo@arm.comparser.add_argument("--verbose", action="store_true", 1109935Sdam.sunwoo@arm.com help="Enable verbose output") 1119935Sdam.sunwoo@arm.com 1129935Sdam.sunwoo@arm.comargs = parser.parse_args() 1139935Sdam.sunwoo@arm.com 1149935Sdam.sunwoo@arm.comif not re.match("(.*)\.apc", args.output_path): 1159935Sdam.sunwoo@arm.com print "ERROR: <dest .apc folder> should end with '.apc'!" 1169935Sdam.sunwoo@arm.com sys.exit(1) 1179935Sdam.sunwoo@arm.com 1189935Sdam.sunwoo@arm.com# gzipped BMP files for visual annotation is supported in Streamline 5.14. 1199935Sdam.sunwoo@arm.com# Setting this to True will significantly compress the .apc binary file that 1209935Sdam.sunwoo@arm.com# includes frame buffer snapshots. 1219935Sdam.sunwoo@arm.comgzipped_bmp_supported = not args.gzipped_bmp_not_supported 1229935Sdam.sunwoo@arm.com 1239935Sdam.sunwoo@arm.comticks_in_ns = -1 1249935Sdam.sunwoo@arm.com 1259935Sdam.sunwoo@arm.com# Default max # of events. Increase this for longer runs. 1269935Sdam.sunwoo@arm.comnum_events = args.num_events 1279935Sdam.sunwoo@arm.com 1289935Sdam.sunwoo@arm.comstart_tick = -1 1299935Sdam.sunwoo@arm.comend_tick = -1 1309935Sdam.sunwoo@arm.com 1319935Sdam.sunwoo@arm.com# Parse gem5 config.ini file to determine some system configurations. 1329935Sdam.sunwoo@arm.com# Number of CPUs, L2s, etc. 1339935Sdam.sunwoo@arm.comdef parseConfig(config_file): 1349935Sdam.sunwoo@arm.com global num_cpus, num_l2 1359935Sdam.sunwoo@arm.com 1369935Sdam.sunwoo@arm.com print "\n===============================" 1379935Sdam.sunwoo@arm.com print "Parsing gem5 config.ini file..." 1389935Sdam.sunwoo@arm.com print config_file 1399935Sdam.sunwoo@arm.com print "===============================\n" 1409935Sdam.sunwoo@arm.com config = ConfigParser() 1419935Sdam.sunwoo@arm.com if not config.read(config_file): 1429935Sdam.sunwoo@arm.com print "ERROR: config file '", config_file, "' not found" 1439935Sdam.sunwoo@arm.com sys.exit(1) 1449935Sdam.sunwoo@arm.com 1459935Sdam.sunwoo@arm.com if config.has_section("system.cpu"): 1469935Sdam.sunwoo@arm.com num_cpus = 1 1479935Sdam.sunwoo@arm.com else: 1489935Sdam.sunwoo@arm.com num_cpus = 0 1499935Sdam.sunwoo@arm.com while config.has_section("system.cpu" + str(num_cpus)): 1509935Sdam.sunwoo@arm.com num_cpus += 1 1519935Sdam.sunwoo@arm.com 1529935Sdam.sunwoo@arm.com if config.has_section("system.l2"): 1539935Sdam.sunwoo@arm.com num_l2 = 1 1549935Sdam.sunwoo@arm.com else: 1559935Sdam.sunwoo@arm.com num_l2 = 0 1569935Sdam.sunwoo@arm.com while config.has_section("system.l2" + str(num_l2)): 1579935Sdam.sunwoo@arm.com num_l2 += 1 1589935Sdam.sunwoo@arm.com 1599935Sdam.sunwoo@arm.com print "Num CPUs:", num_cpus 1609935Sdam.sunwoo@arm.com print "Num L2s:", num_l2 1619935Sdam.sunwoo@arm.com print "" 1629935Sdam.sunwoo@arm.com 1639935Sdam.sunwoo@arm.com return (num_cpus, num_l2) 1649935Sdam.sunwoo@arm.com 1659935Sdam.sunwoo@arm.com 1669935Sdam.sunwoo@arm.comprocess_dict = {} 1679935Sdam.sunwoo@arm.comthread_dict = {} 1689935Sdam.sunwoo@arm.com 1699935Sdam.sunwoo@arm.comprocess_list = [] 1709935Sdam.sunwoo@arm.com 1719935Sdam.sunwoo@arm.comidle_uid = -1 1729935Sdam.sunwoo@arm.comkernel_uid = -1 1739935Sdam.sunwoo@arm.com 1749935Sdam.sunwoo@arm.comclass Task(object): 1759935Sdam.sunwoo@arm.com def __init__(self, uid, pid, tgid, task_name, is_process, tick): 1769935Sdam.sunwoo@arm.com if pid == 0: # Idle 1779935Sdam.sunwoo@arm.com self.uid = 0 1789935Sdam.sunwoo@arm.com elif pid == -1: # Kernel 1799935Sdam.sunwoo@arm.com self.uid = 0 1809935Sdam.sunwoo@arm.com else: 1819935Sdam.sunwoo@arm.com self.uid = uid 1829935Sdam.sunwoo@arm.com self.pid = pid 1839935Sdam.sunwoo@arm.com self.tgid = tgid 1849935Sdam.sunwoo@arm.com self.is_process = is_process 1859935Sdam.sunwoo@arm.com self.task_name = task_name 1869935Sdam.sunwoo@arm.com self.children = [] 1879935Sdam.sunwoo@arm.com self.tick = tick # time this task first appeared 1889935Sdam.sunwoo@arm.com 1899935Sdam.sunwoo@arm.comclass Event(object): 1909935Sdam.sunwoo@arm.com def __init__(self, tick, task): 1919935Sdam.sunwoo@arm.com self.tick = tick 1929935Sdam.sunwoo@arm.com self.task = task 1939935Sdam.sunwoo@arm.com 1949935Sdam.sunwoo@arm.com############################################################ 1959935Sdam.sunwoo@arm.com# Types used in APC Protocol 1969935Sdam.sunwoo@arm.com# - packed32, packed64 1979935Sdam.sunwoo@arm.com# - int32 1989935Sdam.sunwoo@arm.com# - string 1999935Sdam.sunwoo@arm.com############################################################ 2009935Sdam.sunwoo@arm.com 2019935Sdam.sunwoo@arm.com# variable length packed 4-byte signed value 2029935Sdam.sunwoo@arm.comdef packed32(x): 2039935Sdam.sunwoo@arm.com ret = [] 2049935Sdam.sunwoo@arm.com if ((x & 0xffffff80) == 0): 2059935Sdam.sunwoo@arm.com ret.append(x & 0x7f) 2069935Sdam.sunwoo@arm.com elif ((x & 0xffffc000) == 0): 2079935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2089935Sdam.sunwoo@arm.com ret.append((x >> 7) & 0x7f) 2099935Sdam.sunwoo@arm.com elif ((x & 0xffe00000) == 0): 2109935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2119935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2129935Sdam.sunwoo@arm.com ret.append((x >> 14) & 0x7f) 2139935Sdam.sunwoo@arm.com elif ((x & 0xf0000000) == 0): 2149935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2159935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2169935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2179935Sdam.sunwoo@arm.com ret.append((x >> 21) & 0x7f) 2189935Sdam.sunwoo@arm.com else: 2199935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2209935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2219935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2229935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2239935Sdam.sunwoo@arm.com ret.append((x >> 28) & 0x0f) 2249935Sdam.sunwoo@arm.com return ret 2259935Sdam.sunwoo@arm.com 2269935Sdam.sunwoo@arm.com# variable length packed 8-byte signed value 2279935Sdam.sunwoo@arm.comdef packed64(x): 2289935Sdam.sunwoo@arm.com ret = [] 2299935Sdam.sunwoo@arm.com if ((x & 0xffffffffffffff80) == 0): 2309935Sdam.sunwoo@arm.com ret.append(x & 0x7f) 2319935Sdam.sunwoo@arm.com elif ((x & 0xffffffffffffc000) == 0): 2329935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2339935Sdam.sunwoo@arm.com ret.append((x >> 7) & 0x7f) 2349935Sdam.sunwoo@arm.com elif ((x & 0xffffffffffe00000) == 0): 2359935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2369935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2379935Sdam.sunwoo@arm.com ret.append((x >> 14) & 0x7f) 2389935Sdam.sunwoo@arm.com elif ((x & 0xfffffffff0000000) == 0): 2399935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2409935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2419935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2429935Sdam.sunwoo@arm.com ret.append((x >> 21) & 0x7f) 2439935Sdam.sunwoo@arm.com elif ((x & 0xfffffff800000000) == 0): 2449935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2459935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2469935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2479935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2489935Sdam.sunwoo@arm.com ret.append((x >> 28) & 0x7f) 2499935Sdam.sunwoo@arm.com elif ((x & 0xfffffc0000000000) == 0): 2509935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2519935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2529935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2539935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2549935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2559935Sdam.sunwoo@arm.com ret.append((x >> 35) & 0x7f) 2569935Sdam.sunwoo@arm.com elif ((x & 0xfffe000000000000) == 0): 2579935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2589935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2599935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2609935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2619935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2629935Sdam.sunwoo@arm.com ret.append(((x >> 35) | 0x80) & 0xff) 2639935Sdam.sunwoo@arm.com ret.append((x >> 42) & 0x7f) 2649935Sdam.sunwoo@arm.com elif ((x & 0xff00000000000000) == 0): 2659935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2669935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2679935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2689935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2699935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2709935Sdam.sunwoo@arm.com ret.append(((x >> 35) | 0x80) & 0xff) 2719935Sdam.sunwoo@arm.com ret.append(((x >> 42) | 0x80) & 0xff) 2729935Sdam.sunwoo@arm.com ret.append((x >> 49) & 0x7f) 2739935Sdam.sunwoo@arm.com elif ((x & 0x8000000000000000) == 0): 2749935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2759935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2769935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2779935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2789935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2799935Sdam.sunwoo@arm.com ret.append(((x >> 35) | 0x80) & 0xff) 2809935Sdam.sunwoo@arm.com ret.append(((x >> 42) | 0x80) & 0xff) 2819935Sdam.sunwoo@arm.com ret.append(((x >> 49) | 0x80) & 0xff) 2829935Sdam.sunwoo@arm.com ret.append((x >> 56) & 0x7f) 2839935Sdam.sunwoo@arm.com else: 2849935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2859935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2869935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2879935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2889935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2899935Sdam.sunwoo@arm.com ret.append(((x >> 35) | 0x80) & 0xff) 2909935Sdam.sunwoo@arm.com ret.append(((x >> 42) | 0x80) & 0xff) 2919935Sdam.sunwoo@arm.com ret.append(((x >> 49) | 0x80) & 0xff) 2929935Sdam.sunwoo@arm.com ret.append(((x >> 56) | 0x80) & 0xff) 2939935Sdam.sunwoo@arm.com ret.append((x >> 63) & 0x7f) 2949935Sdam.sunwoo@arm.com return ret 2959935Sdam.sunwoo@arm.com 2969935Sdam.sunwoo@arm.com# 4-byte signed little endian 2979935Sdam.sunwoo@arm.comdef int32(x): 2989935Sdam.sunwoo@arm.com ret = [] 2999935Sdam.sunwoo@arm.com ret.append(x & 0xff) 3009935Sdam.sunwoo@arm.com ret.append((x >> 8) & 0xff) 3019935Sdam.sunwoo@arm.com ret.append((x >> 16) & 0xff) 3029935Sdam.sunwoo@arm.com ret.append((x >> 24) & 0xff) 3039935Sdam.sunwoo@arm.com return ret 3049935Sdam.sunwoo@arm.com 3059935Sdam.sunwoo@arm.com# 2-byte signed little endian 3069935Sdam.sunwoo@arm.comdef int16(x): 3079935Sdam.sunwoo@arm.com ret = [] 3089935Sdam.sunwoo@arm.com ret.append(x & 0xff) 3099935Sdam.sunwoo@arm.com ret.append((x >> 8) & 0xff) 3109935Sdam.sunwoo@arm.com return ret 3119935Sdam.sunwoo@arm.com 3129935Sdam.sunwoo@arm.com# a packed32 length followed by the specified number of characters 3139935Sdam.sunwoo@arm.comdef stringList(x): 3149935Sdam.sunwoo@arm.com ret = [] 3159935Sdam.sunwoo@arm.com ret += packed32(len(x)) 3169935Sdam.sunwoo@arm.com for i in x: 3179935Sdam.sunwoo@arm.com ret.append(i) 3189935Sdam.sunwoo@arm.com return ret 3199935Sdam.sunwoo@arm.com 3209935Sdam.sunwoo@arm.comdef utf8StringList(x): 3219935Sdam.sunwoo@arm.com ret = [] 3229935Sdam.sunwoo@arm.com for i in x: 3239935Sdam.sunwoo@arm.com ret.append(ord(i)) 3249935Sdam.sunwoo@arm.com return ret 3259935Sdam.sunwoo@arm.com 3269935Sdam.sunwoo@arm.com# packed64 time value in nanoseconds relative to the uptime from the 3279935Sdam.sunwoo@arm.com# Summary message. 3289935Sdam.sunwoo@arm.comdef timestampList(x): 3299935Sdam.sunwoo@arm.com ret = packed64(x) 3309935Sdam.sunwoo@arm.com return ret 3319935Sdam.sunwoo@arm.com 3329935Sdam.sunwoo@arm.com 3339935Sdam.sunwoo@arm.com############################################################ 3349935Sdam.sunwoo@arm.com# Write binary 3359935Sdam.sunwoo@arm.com############################################################ 3369935Sdam.sunwoo@arm.com 3379935Sdam.sunwoo@arm.comdef writeBinary(outfile, binary_list): 3389935Sdam.sunwoo@arm.com for i in binary_list: 3399935Sdam.sunwoo@arm.com outfile.write("%c" % i) 3409935Sdam.sunwoo@arm.com 3419935Sdam.sunwoo@arm.com############################################################ 3429935Sdam.sunwoo@arm.com# APC Protocol Frame Types 3439935Sdam.sunwoo@arm.com############################################################ 3449935Sdam.sunwoo@arm.com 3459935Sdam.sunwoo@arm.comdef addFrameHeader(frame_type, body, core): 3469935Sdam.sunwoo@arm.com ret = [] 3479935Sdam.sunwoo@arm.com 3489935Sdam.sunwoo@arm.com if frame_type == "Summary": 3499935Sdam.sunwoo@arm.com code = 1 3509935Sdam.sunwoo@arm.com elif frame_type == "Backtrace": 3519935Sdam.sunwoo@arm.com code = 2 3529935Sdam.sunwoo@arm.com elif frame_type == "Name": 3539935Sdam.sunwoo@arm.com code = 3 3549935Sdam.sunwoo@arm.com elif frame_type == "Counter": 3559935Sdam.sunwoo@arm.com code = 4 3569935Sdam.sunwoo@arm.com elif frame_type == "Block Counter": 3579935Sdam.sunwoo@arm.com code = 5 3589935Sdam.sunwoo@arm.com elif frame_type == "Annotate": 3599935Sdam.sunwoo@arm.com code = 6 3609935Sdam.sunwoo@arm.com elif frame_type == "Sched Trace": 3619935Sdam.sunwoo@arm.com code = 7 3629935Sdam.sunwoo@arm.com elif frame_type == "GPU Trace": 3639935Sdam.sunwoo@arm.com code = 8 3649935Sdam.sunwoo@arm.com elif frame_type == "Idle": 3659935Sdam.sunwoo@arm.com code = 9 3669935Sdam.sunwoo@arm.com else: 3679935Sdam.sunwoo@arm.com print "ERROR: Unknown frame type:", frame_type 3689935Sdam.sunwoo@arm.com sys.exit(1) 3699935Sdam.sunwoo@arm.com 3709935Sdam.sunwoo@arm.com packed_code = packed32(code) 3719935Sdam.sunwoo@arm.com 3729935Sdam.sunwoo@arm.com packed_core = packed32(core) 3739935Sdam.sunwoo@arm.com 3749935Sdam.sunwoo@arm.com length = int32(len(packed_code) + len(packed_core) + len(body)) 3759935Sdam.sunwoo@arm.com 3769935Sdam.sunwoo@arm.com ret = length + packed_code + packed_core + body 3779935Sdam.sunwoo@arm.com return ret 3789935Sdam.sunwoo@arm.com 3799935Sdam.sunwoo@arm.com 3809935Sdam.sunwoo@arm.com# Summary frame 3819935Sdam.sunwoo@arm.com# - timestamp: packed64 3829935Sdam.sunwoo@arm.com# - uptime: packed64 3839935Sdam.sunwoo@arm.comdef summaryFrame(timestamp, uptime): 3849935Sdam.sunwoo@arm.com frame_type = "Summary" 3859935Sdam.sunwoo@arm.com body = packed64(timestamp) + packed64(uptime) 3869935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 3879935Sdam.sunwoo@arm.com return ret 3889935Sdam.sunwoo@arm.com 3899935Sdam.sunwoo@arm.com# Backtrace frame 3909935Sdam.sunwoo@arm.com# - not implemented yet 3919935Sdam.sunwoo@arm.comdef backtraceFrame(): 3929935Sdam.sunwoo@arm.com pass 3939935Sdam.sunwoo@arm.com 3949935Sdam.sunwoo@arm.com# Cookie name message 3959935Sdam.sunwoo@arm.com# - cookie: packed32 3969935Sdam.sunwoo@arm.com# - name: string 3979935Sdam.sunwoo@arm.comdef cookieNameFrame(cookie, name): 3989935Sdam.sunwoo@arm.com frame_type = "Name" 3999935Sdam.sunwoo@arm.com packed_code = packed32(1) 4009935Sdam.sunwoo@arm.com body = packed_code + packed32(cookie) + stringList(name) 4019935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 4029935Sdam.sunwoo@arm.com return ret 4039935Sdam.sunwoo@arm.com 4049935Sdam.sunwoo@arm.com# Thread name message 4059935Sdam.sunwoo@arm.com# - timestamp: timestamp 4069935Sdam.sunwoo@arm.com# - thread id: packed32 4079935Sdam.sunwoo@arm.com# - name: string 4089935Sdam.sunwoo@arm.comdef threadNameFrame(timestamp, thread_id, name): 4099935Sdam.sunwoo@arm.com frame_type = "Name" 4109935Sdam.sunwoo@arm.com packed_code = packed32(2) 4119935Sdam.sunwoo@arm.com body = packed_code + timestampList(timestamp) + \ 4129935Sdam.sunwoo@arm.com packed32(thread_id) + stringList(name) 4139935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 4149935Sdam.sunwoo@arm.com return ret 4159935Sdam.sunwoo@arm.com 4169935Sdam.sunwoo@arm.com# Core name message 4179935Sdam.sunwoo@arm.com# - name: string 4189935Sdam.sunwoo@arm.comdef coreNameFrame(name): 4199935Sdam.sunwoo@arm.com frame_type = "Name" 4209935Sdam.sunwoo@arm.com packed_code = packed32(3) 4219935Sdam.sunwoo@arm.com body = packed_code + stringList(name) 4229935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 4239935Sdam.sunwoo@arm.com return ret 4249935Sdam.sunwoo@arm.com 4259935Sdam.sunwoo@arm.com# Counter frame message 4269935Sdam.sunwoo@arm.com# - timestamp: timestamp 4279935Sdam.sunwoo@arm.com# - core: packed32 4289935Sdam.sunwoo@arm.com# - key: packed32 4299935Sdam.sunwoo@arm.com# - value: packed64 4309935Sdam.sunwoo@arm.comdef counterFrame(timestamp, core, key, value): 4319935Sdam.sunwoo@arm.com frame_type = "Counter" 4329935Sdam.sunwoo@arm.com body = timestampList(timestamp) + packed32(core) + packed32(key) + \ 4339935Sdam.sunwoo@arm.com packed64(value) 4349935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4359935Sdam.sunwoo@arm.com return ret 4369935Sdam.sunwoo@arm.com 4379935Sdam.sunwoo@arm.com# Block Counter frame message 4389935Sdam.sunwoo@arm.com# - key: packed32 4399935Sdam.sunwoo@arm.com# - value: packed64 4409935Sdam.sunwoo@arm.comdef blockCounterFrame(core, key, value): 4419935Sdam.sunwoo@arm.com frame_type = "Block Counter" 4429935Sdam.sunwoo@arm.com body = packed32(key) + packed64(value) 4439935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4449935Sdam.sunwoo@arm.com return ret 4459935Sdam.sunwoo@arm.com 4469935Sdam.sunwoo@arm.com# Annotate frame messages 4479935Sdam.sunwoo@arm.com# - core: packed32 4489935Sdam.sunwoo@arm.com# - tid: packed32 4499935Sdam.sunwoo@arm.com# - timestamp: timestamp 4509935Sdam.sunwoo@arm.com# - size: packed32 4519935Sdam.sunwoo@arm.com# - body 4529935Sdam.sunwoo@arm.comdef annotateFrame(core, tid, timestamp, size, userspace_body): 4539935Sdam.sunwoo@arm.com frame_type = "Annotate" 4549935Sdam.sunwoo@arm.com body = packed32(core) + packed32(tid) + timestampList(timestamp) + \ 4559935Sdam.sunwoo@arm.com packed32(size) + userspace_body 4569935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4579935Sdam.sunwoo@arm.com return ret 4589935Sdam.sunwoo@arm.com 4599935Sdam.sunwoo@arm.com# Scheduler Trace frame messages 4609935Sdam.sunwoo@arm.com# Sched Switch 4619935Sdam.sunwoo@arm.com# - Code: 1 4629935Sdam.sunwoo@arm.com# - timestamp: timestamp 4639935Sdam.sunwoo@arm.com# - pid: packed32 4649935Sdam.sunwoo@arm.com# - tid: packed32 4659935Sdam.sunwoo@arm.com# - cookie: packed32 4669935Sdam.sunwoo@arm.com# - state: packed32 4679935Sdam.sunwoo@arm.comdef schedSwitchFrame(core, timestamp, pid, tid, cookie, state): 4689935Sdam.sunwoo@arm.com frame_type = "Sched Trace" 4699935Sdam.sunwoo@arm.com body = packed32(1) + timestampList(timestamp) + packed32(pid) + \ 4709935Sdam.sunwoo@arm.com packed32(tid) + packed32(cookie) + packed32(state) 4719935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4729935Sdam.sunwoo@arm.com return ret 4739935Sdam.sunwoo@arm.com 4749935Sdam.sunwoo@arm.com# Sched Thread Exit 4759935Sdam.sunwoo@arm.com# - Code: 2 4769935Sdam.sunwoo@arm.com# - timestamp: timestamp 4779935Sdam.sunwoo@arm.com# - tid: packed32 4789935Sdam.sunwoo@arm.comdef schedThreadExitFrame(core, timestamp, pid, tid, cookie, state): 4799935Sdam.sunwoo@arm.com frame_type = "Sched Trace" 4809935Sdam.sunwoo@arm.com body = packed32(2) + timestampList(timestamp) + packed32(tid) 4819935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4829935Sdam.sunwoo@arm.com return ret 4839935Sdam.sunwoo@arm.com 4849935Sdam.sunwoo@arm.com# GPU Trace frame messages 4859935Sdam.sunwoo@arm.com# - Not implemented yet 4869935Sdam.sunwoo@arm.comdef gpuTraceFrame(): 4879935Sdam.sunwoo@arm.com pass 4889935Sdam.sunwoo@arm.com 4899935Sdam.sunwoo@arm.com# Idle frame messages 4909935Sdam.sunwoo@arm.com# Enter Idle 4919935Sdam.sunwoo@arm.com# - code: 1 4929935Sdam.sunwoo@arm.com# - timestamp: timestamp 4939935Sdam.sunwoo@arm.com# - core: packed32 4949935Sdam.sunwoo@arm.comdef enterIdleFrame(timestamp, core): 4959935Sdam.sunwoo@arm.com frame_type = "Idle" 4969935Sdam.sunwoo@arm.com body = packed32(1) + timestampList(timestamp) + packed32(core) 4979935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4989935Sdam.sunwoo@arm.com return ret 4999935Sdam.sunwoo@arm.com 5009935Sdam.sunwoo@arm.com# Exit Idle 5019935Sdam.sunwoo@arm.com# - code: 2 5029935Sdam.sunwoo@arm.com# - timestamp: timestamp 5039935Sdam.sunwoo@arm.com# - core: packed32 5049935Sdam.sunwoo@arm.comdef exitIdleFrame(timestamp, core): 5059935Sdam.sunwoo@arm.com frame_type = "Idle" 5069935Sdam.sunwoo@arm.com body = packed32(2) + timestampList(timestamp) + packed32(core) 5079935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 5089935Sdam.sunwoo@arm.com return ret 5099935Sdam.sunwoo@arm.com 5109935Sdam.sunwoo@arm.com 5119935Sdam.sunwoo@arm.com#################################################################### 5129935Sdam.sunwoo@arm.comdef parseProcessInfo(task_file): 5139935Sdam.sunwoo@arm.com print "\n===============================" 5149935Sdam.sunwoo@arm.com print "Parsing Task file..." 5159935Sdam.sunwoo@arm.com print task_file 5169935Sdam.sunwoo@arm.com print "===============================\n" 5179935Sdam.sunwoo@arm.com 5189935Sdam.sunwoo@arm.com global start_tick, end_tick, num_cpus 5199935Sdam.sunwoo@arm.com global process_dict, thread_dict, process_list 5209935Sdam.sunwoo@arm.com global event_list, unified_event_list 5219935Sdam.sunwoo@arm.com global idle_uid, kernel_uid 5229935Sdam.sunwoo@arm.com 5239935Sdam.sunwoo@arm.com event_list = [] 5249935Sdam.sunwoo@arm.com unified_event_list = [] 5259935Sdam.sunwoo@arm.com for cpu in range(num_cpus): 5269935Sdam.sunwoo@arm.com event_list.append([]) 5279935Sdam.sunwoo@arm.com 5289935Sdam.sunwoo@arm.com uid = 1 # uid 0 is reserved for idle 5299935Sdam.sunwoo@arm.com 5309935Sdam.sunwoo@arm.com # Dummy Tasks for frame buffers and system diagrams 5319935Sdam.sunwoo@arm.com process = Task(uid, 9999, 9999, "framebuffer", True, 0) 5329935Sdam.sunwoo@arm.com process_list.append(process) 5339935Sdam.sunwoo@arm.com uid += 1 5349935Sdam.sunwoo@arm.com thread = Task(uid, 9999, 9999, "framebuffer", False, 0) 5359935Sdam.sunwoo@arm.com process.children.append(thread) 5369935Sdam.sunwoo@arm.com uid += 1 5379935Sdam.sunwoo@arm.com process = Task(uid, 9998, 9998, "System", True, 0) 5389935Sdam.sunwoo@arm.com process_list.append(process) 5399935Sdam.sunwoo@arm.com # if we don't find the real kernel, use this to keep things going 5409935Sdam.sunwoo@arm.com kernel_uid = uid 5419935Sdam.sunwoo@arm.com uid += 1 5429935Sdam.sunwoo@arm.com thread = Task(uid, 9998, 9998, "System", False, 0) 5439935Sdam.sunwoo@arm.com process.children.append(thread) 5449935Sdam.sunwoo@arm.com uid += 1 5459935Sdam.sunwoo@arm.com 5469935Sdam.sunwoo@arm.com ext = os.path.splitext(task_file)[1] 5479935Sdam.sunwoo@arm.com 5489935Sdam.sunwoo@arm.com try: 5499935Sdam.sunwoo@arm.com if ext == ".gz": 5509935Sdam.sunwoo@arm.com process_file = gzip.open(task_file, 'rb') 5519935Sdam.sunwoo@arm.com else: 5529935Sdam.sunwoo@arm.com process_file = open(task_file, 'rb') 5539935Sdam.sunwoo@arm.com except: 5549935Sdam.sunwoo@arm.com print "ERROR opening task file:", task_file 5559935Sdam.sunwoo@arm.com print "Make sure context switch task dumping is enabled in gem5." 5569935Sdam.sunwoo@arm.com sys.exit(1) 5579935Sdam.sunwoo@arm.com 5589935Sdam.sunwoo@arm.com process_re = re.compile("tick=(\d+)\s+(\d+)\s+cpu_id=(\d+)\s+" + 5599935Sdam.sunwoo@arm.com "next_pid=([-\d]+)\s+next_tgid=([-\d]+)\s+next_task=(.*)") 5609935Sdam.sunwoo@arm.com 5619935Sdam.sunwoo@arm.com task_name_failure_warned = False 5629935Sdam.sunwoo@arm.com 5639935Sdam.sunwoo@arm.com for line in process_file: 5649935Sdam.sunwoo@arm.com match = re.match(process_re, line) 5659935Sdam.sunwoo@arm.com if match: 5669935Sdam.sunwoo@arm.com tick = int(match.group(1)) 5679935Sdam.sunwoo@arm.com if (start_tick < 0): 5689935Sdam.sunwoo@arm.com start_tick = tick 5699935Sdam.sunwoo@arm.com cpu_id = int(match.group(3)) 5709935Sdam.sunwoo@arm.com pid = int(match.group(4)) 5719935Sdam.sunwoo@arm.com tgid = int(match.group(5)) 5729935Sdam.sunwoo@arm.com task_name = match.group(6) 5739935Sdam.sunwoo@arm.com 5749935Sdam.sunwoo@arm.com if not task_name_failure_warned: 5759935Sdam.sunwoo@arm.com if task_name == "FailureIn_curTaskName": 5769935Sdam.sunwoo@arm.com print "-------------------------------------------------" 5779935Sdam.sunwoo@arm.com print "WARNING: Task name not set correctly!" 5789935Sdam.sunwoo@arm.com print "Process/Thread info will not be displayed correctly" 5799935Sdam.sunwoo@arm.com print "Perhaps forgot to apply m5struct.patch to kernel?" 5809935Sdam.sunwoo@arm.com print "-------------------------------------------------" 5819935Sdam.sunwoo@arm.com task_name_failure_warned = True 5829935Sdam.sunwoo@arm.com 5839935Sdam.sunwoo@arm.com if not tgid in process_dict: 5849935Sdam.sunwoo@arm.com if tgid == pid: 5859935Sdam.sunwoo@arm.com # new task is parent as well 5869935Sdam.sunwoo@arm.com if args.verbose: 5879935Sdam.sunwoo@arm.com print "new process", uid, pid, tgid, task_name 5889935Sdam.sunwoo@arm.com if tgid == 0: 5899935Sdam.sunwoo@arm.com # new process is the "idle" task 5909935Sdam.sunwoo@arm.com process = Task(uid, pid, tgid, "idle", True, tick) 5919935Sdam.sunwoo@arm.com idle_uid = 0 5929935Sdam.sunwoo@arm.com else: 5939935Sdam.sunwoo@arm.com process = Task(uid, pid, tgid, task_name, True, tick) 5949935Sdam.sunwoo@arm.com else: 5959935Sdam.sunwoo@arm.com if tgid == 0: 5969935Sdam.sunwoo@arm.com process = Task(uid, tgid, tgid, "idle", True, tick) 5979935Sdam.sunwoo@arm.com idle_uid = 0 5989935Sdam.sunwoo@arm.com else: 5999935Sdam.sunwoo@arm.com # parent process name not known yet 6009935Sdam.sunwoo@arm.com process = Task(uid, tgid, tgid, "_Unknown_", True, tick) 6019935Sdam.sunwoo@arm.com if tgid == -1: # kernel 6029935Sdam.sunwoo@arm.com kernel_uid = 0 6039935Sdam.sunwoo@arm.com uid += 1 6049935Sdam.sunwoo@arm.com process_dict[tgid] = process 6059935Sdam.sunwoo@arm.com process_list.append(process) 6069935Sdam.sunwoo@arm.com else: 6079935Sdam.sunwoo@arm.com if tgid == pid: 6089935Sdam.sunwoo@arm.com if process_dict[tgid].task_name == "_Unknown_": 6099935Sdam.sunwoo@arm.com if args.verbose: 6109935Sdam.sunwoo@arm.com print "new process", \ 6119935Sdam.sunwoo@arm.com process_dict[tgid].uid, pid, tgid, task_name 6129935Sdam.sunwoo@arm.com process_dict[tgid].task_name = task_name 6139935Sdam.sunwoo@arm.com if process_dict[tgid].task_name != task_name and tgid != 0: 6149935Sdam.sunwoo@arm.com process_dict[tgid].task_name = task_name 6159935Sdam.sunwoo@arm.com 6169935Sdam.sunwoo@arm.com if not pid in thread_dict: 6179935Sdam.sunwoo@arm.com if args.verbose: 6189935Sdam.sunwoo@arm.com print "new thread", \ 6199935Sdam.sunwoo@arm.com uid, process_dict[tgid].uid, pid, tgid, task_name 6209935Sdam.sunwoo@arm.com thread = Task(uid, pid, tgid, task_name, False, tick) 6219935Sdam.sunwoo@arm.com uid += 1 6229935Sdam.sunwoo@arm.com thread_dict[pid] = thread 6239935Sdam.sunwoo@arm.com process_dict[tgid].children.append(thread) 6249935Sdam.sunwoo@arm.com else: 6259935Sdam.sunwoo@arm.com if thread_dict[pid].task_name != task_name: 6269935Sdam.sunwoo@arm.com thread_dict[pid].task_name = task_name 6279935Sdam.sunwoo@arm.com 6289935Sdam.sunwoo@arm.com if args.verbose: 6299935Sdam.sunwoo@arm.com print tick, uid, cpu_id, pid, tgid, task_name 6309935Sdam.sunwoo@arm.com 6319935Sdam.sunwoo@arm.com task = thread_dict[pid] 6329935Sdam.sunwoo@arm.com event = Event(tick, task) 6339935Sdam.sunwoo@arm.com event_list[cpu_id].append(event) 6349935Sdam.sunwoo@arm.com unified_event_list.append(event) 6359935Sdam.sunwoo@arm.com 6369935Sdam.sunwoo@arm.com if len(unified_event_list) == num_events: 6379935Sdam.sunwoo@arm.com print "Truncating at", num_events, "events!" 6389935Sdam.sunwoo@arm.com break 6399935Sdam.sunwoo@arm.com print "Found %d events." % len(unified_event_list) 6409935Sdam.sunwoo@arm.com 6419935Sdam.sunwoo@arm.com for process in process_list: 6429935Sdam.sunwoo@arm.com if process.pid > 9990: # fix up framebuffer ticks 6439935Sdam.sunwoo@arm.com process.tick = start_tick 6449935Sdam.sunwoo@arm.com print process.uid, process.pid, process.tgid, \ 6459935Sdam.sunwoo@arm.com process.task_name, str(process.tick) 6469935Sdam.sunwoo@arm.com for thread in process.children: 6479935Sdam.sunwoo@arm.com if thread.pid > 9990: 6489935Sdam.sunwoo@arm.com thread.tick = start_tick 6499935Sdam.sunwoo@arm.com print "\t", thread.uid, thread.pid, thread.tgid, \ 6509935Sdam.sunwoo@arm.com thread.task_name, str(thread.tick) 6519935Sdam.sunwoo@arm.com 6529935Sdam.sunwoo@arm.com end_tick = tick 6539935Sdam.sunwoo@arm.com 6549935Sdam.sunwoo@arm.com print "Start tick:", start_tick 6559935Sdam.sunwoo@arm.com print "End tick: ", end_tick 6569935Sdam.sunwoo@arm.com print "" 6579935Sdam.sunwoo@arm.com 6589935Sdam.sunwoo@arm.com return 6599935Sdam.sunwoo@arm.com 6609935Sdam.sunwoo@arm.com 6619935Sdam.sunwoo@arm.comdef initOutput(output_path): 6629935Sdam.sunwoo@arm.com if not os.path.exists(output_path): 6639935Sdam.sunwoo@arm.com os.mkdir(output_path) 6649935Sdam.sunwoo@arm.com 6659935Sdam.sunwoo@arm.comdef ticksToNs(tick): 6669935Sdam.sunwoo@arm.com if ticks_in_ns < 0: 6679935Sdam.sunwoo@arm.com print "ticks_in_ns not set properly!" 6689935Sdam.sunwoo@arm.com sys.exit(1) 6699935Sdam.sunwoo@arm.com 6709935Sdam.sunwoo@arm.com return tick / ticks_in_ns 6719935Sdam.sunwoo@arm.com 6729935Sdam.sunwoo@arm.comdef writeXmlFile(xml, filename): 6739935Sdam.sunwoo@arm.com f = open(filename, "w") 6749935Sdam.sunwoo@arm.com txt = ET.tostring(xml) 6759935Sdam.sunwoo@arm.com f.write(minidom.parseString(txt).toprettyxml()) 6769935Sdam.sunwoo@arm.com f.close() 6779935Sdam.sunwoo@arm.com 6789935Sdam.sunwoo@arm.com 6799935Sdam.sunwoo@arm.com# StatsEntry that contains individual statistics 6809935Sdam.sunwoo@arm.comclass StatsEntry(object): 6819935Sdam.sunwoo@arm.com def __init__(self, name, group, group_index, per_cpu, per_switchcpu, key): 6829935Sdam.sunwoo@arm.com 6839935Sdam.sunwoo@arm.com # Full name of statistics 6849935Sdam.sunwoo@arm.com self.name = name 6859935Sdam.sunwoo@arm.com 6869935Sdam.sunwoo@arm.com # Streamline group name that statistic will belong to 6879935Sdam.sunwoo@arm.com self.group = group 6889935Sdam.sunwoo@arm.com 6899935Sdam.sunwoo@arm.com # Index of statistics within group (used to change colors within groups) 6909935Sdam.sunwoo@arm.com self.group_index = group_index 6919935Sdam.sunwoo@arm.com 6929935Sdam.sunwoo@arm.com # Shorter name with "system" stripped off 6939935Sdam.sunwoo@arm.com # and symbols converted to alphanumerics 6949935Sdam.sunwoo@arm.com self.short_name = re.sub("system\.", "", name) 6959935Sdam.sunwoo@arm.com self.short_name = re.sub(":", "_", name) 6969935Sdam.sunwoo@arm.com 6979935Sdam.sunwoo@arm.com # Regex for this stat (string version used to construct union regex) 6989935Sdam.sunwoo@arm.com self.regex_string = "^" + name + "\s+([\d\.]+)" 6999935Sdam.sunwoo@arm.com self.regex = re.compile("^" + name + "\s+([\d\.e\-]+)\s+# (.*)$", re.M) 7009935Sdam.sunwoo@arm.com self.description = "" 7019935Sdam.sunwoo@arm.com 7029935Sdam.sunwoo@arm.com # Whether this stat is use per CPU or not 7039935Sdam.sunwoo@arm.com self.per_cpu = per_cpu 7049935Sdam.sunwoo@arm.com self.per_switchcpu = per_switchcpu 7059935Sdam.sunwoo@arm.com 7069935Sdam.sunwoo@arm.com # Key used in .apc protocol (as described in captured.xml) 7079935Sdam.sunwoo@arm.com self.key = key 7089935Sdam.sunwoo@arm.com 7099935Sdam.sunwoo@arm.com # List of values of stat per timestamp 7109935Sdam.sunwoo@arm.com self.values = [] 7119935Sdam.sunwoo@arm.com 7129935Sdam.sunwoo@arm.com # Whether this stat has been found for the current timestamp 7139935Sdam.sunwoo@arm.com self.found = False 7149935Sdam.sunwoo@arm.com 7159935Sdam.sunwoo@arm.com # Whether this stat has been found at least once 7169935Sdam.sunwoo@arm.com # (to suppress too many warnings) 7179935Sdam.sunwoo@arm.com self.not_found_at_least_once = False 7189935Sdam.sunwoo@arm.com 7199935Sdam.sunwoo@arm.com # Field used to hold ElementTree subelement for this stat 7209935Sdam.sunwoo@arm.com self.ET_element = None 7219935Sdam.sunwoo@arm.com 7229935Sdam.sunwoo@arm.com # Create per-CPU stat name and regex, etc. 7239935Sdam.sunwoo@arm.com if self.per_cpu: 7249935Sdam.sunwoo@arm.com self.per_cpu_regex_string = [] 7259935Sdam.sunwoo@arm.com self.per_cpu_regex = [] 7269935Sdam.sunwoo@arm.com self.per_cpu_name = [] 7279935Sdam.sunwoo@arm.com self.per_cpu_found = [] 7289935Sdam.sunwoo@arm.com for i in range(num_cpus): 7299935Sdam.sunwoo@arm.com # Resuming from checkpoints results in using "switch_cpus" 7309935Sdam.sunwoo@arm.com if per_switchcpu: 7319935Sdam.sunwoo@arm.com per_cpu_name = "system.switch_cpus" 7329935Sdam.sunwoo@arm.com else: 7339935Sdam.sunwoo@arm.com per_cpu_name = "system.cpu" 7349935Sdam.sunwoo@arm.com 7359935Sdam.sunwoo@arm.com # No CPU number appends if num_cpus == 1 7369935Sdam.sunwoo@arm.com if num_cpus > 1: 7379935Sdam.sunwoo@arm.com per_cpu_name += str(i) 7389935Sdam.sunwoo@arm.com per_cpu_name += "." + self.name 7399935Sdam.sunwoo@arm.com self.per_cpu_name.append(per_cpu_name) 7409935Sdam.sunwoo@arm.com print "\t", per_cpu_name 7419935Sdam.sunwoo@arm.com 7429935Sdam.sunwoo@arm.com self.per_cpu_regex_string.\ 7439935Sdam.sunwoo@arm.com append("^" + per_cpu_name + "\s+[\d\.]+") 7449935Sdam.sunwoo@arm.com self.per_cpu_regex.append(re.compile("^" + per_cpu_name + \ 7459935Sdam.sunwoo@arm.com "\s+([\d\.e\-]+)\s+# (.*)$", re.M)) 7469935Sdam.sunwoo@arm.com self.values.append([]) 7479935Sdam.sunwoo@arm.com self.per_cpu_found.append(False) 7489935Sdam.sunwoo@arm.com 7499935Sdam.sunwoo@arm.com def append_value(self, val, per_cpu_index = None): 7509935Sdam.sunwoo@arm.com if self.per_cpu: 7519935Sdam.sunwoo@arm.com self.values[per_cpu_index].append(str(val)) 7529935Sdam.sunwoo@arm.com else: 7539935Sdam.sunwoo@arm.com self.values.append(str(val)) 7549935Sdam.sunwoo@arm.com 7559935Sdam.sunwoo@arm.com# Global stats object that contains the list of stats entries 7569935Sdam.sunwoo@arm.com# and other utility functions 7579935Sdam.sunwoo@arm.comclass Stats(object): 7589935Sdam.sunwoo@arm.com def __init__(self): 7599935Sdam.sunwoo@arm.com self.stats_list = [] 7609935Sdam.sunwoo@arm.com self.tick_list = [] 7619935Sdam.sunwoo@arm.com self.next_key = 1 7629935Sdam.sunwoo@arm.com 7639935Sdam.sunwoo@arm.com def register(self, name, group, group_index, per_cpu, per_switchcpu): 7649935Sdam.sunwoo@arm.com print "registering stat:", name, "group:", group, group_index 7659935Sdam.sunwoo@arm.com self.stats_list.append(StatsEntry(name, group, group_index, per_cpu, \ 7669935Sdam.sunwoo@arm.com per_switchcpu, self.next_key)) 7679935Sdam.sunwoo@arm.com self.next_key += 1 7689935Sdam.sunwoo@arm.com 7699935Sdam.sunwoo@arm.com # Union of all stats to accelerate parsing speed 7709935Sdam.sunwoo@arm.com def createStatsRegex(self): 7719935Sdam.sunwoo@arm.com regex_strings = []; 7729935Sdam.sunwoo@arm.com print "\nnum entries in stats_list", len(self.stats_list) 7739935Sdam.sunwoo@arm.com for entry in self.stats_list: 7749935Sdam.sunwoo@arm.com if entry.per_cpu: 7759935Sdam.sunwoo@arm.com for i in range(num_cpus): 7769935Sdam.sunwoo@arm.com regex_strings.append(entry.per_cpu_regex_string[i]) 7779935Sdam.sunwoo@arm.com else: 7789935Sdam.sunwoo@arm.com regex_strings.append(entry.regex_string) 7799935Sdam.sunwoo@arm.com 7809935Sdam.sunwoo@arm.com self.regex = re.compile('|'.join(regex_strings)) 7819935Sdam.sunwoo@arm.com 7829935Sdam.sunwoo@arm.com 7839935Sdam.sunwoo@arm.comdef registerStats(config_file): 7849935Sdam.sunwoo@arm.com print "===============================" 7859935Sdam.sunwoo@arm.com print "Parsing stats config.ini file..." 7869935Sdam.sunwoo@arm.com print config_file 7879935Sdam.sunwoo@arm.com print "===============================" 7889935Sdam.sunwoo@arm.com 7899935Sdam.sunwoo@arm.com config = ConfigParser() 7909935Sdam.sunwoo@arm.com if not config.read(config_file): 7919935Sdam.sunwoo@arm.com print "ERROR: config file '", config_file, "' not found!" 7929935Sdam.sunwoo@arm.com sys.exit(1) 7939935Sdam.sunwoo@arm.com 7949935Sdam.sunwoo@arm.com print "\nRegistering Stats..." 7959935Sdam.sunwoo@arm.com 7969935Sdam.sunwoo@arm.com stats = Stats() 7979935Sdam.sunwoo@arm.com 7989935Sdam.sunwoo@arm.com per_cpu_stat_groups = config.options('PER_CPU_STATS') 7999935Sdam.sunwoo@arm.com for group in per_cpu_stat_groups: 8009935Sdam.sunwoo@arm.com i = 0 8019935Sdam.sunwoo@arm.com per_cpu_stats_list = config.get('PER_CPU_STATS', group).split('\n') 8029935Sdam.sunwoo@arm.com for item in per_cpu_stats_list: 8039935Sdam.sunwoo@arm.com if item: 8049935Sdam.sunwoo@arm.com stats.register(item, group, i, True, False) 8059935Sdam.sunwoo@arm.com i += 1 8069935Sdam.sunwoo@arm.com 8079935Sdam.sunwoo@arm.com per_cpu_stat_groups = config.options('PER_SWITCHCPU_STATS') 8089935Sdam.sunwoo@arm.com for group in per_cpu_stat_groups: 8099935Sdam.sunwoo@arm.com i = 0 8109935Sdam.sunwoo@arm.com per_cpu_stats_list = \ 8119935Sdam.sunwoo@arm.com config.get('PER_SWITCHCPU_STATS', group).split('\n') 8129935Sdam.sunwoo@arm.com for item in per_cpu_stats_list: 8139935Sdam.sunwoo@arm.com if item: 8149935Sdam.sunwoo@arm.com stats.register(item, group, i, True, True) 8159935Sdam.sunwoo@arm.com i += 1 8169935Sdam.sunwoo@arm.com 8179935Sdam.sunwoo@arm.com per_l2_stat_groups = config.options('PER_L2_STATS') 8189935Sdam.sunwoo@arm.com for group in per_l2_stat_groups: 8199935Sdam.sunwoo@arm.com i = 0 8209935Sdam.sunwoo@arm.com per_l2_stats_list = config.get('PER_L2_STATS', group).split('\n') 8219935Sdam.sunwoo@arm.com for item in per_l2_stats_list: 8229935Sdam.sunwoo@arm.com if item: 8239935Sdam.sunwoo@arm.com for l2 in range(num_l2): 8249935Sdam.sunwoo@arm.com name = item 8259935Sdam.sunwoo@arm.com prefix = "system.l2" 8269935Sdam.sunwoo@arm.com if num_l2 > 1: 8279935Sdam.sunwoo@arm.com prefix += str(l2) 8289935Sdam.sunwoo@arm.com prefix += "." 8299935Sdam.sunwoo@arm.com name = prefix + name 8309935Sdam.sunwoo@arm.com stats.register(name, group, i, False, False) 8319935Sdam.sunwoo@arm.com i += 1 8329935Sdam.sunwoo@arm.com 8339935Sdam.sunwoo@arm.com other_stat_groups = config.options('OTHER_STATS') 8349935Sdam.sunwoo@arm.com for group in other_stat_groups: 8359935Sdam.sunwoo@arm.com i = 0 8369935Sdam.sunwoo@arm.com other_stats_list = config.get('OTHER_STATS', group).split('\n') 8379935Sdam.sunwoo@arm.com for item in other_stats_list: 8389935Sdam.sunwoo@arm.com if item: 8399935Sdam.sunwoo@arm.com stats.register(item, group, i, False, False) 8409935Sdam.sunwoo@arm.com i += 1 8419935Sdam.sunwoo@arm.com 8429935Sdam.sunwoo@arm.com stats.createStatsRegex() 8439935Sdam.sunwoo@arm.com 8449935Sdam.sunwoo@arm.com return stats 8459935Sdam.sunwoo@arm.com 8469935Sdam.sunwoo@arm.com# Parse and read in gem5 stats file 8479935Sdam.sunwoo@arm.com# Streamline counters are organized per CPU 8489935Sdam.sunwoo@arm.comdef readGem5Stats(stats, gem5_stats_file): 8499935Sdam.sunwoo@arm.com print "\n===============================" 8509935Sdam.sunwoo@arm.com print "Parsing gem5 stats file..." 8519935Sdam.sunwoo@arm.com print gem5_stats_file 8529935Sdam.sunwoo@arm.com print "===============================\n" 8539935Sdam.sunwoo@arm.com ext = os.path.splitext(gem5_stats_file)[1] 8549935Sdam.sunwoo@arm.com 8559935Sdam.sunwoo@arm.com window_start_regex = \ 8569935Sdam.sunwoo@arm.com re.compile("^---------- Begin Simulation Statistics ----------") 8579935Sdam.sunwoo@arm.com window_end_regex = \ 8589935Sdam.sunwoo@arm.com re.compile("^---------- End Simulation Statistics ----------") 8599935Sdam.sunwoo@arm.com final_tick_regex = re.compile("^final_tick\s+(\d+)") 8609935Sdam.sunwoo@arm.com 8619935Sdam.sunwoo@arm.com global ticks_in_ns 8629935Sdam.sunwoo@arm.com sim_freq_regex = re.compile("^sim_freq\s+(\d+)") 8639935Sdam.sunwoo@arm.com sim_freq = -1 8649935Sdam.sunwoo@arm.com 8659935Sdam.sunwoo@arm.com try: 8669935Sdam.sunwoo@arm.com if ext == ".gz": 8679935Sdam.sunwoo@arm.com f = gzip.open(gem5_stats_file, "r") 8689935Sdam.sunwoo@arm.com else: 8699935Sdam.sunwoo@arm.com f = open(gem5_stats_file, "r") 8709935Sdam.sunwoo@arm.com except: 8719935Sdam.sunwoo@arm.com print "ERROR opening stats file", gem5_stats_file, "!" 8729935Sdam.sunwoo@arm.com sys.exit(1) 8739935Sdam.sunwoo@arm.com 8749935Sdam.sunwoo@arm.com stats_not_found_list = stats.stats_list[:] 8759935Sdam.sunwoo@arm.com window_num = 0 8769935Sdam.sunwoo@arm.com 8779935Sdam.sunwoo@arm.com while (True): 8789935Sdam.sunwoo@arm.com error = False 8799935Sdam.sunwoo@arm.com try: 8809935Sdam.sunwoo@arm.com line = f.readline() 8819935Sdam.sunwoo@arm.com except IOError: 8829935Sdam.sunwoo@arm.com print "" 8839935Sdam.sunwoo@arm.com print "WARNING: IO error in stats file" 8849935Sdam.sunwoo@arm.com print "(gzip stream not closed properly?)...continuing for now" 8859935Sdam.sunwoo@arm.com error = True 8869935Sdam.sunwoo@arm.com if not line: 8879935Sdam.sunwoo@arm.com break 8889935Sdam.sunwoo@arm.com 8899935Sdam.sunwoo@arm.com # Find out how many gem5 ticks in 1ns 8909935Sdam.sunwoo@arm.com if sim_freq < 0: 8919935Sdam.sunwoo@arm.com m = sim_freq_regex.match(line) 8929935Sdam.sunwoo@arm.com if m: 8939935Sdam.sunwoo@arm.com sim_freq = int(m.group(1)) # ticks in 1 sec 8949935Sdam.sunwoo@arm.com ticks_in_ns = int(sim_freq / 1e9) 8959935Sdam.sunwoo@arm.com print "Simulation frequency found! 1 tick == %e sec\n" \ 8969935Sdam.sunwoo@arm.com % (1.0 / sim_freq) 8979935Sdam.sunwoo@arm.com 8989935Sdam.sunwoo@arm.com # Final tick in gem5 stats: current absolute timestamp 8999935Sdam.sunwoo@arm.com m = final_tick_regex.match(line) 9009935Sdam.sunwoo@arm.com if m: 9019935Sdam.sunwoo@arm.com tick = int(m.group(1)) 9029935Sdam.sunwoo@arm.com if tick > end_tick: 9039935Sdam.sunwoo@arm.com break 9049935Sdam.sunwoo@arm.com stats.tick_list.append(tick) 9059935Sdam.sunwoo@arm.com 9069935Sdam.sunwoo@arm.com 9079935Sdam.sunwoo@arm.com if (window_end_regex.match(line) or error): 9089935Sdam.sunwoo@arm.com if args.verbose: 9099935Sdam.sunwoo@arm.com print "new window" 9109935Sdam.sunwoo@arm.com for stat in stats.stats_list: 9119935Sdam.sunwoo@arm.com if stat.per_cpu: 9129935Sdam.sunwoo@arm.com for i in range(num_cpus): 9139935Sdam.sunwoo@arm.com if not stat.per_cpu_found[i]: 9149935Sdam.sunwoo@arm.com if not stat.not_found_at_least_once: 9159935Sdam.sunwoo@arm.com print "WARNING: stat not found in window #", \ 9169935Sdam.sunwoo@arm.com window_num, ":", stat.per_cpu_name[i] 9179935Sdam.sunwoo@arm.com print "suppressing further warnings for " + \ 9189935Sdam.sunwoo@arm.com "this stat" 9199935Sdam.sunwoo@arm.com stat.not_found_at_least_once = True 9209935Sdam.sunwoo@arm.com stat.values[i].append(str(0)) 9219935Sdam.sunwoo@arm.com stat.per_cpu_found[i] = False 9229935Sdam.sunwoo@arm.com else: 9239935Sdam.sunwoo@arm.com if not stat.found: 9249935Sdam.sunwoo@arm.com if not stat.not_found_at_least_once: 9259935Sdam.sunwoo@arm.com print "WARNING: stat not found in window #", \ 9269935Sdam.sunwoo@arm.com window_num, ":", stat.name 9279935Sdam.sunwoo@arm.com print "suppressing further warnings for this stat" 9289935Sdam.sunwoo@arm.com stat.not_found_at_least_once = True 9299935Sdam.sunwoo@arm.com stat.values.append(str(0)) 9309935Sdam.sunwoo@arm.com stat.found = False 9319935Sdam.sunwoo@arm.com stats_not_found_list = stats.stats_list[:] 9329935Sdam.sunwoo@arm.com window_num += 1 9339935Sdam.sunwoo@arm.com if error: 9349935Sdam.sunwoo@arm.com break 9359935Sdam.sunwoo@arm.com 9369935Sdam.sunwoo@arm.com # Do a single regex of the union of all stats first for speed 9379935Sdam.sunwoo@arm.com if stats.regex.match(line): 9389935Sdam.sunwoo@arm.com # Then loop through only the stats we haven't seen in this window 9399935Sdam.sunwoo@arm.com for stat in stats_not_found_list[:]: 9409935Sdam.sunwoo@arm.com if stat.per_cpu: 9419935Sdam.sunwoo@arm.com for i in range(num_cpus): 9429935Sdam.sunwoo@arm.com m = stat.per_cpu_regex[i].match(line) 9439935Sdam.sunwoo@arm.com if m: 9449935Sdam.sunwoo@arm.com if stat.name == "ipc": 9459935Sdam.sunwoo@arm.com value = str(int(float(m.group(1)) * 1000)) 9469935Sdam.sunwoo@arm.com else: 9479935Sdam.sunwoo@arm.com value = str(int(float(m.group(1)))) 9489935Sdam.sunwoo@arm.com if args.verbose: 9499935Sdam.sunwoo@arm.com print stat.per_cpu_name[i], value 9509935Sdam.sunwoo@arm.com stat.values[i].append(value) 9519935Sdam.sunwoo@arm.com stat.per_cpu_found[i] = True 9529935Sdam.sunwoo@arm.com all_found = True 9539935Sdam.sunwoo@arm.com for j in range(num_cpus): 9549935Sdam.sunwoo@arm.com if not stat.per_cpu_found[j]: 9559935Sdam.sunwoo@arm.com all_found = False 9569935Sdam.sunwoo@arm.com if all_found: 9579935Sdam.sunwoo@arm.com stats_not_found_list.remove(stat) 9589935Sdam.sunwoo@arm.com if stat.description == "": 9599935Sdam.sunwoo@arm.com stat.description = m.group(2) 9609935Sdam.sunwoo@arm.com else: 9619935Sdam.sunwoo@arm.com m = stat.regex.match(line) 9629935Sdam.sunwoo@arm.com if m: 9639935Sdam.sunwoo@arm.com value = str(int(float(m.group(1)))) 9649935Sdam.sunwoo@arm.com if args.verbose: 9659935Sdam.sunwoo@arm.com print stat.name, value 9669935Sdam.sunwoo@arm.com stat.values.append(value) 9679935Sdam.sunwoo@arm.com stat.found = True 9689935Sdam.sunwoo@arm.com stats_not_found_list.remove(stat) 9699935Sdam.sunwoo@arm.com if stat.description == "": 9709935Sdam.sunwoo@arm.com stat.description = m.group(2) 9719935Sdam.sunwoo@arm.com f.close() 9729935Sdam.sunwoo@arm.com 9739935Sdam.sunwoo@arm.com 9749935Sdam.sunwoo@arm.com# Create session.xml file in .apc folder 9759935Sdam.sunwoo@arm.comdef doSessionXML(output_path): 9769935Sdam.sunwoo@arm.com session_file = output_path + "/session.xml" 9779935Sdam.sunwoo@arm.com 9789935Sdam.sunwoo@arm.com xml = ET.Element("session") 9799935Sdam.sunwoo@arm.com 9809935Sdam.sunwoo@arm.com xml.set("version", "1") 9819935Sdam.sunwoo@arm.com xml.set("call_stack_unwinding", "no") 9829935Sdam.sunwoo@arm.com xml.set("parse_debug_info", "no") 9839935Sdam.sunwoo@arm.com xml.set("high_resolution", "yes") 9849935Sdam.sunwoo@arm.com xml.set("buffer_mode", "streaming") 9859935Sdam.sunwoo@arm.com xml.set("sample_rate", "low") 9869935Sdam.sunwoo@arm.com 9879935Sdam.sunwoo@arm.com # Setting duration to zero for now. Doesn't affect visualization. 9889935Sdam.sunwoo@arm.com xml.set("duration", "0") 9899935Sdam.sunwoo@arm.com 9909935Sdam.sunwoo@arm.com xml.set("target_host", "") 9919935Sdam.sunwoo@arm.com xml.set("target_port", "8080") 9929935Sdam.sunwoo@arm.com 9939935Sdam.sunwoo@arm.com writeXmlFile(xml, session_file) 9949935Sdam.sunwoo@arm.com 9959935Sdam.sunwoo@arm.com 9969935Sdam.sunwoo@arm.com# Create captured.xml file in .apc folder 9979935Sdam.sunwoo@arm.comdef doCapturedXML(output_path, stats): 9989935Sdam.sunwoo@arm.com captured_file = output_path + "/captured.xml" 9999935Sdam.sunwoo@arm.com 10009935Sdam.sunwoo@arm.com xml = ET.Element("captured") 10019935Sdam.sunwoo@arm.com xml.set("version", "1") 10029935Sdam.sunwoo@arm.com xml.set("protocol", "12") 10039935Sdam.sunwoo@arm.com 10049935Sdam.sunwoo@arm.com target = ET.SubElement(xml, "target") 10059935Sdam.sunwoo@arm.com target.set("name", "gem5") 10069935Sdam.sunwoo@arm.com target.set("sample_rate", "1000") 10079935Sdam.sunwoo@arm.com target.set("cores", str(num_cpus)) 10089935Sdam.sunwoo@arm.com 10099935Sdam.sunwoo@arm.com counters = ET.SubElement(xml, "counters") 10109935Sdam.sunwoo@arm.com for stat in stats.stats_list: 10119935Sdam.sunwoo@arm.com s = ET.SubElement(counters, "counter") 10129935Sdam.sunwoo@arm.com stat_name = re.sub("\.", "_", stat.short_name) 10139935Sdam.sunwoo@arm.com s.set("title", stat.group) 10149935Sdam.sunwoo@arm.com s.set("name", stat_name) 10159935Sdam.sunwoo@arm.com s.set("color", "0x00000000") 10169935Sdam.sunwoo@arm.com s.set("key", "0x%08x" % stat.key) 10179935Sdam.sunwoo@arm.com s.set("type", stat_name) 10189935Sdam.sunwoo@arm.com s.set("event", "0x00000000") 10199935Sdam.sunwoo@arm.com if stat.per_cpu: 10209935Sdam.sunwoo@arm.com s.set("per_cpu", "yes") 10219935Sdam.sunwoo@arm.com else: 10229935Sdam.sunwoo@arm.com s.set("per_cpu", "no") 10239935Sdam.sunwoo@arm.com s.set("display", "") 10249935Sdam.sunwoo@arm.com s.set("units", "") 10259935Sdam.sunwoo@arm.com s.set("average_selection", "no") 10269935Sdam.sunwoo@arm.com s.set("description", stat.description) 10279935Sdam.sunwoo@arm.com 10289935Sdam.sunwoo@arm.com writeXmlFile(xml, captured_file) 10299935Sdam.sunwoo@arm.com 10309935Sdam.sunwoo@arm.com# Writes out Streamline cookies (unique IDs per process/thread) 10319935Sdam.sunwoo@arm.comdef writeCookiesThreads(blob): 10329935Sdam.sunwoo@arm.com thread_list = [] 10339935Sdam.sunwoo@arm.com for process in process_list: 10349935Sdam.sunwoo@arm.com if process.uid > 0: 10359935Sdam.sunwoo@arm.com print "cookie", process.task_name, process.uid 10369935Sdam.sunwoo@arm.com writeBinary(blob, cookieNameFrame(process.uid, process.task_name)) 10379935Sdam.sunwoo@arm.com 10389935Sdam.sunwoo@arm.com # pid and tgid need to be positive values -- no longer true? 10399935Sdam.sunwoo@arm.com for thread in process.children: 10409935Sdam.sunwoo@arm.com thread_list.append(thread) 10419935Sdam.sunwoo@arm.com 10429935Sdam.sunwoo@arm.com # Threads need to be sorted in timestamp order 10439935Sdam.sunwoo@arm.com thread_list.sort(key = lambda x: x.tick) 10449935Sdam.sunwoo@arm.com for thread in thread_list: 10459935Sdam.sunwoo@arm.com print "thread", thread.task_name, (ticksToNs(thread.tick)),\ 10469935Sdam.sunwoo@arm.com thread.tgid, thread.pid 10479935Sdam.sunwoo@arm.com writeBinary(blob, threadNameFrame(ticksToNs(thread.tick),\ 10489935Sdam.sunwoo@arm.com thread.pid, thread.task_name)) 10499935Sdam.sunwoo@arm.com 10509935Sdam.sunwoo@arm.com# Writes context switch info as Streamline scheduling events 10519935Sdam.sunwoo@arm.comdef writeSchedEvents(blob): 10529935Sdam.sunwoo@arm.com for cpu in range(num_cpus): 10539935Sdam.sunwoo@arm.com for event in event_list[cpu]: 10549935Sdam.sunwoo@arm.com timestamp = ticksToNs(event.tick) 10559935Sdam.sunwoo@arm.com pid = event.task.tgid 10569935Sdam.sunwoo@arm.com tid = event.task.pid 10579935Sdam.sunwoo@arm.com if process_dict.has_key(event.task.tgid): 10589935Sdam.sunwoo@arm.com cookie = process_dict[event.task.tgid].uid 10599935Sdam.sunwoo@arm.com else: 10609935Sdam.sunwoo@arm.com cookie = 0 10619935Sdam.sunwoo@arm.com 10629935Sdam.sunwoo@arm.com # State: 10639935Sdam.sunwoo@arm.com # 0: waiting on other event besides I/O 10649935Sdam.sunwoo@arm.com # 1: Contention/pre-emption 10659935Sdam.sunwoo@arm.com # 2: Waiting on I/O 10669935Sdam.sunwoo@arm.com # 3: Waiting on mutex 10679935Sdam.sunwoo@arm.com # Hardcoding to 0 for now. Other states not implemented yet. 10689935Sdam.sunwoo@arm.com state = 0 10699935Sdam.sunwoo@arm.com 10709935Sdam.sunwoo@arm.com if args.verbose: 10719935Sdam.sunwoo@arm.com print cpu, timestamp, pid, tid, cookie 10729935Sdam.sunwoo@arm.com 10739935Sdam.sunwoo@arm.com writeBinary(blob,\ 10749935Sdam.sunwoo@arm.com schedSwitchFrame(cpu, timestamp, pid, tid, cookie, state)) 10759935Sdam.sunwoo@arm.com 10769935Sdam.sunwoo@arm.com# Writes selected gem5 statistics as Streamline counters 10779935Sdam.sunwoo@arm.comdef writeCounters(blob, stats): 10789935Sdam.sunwoo@arm.com timestamp_list = [] 10799935Sdam.sunwoo@arm.com for tick in stats.tick_list: 10809935Sdam.sunwoo@arm.com if tick > end_tick: 10819935Sdam.sunwoo@arm.com break 10829935Sdam.sunwoo@arm.com timestamp_list.append(ticksToNs(tick)) 10839935Sdam.sunwoo@arm.com 10849935Sdam.sunwoo@arm.com for stat in stats.stats_list: 10859935Sdam.sunwoo@arm.com if stat.per_cpu: 10869935Sdam.sunwoo@arm.com stat_length = len(stat.values[0]) 10879935Sdam.sunwoo@arm.com else: 10889935Sdam.sunwoo@arm.com stat_length = len(stat.values) 10899935Sdam.sunwoo@arm.com 10909935Sdam.sunwoo@arm.com for n in range(len(timestamp_list)): 10919935Sdam.sunwoo@arm.com for stat in stats.stats_list: 10929935Sdam.sunwoo@arm.com if stat.per_cpu: 10939935Sdam.sunwoo@arm.com for i in range(num_cpus): 10949935Sdam.sunwoo@arm.com writeBinary(blob, counterFrame(timestamp_list[n], i, \ 10959935Sdam.sunwoo@arm.com stat.key, int(float(stat.values[i][n])))) 10969935Sdam.sunwoo@arm.com else: 10979935Sdam.sunwoo@arm.com writeBinary(blob, counterFrame(timestamp_list[n], 0, \ 10989935Sdam.sunwoo@arm.com stat.key, int(float(stat.values[n])))) 10999935Sdam.sunwoo@arm.com 11009935Sdam.sunwoo@arm.com# Streamline can display LCD frame buffer dumps (gzipped bmp) 11019935Sdam.sunwoo@arm.com# This function converts the frame buffer dumps to the Streamline format 11029935Sdam.sunwoo@arm.comdef writeVisualAnnotations(blob, input_path, output_path): 11039935Sdam.sunwoo@arm.com frame_path = input_path + "/frames_system.vncserver" 11049935Sdam.sunwoo@arm.com if not os.path.exists(frame_path): 11059935Sdam.sunwoo@arm.com return 11069935Sdam.sunwoo@arm.com 11079935Sdam.sunwoo@arm.com frame_count = 0 11089935Sdam.sunwoo@arm.com file_list = os.listdir(frame_path) 11099935Sdam.sunwoo@arm.com file_list.sort() 11109935Sdam.sunwoo@arm.com re_fb = re.compile("fb\.(\d+)\.(\d+)\.bmp.gz") 11119935Sdam.sunwoo@arm.com 11129935Sdam.sunwoo@arm.com # Use first non-negative pid to tag visual annotations 11139935Sdam.sunwoo@arm.com annotate_pid = -1 11149935Sdam.sunwoo@arm.com for e in unified_event_list: 11159935Sdam.sunwoo@arm.com pid = e.task.pid 11169935Sdam.sunwoo@arm.com if pid >= 0: 11179935Sdam.sunwoo@arm.com annotate_pid = pid 11189935Sdam.sunwoo@arm.com break 11199935Sdam.sunwoo@arm.com 11209935Sdam.sunwoo@arm.com for fn in file_list: 11219935Sdam.sunwoo@arm.com m = re_fb.match(fn) 11229935Sdam.sunwoo@arm.com if m: 11239935Sdam.sunwoo@arm.com seq = m.group(1) 11249935Sdam.sunwoo@arm.com tick = int(m.group(2)) 11259935Sdam.sunwoo@arm.com if tick > end_tick: 11269935Sdam.sunwoo@arm.com break 11279935Sdam.sunwoo@arm.com frame_count += 1 11289935Sdam.sunwoo@arm.com 11299935Sdam.sunwoo@arm.com userspace_body = [] 11309935Sdam.sunwoo@arm.com userspace_body += packed32(0x1C) # escape code 11319935Sdam.sunwoo@arm.com userspace_body += packed32(0x04) # visual code 11329935Sdam.sunwoo@arm.com 11339935Sdam.sunwoo@arm.com text_annotation = "image_" + str(ticksToNs(tick)) + ".bmp.gz" 11349935Sdam.sunwoo@arm.com userspace_body += int16(len(text_annotation)) 11359935Sdam.sunwoo@arm.com userspace_body += utf8StringList(text_annotation) 11369935Sdam.sunwoo@arm.com 11379935Sdam.sunwoo@arm.com if gzipped_bmp_supported: 11389935Sdam.sunwoo@arm.com # copy gzipped bmp directly 11399935Sdam.sunwoo@arm.com bytes_read = open(frame_path + "/" + fn, "rb").read() 11409935Sdam.sunwoo@arm.com else: 11419935Sdam.sunwoo@arm.com # copy uncompressed bmp 11429935Sdam.sunwoo@arm.com bytes_read = gzip.open(frame_path + "/" + fn, "rb").read() 11439935Sdam.sunwoo@arm.com 11449935Sdam.sunwoo@arm.com userspace_body += int32(len(bytes_read)) 11459935Sdam.sunwoo@arm.com userspace_body += bytes_read 11469935Sdam.sunwoo@arm.com 11479935Sdam.sunwoo@arm.com writeBinary(blob, annotateFrame(0, annotate_pid, ticksToNs(tick), \ 11489935Sdam.sunwoo@arm.com len(userspace_body), userspace_body)) 11499935Sdam.sunwoo@arm.com 11509935Sdam.sunwoo@arm.com print "\nfound", frame_count, "frames for visual annotation.\n" 11519935Sdam.sunwoo@arm.com 11529935Sdam.sunwoo@arm.com 11539935Sdam.sunwoo@arm.comdef createApcProject(input_path, output_path, stats): 11549935Sdam.sunwoo@arm.com initOutput(output_path) 11559935Sdam.sunwoo@arm.com 11569935Sdam.sunwoo@arm.com blob = open(output_path + "/0000000000", "wb") 11579935Sdam.sunwoo@arm.com 11589935Sdam.sunwoo@arm.com # Summary frame takes current system time and system uptime. 11599935Sdam.sunwoo@arm.com # Filling in with random values for now. 11609935Sdam.sunwoo@arm.com writeBinary(blob, summaryFrame(1234, 5678)) 11619935Sdam.sunwoo@arm.com 11629935Sdam.sunwoo@arm.com writeCookiesThreads(blob) 11639935Sdam.sunwoo@arm.com 11649935Sdam.sunwoo@arm.com print "writing Events" 11659935Sdam.sunwoo@arm.com writeSchedEvents(blob) 11669935Sdam.sunwoo@arm.com 11679935Sdam.sunwoo@arm.com print "writing Counters" 11689935Sdam.sunwoo@arm.com writeCounters(blob, stats) 11699935Sdam.sunwoo@arm.com 11709935Sdam.sunwoo@arm.com print "writing Visual Annotations" 11719935Sdam.sunwoo@arm.com writeVisualAnnotations(blob, input_path, output_path) 11729935Sdam.sunwoo@arm.com 11739935Sdam.sunwoo@arm.com doSessionXML(output_path) 11749935Sdam.sunwoo@arm.com doCapturedXML(output_path, stats) 11759935Sdam.sunwoo@arm.com 11769935Sdam.sunwoo@arm.com blob.close() 11779935Sdam.sunwoo@arm.com 11789935Sdam.sunwoo@arm.com 11799935Sdam.sunwoo@arm.com 11809935Sdam.sunwoo@arm.com####################### 11819935Sdam.sunwoo@arm.com# Main Routine 11829935Sdam.sunwoo@arm.com 11839935Sdam.sunwoo@arm.cominput_path = args.input_path 11849935Sdam.sunwoo@arm.comoutput_path = args.output_path 11859935Sdam.sunwoo@arm.com 11869935Sdam.sunwoo@arm.com#### 11879935Sdam.sunwoo@arm.com# Make sure input path exists 11889935Sdam.sunwoo@arm.com#### 11899935Sdam.sunwoo@arm.comif not os.path.exists(input_path): 11909935Sdam.sunwoo@arm.com print "ERROR: Input path %s does not exist!" % input_path 11919935Sdam.sunwoo@arm.com sys.exit(1) 11929935Sdam.sunwoo@arm.com 11939935Sdam.sunwoo@arm.com#### 11949935Sdam.sunwoo@arm.com# Parse gem5 configuration file to find # of CPUs and L2s 11959935Sdam.sunwoo@arm.com#### 11969935Sdam.sunwoo@arm.com(num_cpus, num_l2) = parseConfig(input_path + "/config.ini") 11979935Sdam.sunwoo@arm.com 11989935Sdam.sunwoo@arm.com#### 11999935Sdam.sunwoo@arm.com# Parse task file to find process/thread info 12009935Sdam.sunwoo@arm.com#### 12019935Sdam.sunwoo@arm.comparseProcessInfo(input_path + "/system.tasks.txt") 12029935Sdam.sunwoo@arm.com 12039935Sdam.sunwoo@arm.com#### 12049935Sdam.sunwoo@arm.com# Parse stat config file and register stats 12059935Sdam.sunwoo@arm.com#### 12069935Sdam.sunwoo@arm.comstat_config_file = args.stat_config_file 12079935Sdam.sunwoo@arm.comstats = registerStats(stat_config_file) 12089935Sdam.sunwoo@arm.com 12099935Sdam.sunwoo@arm.com#### 12109935Sdam.sunwoo@arm.com# Parse gem5 stats 12119935Sdam.sunwoo@arm.com#### 12129935Sdam.sunwoo@arm.com# Check if both stats.txt and stats.txt.gz exist and warn if both exist 12139935Sdam.sunwoo@arm.comif os.path.exists(input_path + "/stats.txt") and \ 12149935Sdam.sunwoo@arm.com os.path.exists(input_path + "/stats.txt.gz"): 12159935Sdam.sunwoo@arm.com print "WARNING: Both stats.txt.gz and stats.txt exist. \ 12169935Sdam.sunwoo@arm.com Using stats.txt.gz by default." 12179935Sdam.sunwoo@arm.com 12189935Sdam.sunwoo@arm.comgem5_stats_file = input_path + "/stats.txt.gz" 12199935Sdam.sunwoo@arm.comif not os.path.exists(gem5_stats_file): 12209935Sdam.sunwoo@arm.com gem5_stats_file = input_path + "/stats.txt" 12219935Sdam.sunwoo@arm.comif not os.path.exists(gem5_stats_file): 12229935Sdam.sunwoo@arm.com print "ERROR: stats.txt[.gz] file does not exist in %s!" % input_path 12239935Sdam.sunwoo@arm.com sys.exit(1) 12249935Sdam.sunwoo@arm.com 12259935Sdam.sunwoo@arm.comreadGem5Stats(stats, gem5_stats_file) 12269935Sdam.sunwoo@arm.com 12279935Sdam.sunwoo@arm.com#### 12289935Sdam.sunwoo@arm.com# Create Streamline .apc project folder 12299935Sdam.sunwoo@arm.com#### 12309935Sdam.sunwoo@arm.comcreateApcProject(input_path, output_path, stats) 12319935Sdam.sunwoo@arm.com 12329935Sdam.sunwoo@arm.comprint "All done!" 1233