m5stats2streamline.py revision 10354
19935Sdam.sunwoo@arm.com#!/usr/bin/env python 29935Sdam.sunwoo@arm.com 310354Sdam.sunwoo@arm.com# Copyright (c) 2012, 2014 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# 5910016Sdam.sunwoo@arm.com# APC project generation based on Gator v17 (DS-5 v5.17) 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 8110016Sdam.sunwoo@arm.com APC project generation based on Gator v17 (DS-5 v5.17) 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 14510354Sdam.sunwoo@arm.com if config.has_section("system.cluster.cpu"): 1469935Sdam.sunwoo@arm.com num_cpus = 1 1479935Sdam.sunwoo@arm.com else: 1489935Sdam.sunwoo@arm.com num_cpus = 0 14910354Sdam.sunwoo@arm.com while config.has_section("system.cluster.cpu" + str(num_cpus)): 1509935Sdam.sunwoo@arm.com num_cpus += 1 1519935Sdam.sunwoo@arm.com 15210354Sdam.sunwoo@arm.com if config.has_section("system.cluster.l2_cache"): 1539935Sdam.sunwoo@arm.com num_l2 = 1 1549935Sdam.sunwoo@arm.com else: 1559935Sdam.sunwoo@arm.com num_l2 = 0 15610354Sdam.sunwoo@arm.com while config.has_section("system.cluster.l2_cache" + 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 20110016Sdam.sunwoo@arm.comdef packed32(x): 20210016Sdam.sunwoo@arm.com ret = [] 20310016Sdam.sunwoo@arm.com more = True 20410016Sdam.sunwoo@arm.com while more: 20510016Sdam.sunwoo@arm.com b = x & 0x7f 20610016Sdam.sunwoo@arm.com x = x >> 7 20710016Sdam.sunwoo@arm.com if (((x == 0) and ((b & 0x40) == 0)) or \ 20810016Sdam.sunwoo@arm.com ((x == -1) and ((b & 0x40) != 0))): 20910016Sdam.sunwoo@arm.com more = False 21010016Sdam.sunwoo@arm.com else: 21110016Sdam.sunwoo@arm.com b = b | 0x80 21210016Sdam.sunwoo@arm.com ret.append(b) 21310016Sdam.sunwoo@arm.com return ret 21410016Sdam.sunwoo@arm.com 21510016Sdam.sunwoo@arm.com# For historical reasons, 32/64-bit versions of functions are presevered 21610016Sdam.sunwoo@arm.comdef packed64(x): 21710016Sdam.sunwoo@arm.com return packed32(x) 21810016Sdam.sunwoo@arm.com 2199935Sdam.sunwoo@arm.com# variable length packed 4-byte signed value 22010016Sdam.sunwoo@arm.comdef unsigned_packed32(x): 2219935Sdam.sunwoo@arm.com ret = [] 2229935Sdam.sunwoo@arm.com if ((x & 0xffffff80) == 0): 2239935Sdam.sunwoo@arm.com ret.append(x & 0x7f) 2249935Sdam.sunwoo@arm.com elif ((x & 0xffffc000) == 0): 2259935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2269935Sdam.sunwoo@arm.com ret.append((x >> 7) & 0x7f) 2279935Sdam.sunwoo@arm.com elif ((x & 0xffe00000) == 0): 2289935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2299935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2309935Sdam.sunwoo@arm.com ret.append((x >> 14) & 0x7f) 2319935Sdam.sunwoo@arm.com elif ((x & 0xf0000000) == 0): 2329935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2339935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2349935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2359935Sdam.sunwoo@arm.com ret.append((x >> 21) & 0x7f) 2369935Sdam.sunwoo@arm.com else: 2379935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2389935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2399935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2409935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2419935Sdam.sunwoo@arm.com ret.append((x >> 28) & 0x0f) 2429935Sdam.sunwoo@arm.com return ret 2439935Sdam.sunwoo@arm.com 2449935Sdam.sunwoo@arm.com# variable length packed 8-byte signed value 24510016Sdam.sunwoo@arm.comdef unsigned_packed64(x): 2469935Sdam.sunwoo@arm.com ret = [] 2479935Sdam.sunwoo@arm.com if ((x & 0xffffffffffffff80) == 0): 2489935Sdam.sunwoo@arm.com ret.append(x & 0x7f) 2499935Sdam.sunwoo@arm.com elif ((x & 0xffffffffffffc000) == 0): 2509935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2519935Sdam.sunwoo@arm.com ret.append((x >> 7) & 0x7f) 2529935Sdam.sunwoo@arm.com elif ((x & 0xffffffffffe00000) == 0): 2539935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2549935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2559935Sdam.sunwoo@arm.com ret.append((x >> 14) & 0x7f) 2569935Sdam.sunwoo@arm.com elif ((x & 0xfffffffff0000000) == 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) & 0x7f) 2619935Sdam.sunwoo@arm.com elif ((x & 0xfffffff800000000) == 0): 2629935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2639935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2649935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2659935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2669935Sdam.sunwoo@arm.com ret.append((x >> 28) & 0x7f) 2679935Sdam.sunwoo@arm.com elif ((x & 0xfffffc0000000000) == 0): 2689935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2699935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2709935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2719935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2729935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2739935Sdam.sunwoo@arm.com ret.append((x >> 35) & 0x7f) 2749935Sdam.sunwoo@arm.com elif ((x & 0xfffe000000000000) == 0): 2759935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2769935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2779935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2789935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2799935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2809935Sdam.sunwoo@arm.com ret.append(((x >> 35) | 0x80) & 0xff) 2819935Sdam.sunwoo@arm.com ret.append((x >> 42) & 0x7f) 2829935Sdam.sunwoo@arm.com elif ((x & 0xff00000000000000) == 0): 2839935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2849935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2859935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2869935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2879935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2889935Sdam.sunwoo@arm.com ret.append(((x >> 35) | 0x80) & 0xff) 2899935Sdam.sunwoo@arm.com ret.append(((x >> 42) | 0x80) & 0xff) 2909935Sdam.sunwoo@arm.com ret.append((x >> 49) & 0x7f) 2919935Sdam.sunwoo@arm.com elif ((x & 0x8000000000000000) == 0): 2929935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 2939935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 2949935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 2959935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 2969935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 2979935Sdam.sunwoo@arm.com ret.append(((x >> 35) | 0x80) & 0xff) 2989935Sdam.sunwoo@arm.com ret.append(((x >> 42) | 0x80) & 0xff) 2999935Sdam.sunwoo@arm.com ret.append(((x >> 49) | 0x80) & 0xff) 3009935Sdam.sunwoo@arm.com ret.append((x >> 56) & 0x7f) 3019935Sdam.sunwoo@arm.com else: 3029935Sdam.sunwoo@arm.com ret.append((x | 0x80) & 0xff) 3039935Sdam.sunwoo@arm.com ret.append(((x >> 7) | 0x80) & 0xff) 3049935Sdam.sunwoo@arm.com ret.append(((x >> 14) | 0x80) & 0xff) 3059935Sdam.sunwoo@arm.com ret.append(((x >> 21) | 0x80) & 0xff) 3069935Sdam.sunwoo@arm.com ret.append(((x >> 28) | 0x80) & 0xff) 3079935Sdam.sunwoo@arm.com ret.append(((x >> 35) | 0x80) & 0xff) 3089935Sdam.sunwoo@arm.com ret.append(((x >> 42) | 0x80) & 0xff) 3099935Sdam.sunwoo@arm.com ret.append(((x >> 49) | 0x80) & 0xff) 3109935Sdam.sunwoo@arm.com ret.append(((x >> 56) | 0x80) & 0xff) 3119935Sdam.sunwoo@arm.com ret.append((x >> 63) & 0x7f) 3129935Sdam.sunwoo@arm.com return ret 3139935Sdam.sunwoo@arm.com 3149935Sdam.sunwoo@arm.com# 4-byte signed little endian 3159935Sdam.sunwoo@arm.comdef int32(x): 3169935Sdam.sunwoo@arm.com ret = [] 3179935Sdam.sunwoo@arm.com ret.append(x & 0xff) 3189935Sdam.sunwoo@arm.com ret.append((x >> 8) & 0xff) 3199935Sdam.sunwoo@arm.com ret.append((x >> 16) & 0xff) 3209935Sdam.sunwoo@arm.com ret.append((x >> 24) & 0xff) 3219935Sdam.sunwoo@arm.com return ret 3229935Sdam.sunwoo@arm.com 3239935Sdam.sunwoo@arm.com# 2-byte signed little endian 3249935Sdam.sunwoo@arm.comdef int16(x): 3259935Sdam.sunwoo@arm.com ret = [] 3269935Sdam.sunwoo@arm.com ret.append(x & 0xff) 3279935Sdam.sunwoo@arm.com ret.append((x >> 8) & 0xff) 3289935Sdam.sunwoo@arm.com return ret 3299935Sdam.sunwoo@arm.com 3309935Sdam.sunwoo@arm.com# a packed32 length followed by the specified number of characters 3319935Sdam.sunwoo@arm.comdef stringList(x): 3329935Sdam.sunwoo@arm.com ret = [] 3339935Sdam.sunwoo@arm.com ret += packed32(len(x)) 3349935Sdam.sunwoo@arm.com for i in x: 3359935Sdam.sunwoo@arm.com ret.append(i) 3369935Sdam.sunwoo@arm.com return ret 3379935Sdam.sunwoo@arm.com 3389935Sdam.sunwoo@arm.comdef utf8StringList(x): 3399935Sdam.sunwoo@arm.com ret = [] 3409935Sdam.sunwoo@arm.com for i in x: 3419935Sdam.sunwoo@arm.com ret.append(ord(i)) 3429935Sdam.sunwoo@arm.com return ret 3439935Sdam.sunwoo@arm.com 3449935Sdam.sunwoo@arm.com# packed64 time value in nanoseconds relative to the uptime from the 3459935Sdam.sunwoo@arm.com# Summary message. 3469935Sdam.sunwoo@arm.comdef timestampList(x): 3479935Sdam.sunwoo@arm.com ret = packed64(x) 3489935Sdam.sunwoo@arm.com return ret 3499935Sdam.sunwoo@arm.com 3509935Sdam.sunwoo@arm.com 3519935Sdam.sunwoo@arm.com############################################################ 3529935Sdam.sunwoo@arm.com# Write binary 3539935Sdam.sunwoo@arm.com############################################################ 3549935Sdam.sunwoo@arm.com 3559935Sdam.sunwoo@arm.comdef writeBinary(outfile, binary_list): 3569935Sdam.sunwoo@arm.com for i in binary_list: 3579935Sdam.sunwoo@arm.com outfile.write("%c" % i) 3589935Sdam.sunwoo@arm.com 3599935Sdam.sunwoo@arm.com############################################################ 3609935Sdam.sunwoo@arm.com# APC Protocol Frame Types 3619935Sdam.sunwoo@arm.com############################################################ 3629935Sdam.sunwoo@arm.com 3639935Sdam.sunwoo@arm.comdef addFrameHeader(frame_type, body, core): 3649935Sdam.sunwoo@arm.com ret = [] 3659935Sdam.sunwoo@arm.com 3669935Sdam.sunwoo@arm.com if frame_type == "Summary": 3679935Sdam.sunwoo@arm.com code = 1 3689935Sdam.sunwoo@arm.com elif frame_type == "Backtrace": 3699935Sdam.sunwoo@arm.com code = 2 3709935Sdam.sunwoo@arm.com elif frame_type == "Name": 3719935Sdam.sunwoo@arm.com code = 3 3729935Sdam.sunwoo@arm.com elif frame_type == "Counter": 3739935Sdam.sunwoo@arm.com code = 4 3749935Sdam.sunwoo@arm.com elif frame_type == "Block Counter": 3759935Sdam.sunwoo@arm.com code = 5 3769935Sdam.sunwoo@arm.com elif frame_type == "Annotate": 3779935Sdam.sunwoo@arm.com code = 6 3789935Sdam.sunwoo@arm.com elif frame_type == "Sched Trace": 3799935Sdam.sunwoo@arm.com code = 7 3809935Sdam.sunwoo@arm.com elif frame_type == "GPU Trace": 3819935Sdam.sunwoo@arm.com code = 8 3829935Sdam.sunwoo@arm.com elif frame_type == "Idle": 3839935Sdam.sunwoo@arm.com code = 9 3849935Sdam.sunwoo@arm.com else: 3859935Sdam.sunwoo@arm.com print "ERROR: Unknown frame type:", frame_type 3869935Sdam.sunwoo@arm.com sys.exit(1) 3879935Sdam.sunwoo@arm.com 3889935Sdam.sunwoo@arm.com packed_code = packed32(code) 3899935Sdam.sunwoo@arm.com 3909935Sdam.sunwoo@arm.com packed_core = packed32(core) 3919935Sdam.sunwoo@arm.com 3929935Sdam.sunwoo@arm.com length = int32(len(packed_code) + len(packed_core) + len(body)) 3939935Sdam.sunwoo@arm.com 3949935Sdam.sunwoo@arm.com ret = length + packed_code + packed_core + body 3959935Sdam.sunwoo@arm.com return ret 3969935Sdam.sunwoo@arm.com 3979935Sdam.sunwoo@arm.com 3989935Sdam.sunwoo@arm.com# Summary frame 3999935Sdam.sunwoo@arm.com# - timestamp: packed64 4009935Sdam.sunwoo@arm.com# - uptime: packed64 4019935Sdam.sunwoo@arm.comdef summaryFrame(timestamp, uptime): 4029935Sdam.sunwoo@arm.com frame_type = "Summary" 40310016Sdam.sunwoo@arm.com newline_canary = stringList("1\n2\r\n3\r4\n\r5") 40410016Sdam.sunwoo@arm.com monotonic_delta = packed64(0) 40510016Sdam.sunwoo@arm.com end_of_attr = stringList("") 40610016Sdam.sunwoo@arm.com body = newline_canary + packed64(timestamp) + packed64(uptime) 40710016Sdam.sunwoo@arm.com body += monotonic_delta + end_of_attr 4089935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 4099935Sdam.sunwoo@arm.com return ret 4109935Sdam.sunwoo@arm.com 4119935Sdam.sunwoo@arm.com# Backtrace frame 4129935Sdam.sunwoo@arm.com# - not implemented yet 4139935Sdam.sunwoo@arm.comdef backtraceFrame(): 4149935Sdam.sunwoo@arm.com pass 4159935Sdam.sunwoo@arm.com 4169935Sdam.sunwoo@arm.com# Cookie name message 4179935Sdam.sunwoo@arm.com# - cookie: packed32 4189935Sdam.sunwoo@arm.com# - name: string 4199935Sdam.sunwoo@arm.comdef cookieNameFrame(cookie, name): 4209935Sdam.sunwoo@arm.com frame_type = "Name" 4219935Sdam.sunwoo@arm.com packed_code = packed32(1) 4229935Sdam.sunwoo@arm.com body = packed_code + packed32(cookie) + stringList(name) 4239935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 4249935Sdam.sunwoo@arm.com return ret 4259935Sdam.sunwoo@arm.com 4269935Sdam.sunwoo@arm.com# Thread name message 4279935Sdam.sunwoo@arm.com# - timestamp: timestamp 4289935Sdam.sunwoo@arm.com# - thread id: packed32 4299935Sdam.sunwoo@arm.com# - name: string 4309935Sdam.sunwoo@arm.comdef threadNameFrame(timestamp, thread_id, name): 4319935Sdam.sunwoo@arm.com frame_type = "Name" 4329935Sdam.sunwoo@arm.com packed_code = packed32(2) 4339935Sdam.sunwoo@arm.com body = packed_code + timestampList(timestamp) + \ 4349935Sdam.sunwoo@arm.com packed32(thread_id) + stringList(name) 4359935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 4369935Sdam.sunwoo@arm.com return ret 4379935Sdam.sunwoo@arm.com 4389935Sdam.sunwoo@arm.com# Core name message 4399935Sdam.sunwoo@arm.com# - name: string 44010016Sdam.sunwoo@arm.com# - core_id: packed32 44110016Sdam.sunwoo@arm.com# - cpuid: packed32 44210016Sdam.sunwoo@arm.comdef coreNameFrame(name, core_id, cpuid): 4439935Sdam.sunwoo@arm.com frame_type = "Name" 4449935Sdam.sunwoo@arm.com packed_code = packed32(3) 44510016Sdam.sunwoo@arm.com body = packed_code + packed32(core_id) + packed32(cpuid) + stringList(name) 44610016Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 44710016Sdam.sunwoo@arm.com return ret 44810016Sdam.sunwoo@arm.com 44910016Sdam.sunwoo@arm.com# IRQ Cookie name message 45010016Sdam.sunwoo@arm.com# - cookie: packed32 45110016Sdam.sunwoo@arm.com# - name: string 45210016Sdam.sunwoo@arm.com# - irq: packed32 45310016Sdam.sunwoo@arm.comdef irqCookieNameFrame(cookie, name, irq): 45410016Sdam.sunwoo@arm.com frame_type = "Name" 45510016Sdam.sunwoo@arm.com packed_code = packed32(5) 45610016Sdam.sunwoo@arm.com body = packed_code + packed32(cookie) + stringList(name) + packed32(irq) 4579935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, 0) 4589935Sdam.sunwoo@arm.com return ret 4599935Sdam.sunwoo@arm.com 4609935Sdam.sunwoo@arm.com# Counter frame message 4619935Sdam.sunwoo@arm.com# - timestamp: timestamp 4629935Sdam.sunwoo@arm.com# - core: packed32 4639935Sdam.sunwoo@arm.com# - key: packed32 4649935Sdam.sunwoo@arm.com# - value: packed64 4659935Sdam.sunwoo@arm.comdef counterFrame(timestamp, core, key, value): 4669935Sdam.sunwoo@arm.com frame_type = "Counter" 4679935Sdam.sunwoo@arm.com body = timestampList(timestamp) + packed32(core) + packed32(key) + \ 4689935Sdam.sunwoo@arm.com packed64(value) 4699935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4709935Sdam.sunwoo@arm.com return ret 4719935Sdam.sunwoo@arm.com 4729935Sdam.sunwoo@arm.com# Block Counter frame message 4739935Sdam.sunwoo@arm.com# - key: packed32 4749935Sdam.sunwoo@arm.com# - value: packed64 4759935Sdam.sunwoo@arm.comdef blockCounterFrame(core, key, value): 4769935Sdam.sunwoo@arm.com frame_type = "Block Counter" 4779935Sdam.sunwoo@arm.com body = packed32(key) + packed64(value) 4789935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4799935Sdam.sunwoo@arm.com return ret 4809935Sdam.sunwoo@arm.com 4819935Sdam.sunwoo@arm.com# Annotate frame messages 4829935Sdam.sunwoo@arm.com# - core: packed32 4839935Sdam.sunwoo@arm.com# - tid: packed32 4849935Sdam.sunwoo@arm.com# - timestamp: timestamp 4859935Sdam.sunwoo@arm.com# - size: packed32 4869935Sdam.sunwoo@arm.com# - body 4879935Sdam.sunwoo@arm.comdef annotateFrame(core, tid, timestamp, size, userspace_body): 4889935Sdam.sunwoo@arm.com frame_type = "Annotate" 4899935Sdam.sunwoo@arm.com body = packed32(core) + packed32(tid) + timestampList(timestamp) + \ 4909935Sdam.sunwoo@arm.com packed32(size) + userspace_body 4919935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 4929935Sdam.sunwoo@arm.com return ret 4939935Sdam.sunwoo@arm.com 4949935Sdam.sunwoo@arm.com# Scheduler Trace frame messages 4959935Sdam.sunwoo@arm.com# Sched Switch 4969935Sdam.sunwoo@arm.com# - Code: 1 4979935Sdam.sunwoo@arm.com# - timestamp: timestamp 4989935Sdam.sunwoo@arm.com# - pid: packed32 4999935Sdam.sunwoo@arm.com# - tid: packed32 5009935Sdam.sunwoo@arm.com# - cookie: packed32 5019935Sdam.sunwoo@arm.com# - state: packed32 5029935Sdam.sunwoo@arm.comdef schedSwitchFrame(core, timestamp, pid, tid, cookie, state): 5039935Sdam.sunwoo@arm.com frame_type = "Sched Trace" 5049935Sdam.sunwoo@arm.com body = packed32(1) + timestampList(timestamp) + packed32(pid) + \ 5059935Sdam.sunwoo@arm.com packed32(tid) + packed32(cookie) + packed32(state) 5069935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 5079935Sdam.sunwoo@arm.com return ret 5089935Sdam.sunwoo@arm.com 5099935Sdam.sunwoo@arm.com# Sched Thread Exit 5109935Sdam.sunwoo@arm.com# - Code: 2 5119935Sdam.sunwoo@arm.com# - timestamp: timestamp 5129935Sdam.sunwoo@arm.com# - tid: packed32 5139935Sdam.sunwoo@arm.comdef schedThreadExitFrame(core, timestamp, pid, tid, cookie, state): 5149935Sdam.sunwoo@arm.com frame_type = "Sched Trace" 5159935Sdam.sunwoo@arm.com body = packed32(2) + timestampList(timestamp) + packed32(tid) 5169935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 5179935Sdam.sunwoo@arm.com return ret 5189935Sdam.sunwoo@arm.com 5199935Sdam.sunwoo@arm.com# GPU Trace frame messages 5209935Sdam.sunwoo@arm.com# - Not implemented yet 5219935Sdam.sunwoo@arm.comdef gpuTraceFrame(): 5229935Sdam.sunwoo@arm.com pass 5239935Sdam.sunwoo@arm.com 5249935Sdam.sunwoo@arm.com# Idle frame messages 5259935Sdam.sunwoo@arm.com# Enter Idle 5269935Sdam.sunwoo@arm.com# - code: 1 5279935Sdam.sunwoo@arm.com# - timestamp: timestamp 5289935Sdam.sunwoo@arm.com# - core: packed32 5299935Sdam.sunwoo@arm.comdef enterIdleFrame(timestamp, core): 5309935Sdam.sunwoo@arm.com frame_type = "Idle" 5319935Sdam.sunwoo@arm.com body = packed32(1) + timestampList(timestamp) + packed32(core) 5329935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 5339935Sdam.sunwoo@arm.com return ret 5349935Sdam.sunwoo@arm.com 5359935Sdam.sunwoo@arm.com# Exit Idle 5369935Sdam.sunwoo@arm.com# - code: 2 5379935Sdam.sunwoo@arm.com# - timestamp: timestamp 5389935Sdam.sunwoo@arm.com# - core: packed32 5399935Sdam.sunwoo@arm.comdef exitIdleFrame(timestamp, core): 5409935Sdam.sunwoo@arm.com frame_type = "Idle" 5419935Sdam.sunwoo@arm.com body = packed32(2) + timestampList(timestamp) + packed32(core) 5429935Sdam.sunwoo@arm.com ret = addFrameHeader(frame_type, body, core) 5439935Sdam.sunwoo@arm.com return ret 5449935Sdam.sunwoo@arm.com 5459935Sdam.sunwoo@arm.com 5469935Sdam.sunwoo@arm.com#################################################################### 5479935Sdam.sunwoo@arm.comdef parseProcessInfo(task_file): 5489935Sdam.sunwoo@arm.com print "\n===============================" 5499935Sdam.sunwoo@arm.com print "Parsing Task file..." 5509935Sdam.sunwoo@arm.com print task_file 5519935Sdam.sunwoo@arm.com print "===============================\n" 5529935Sdam.sunwoo@arm.com 5539935Sdam.sunwoo@arm.com global start_tick, end_tick, num_cpus 5549935Sdam.sunwoo@arm.com global process_dict, thread_dict, process_list 5559935Sdam.sunwoo@arm.com global event_list, unified_event_list 5569935Sdam.sunwoo@arm.com global idle_uid, kernel_uid 5579935Sdam.sunwoo@arm.com 5589935Sdam.sunwoo@arm.com event_list = [] 5599935Sdam.sunwoo@arm.com unified_event_list = [] 5609935Sdam.sunwoo@arm.com for cpu in range(num_cpus): 5619935Sdam.sunwoo@arm.com event_list.append([]) 5629935Sdam.sunwoo@arm.com 5639935Sdam.sunwoo@arm.com uid = 1 # uid 0 is reserved for idle 5649935Sdam.sunwoo@arm.com 5659935Sdam.sunwoo@arm.com # Dummy Tasks for frame buffers and system diagrams 5669935Sdam.sunwoo@arm.com process = Task(uid, 9999, 9999, "framebuffer", True, 0) 5679935Sdam.sunwoo@arm.com process_list.append(process) 5689935Sdam.sunwoo@arm.com uid += 1 5699935Sdam.sunwoo@arm.com thread = Task(uid, 9999, 9999, "framebuffer", False, 0) 5709935Sdam.sunwoo@arm.com process.children.append(thread) 5719935Sdam.sunwoo@arm.com uid += 1 5729935Sdam.sunwoo@arm.com process = Task(uid, 9998, 9998, "System", True, 0) 5739935Sdam.sunwoo@arm.com process_list.append(process) 5749935Sdam.sunwoo@arm.com # if we don't find the real kernel, use this to keep things going 5759935Sdam.sunwoo@arm.com kernel_uid = uid 5769935Sdam.sunwoo@arm.com uid += 1 5779935Sdam.sunwoo@arm.com thread = Task(uid, 9998, 9998, "System", False, 0) 5789935Sdam.sunwoo@arm.com process.children.append(thread) 5799935Sdam.sunwoo@arm.com uid += 1 5809935Sdam.sunwoo@arm.com 5819935Sdam.sunwoo@arm.com ext = os.path.splitext(task_file)[1] 5829935Sdam.sunwoo@arm.com 5839935Sdam.sunwoo@arm.com try: 5849935Sdam.sunwoo@arm.com if ext == ".gz": 5859935Sdam.sunwoo@arm.com process_file = gzip.open(task_file, 'rb') 5869935Sdam.sunwoo@arm.com else: 5879935Sdam.sunwoo@arm.com process_file = open(task_file, 'rb') 5889935Sdam.sunwoo@arm.com except: 5899935Sdam.sunwoo@arm.com print "ERROR opening task file:", task_file 5909935Sdam.sunwoo@arm.com print "Make sure context switch task dumping is enabled in gem5." 5919935Sdam.sunwoo@arm.com sys.exit(1) 5929935Sdam.sunwoo@arm.com 5939935Sdam.sunwoo@arm.com process_re = re.compile("tick=(\d+)\s+(\d+)\s+cpu_id=(\d+)\s+" + 5949935Sdam.sunwoo@arm.com "next_pid=([-\d]+)\s+next_tgid=([-\d]+)\s+next_task=(.*)") 5959935Sdam.sunwoo@arm.com 5969935Sdam.sunwoo@arm.com task_name_failure_warned = False 5979935Sdam.sunwoo@arm.com 5989935Sdam.sunwoo@arm.com for line in process_file: 5999935Sdam.sunwoo@arm.com match = re.match(process_re, line) 6009935Sdam.sunwoo@arm.com if match: 6019935Sdam.sunwoo@arm.com tick = int(match.group(1)) 6029935Sdam.sunwoo@arm.com if (start_tick < 0): 6039935Sdam.sunwoo@arm.com start_tick = tick 6049935Sdam.sunwoo@arm.com cpu_id = int(match.group(3)) 6059935Sdam.sunwoo@arm.com pid = int(match.group(4)) 6069935Sdam.sunwoo@arm.com tgid = int(match.group(5)) 6079935Sdam.sunwoo@arm.com task_name = match.group(6) 6089935Sdam.sunwoo@arm.com 6099935Sdam.sunwoo@arm.com if not task_name_failure_warned: 6109935Sdam.sunwoo@arm.com if task_name == "FailureIn_curTaskName": 6119935Sdam.sunwoo@arm.com print "-------------------------------------------------" 6129935Sdam.sunwoo@arm.com print "WARNING: Task name not set correctly!" 6139935Sdam.sunwoo@arm.com print "Process/Thread info will not be displayed correctly" 6149935Sdam.sunwoo@arm.com print "Perhaps forgot to apply m5struct.patch to kernel?" 6159935Sdam.sunwoo@arm.com print "-------------------------------------------------" 6169935Sdam.sunwoo@arm.com task_name_failure_warned = True 6179935Sdam.sunwoo@arm.com 6189935Sdam.sunwoo@arm.com if not tgid in process_dict: 6199935Sdam.sunwoo@arm.com if tgid == pid: 6209935Sdam.sunwoo@arm.com # new task is parent as well 6219935Sdam.sunwoo@arm.com if args.verbose: 6229935Sdam.sunwoo@arm.com print "new process", uid, pid, tgid, task_name 6239935Sdam.sunwoo@arm.com if tgid == 0: 6249935Sdam.sunwoo@arm.com # new process is the "idle" task 6259935Sdam.sunwoo@arm.com process = Task(uid, pid, tgid, "idle", True, tick) 6269935Sdam.sunwoo@arm.com idle_uid = 0 6279935Sdam.sunwoo@arm.com else: 6289935Sdam.sunwoo@arm.com process = Task(uid, pid, tgid, task_name, True, tick) 6299935Sdam.sunwoo@arm.com else: 6309935Sdam.sunwoo@arm.com if tgid == 0: 6319935Sdam.sunwoo@arm.com process = Task(uid, tgid, tgid, "idle", True, tick) 6329935Sdam.sunwoo@arm.com idle_uid = 0 6339935Sdam.sunwoo@arm.com else: 6349935Sdam.sunwoo@arm.com # parent process name not known yet 6359935Sdam.sunwoo@arm.com process = Task(uid, tgid, tgid, "_Unknown_", True, tick) 6369935Sdam.sunwoo@arm.com if tgid == -1: # kernel 6379935Sdam.sunwoo@arm.com kernel_uid = 0 6389935Sdam.sunwoo@arm.com uid += 1 6399935Sdam.sunwoo@arm.com process_dict[tgid] = process 6409935Sdam.sunwoo@arm.com process_list.append(process) 6419935Sdam.sunwoo@arm.com else: 6429935Sdam.sunwoo@arm.com if tgid == pid: 6439935Sdam.sunwoo@arm.com if process_dict[tgid].task_name == "_Unknown_": 6449935Sdam.sunwoo@arm.com if args.verbose: 6459935Sdam.sunwoo@arm.com print "new process", \ 6469935Sdam.sunwoo@arm.com process_dict[tgid].uid, pid, tgid, task_name 6479935Sdam.sunwoo@arm.com process_dict[tgid].task_name = task_name 6489935Sdam.sunwoo@arm.com if process_dict[tgid].task_name != task_name and tgid != 0: 6499935Sdam.sunwoo@arm.com process_dict[tgid].task_name = task_name 6509935Sdam.sunwoo@arm.com 6519935Sdam.sunwoo@arm.com if not pid in thread_dict: 6529935Sdam.sunwoo@arm.com if args.verbose: 6539935Sdam.sunwoo@arm.com print "new thread", \ 6549935Sdam.sunwoo@arm.com uid, process_dict[tgid].uid, pid, tgid, task_name 6559935Sdam.sunwoo@arm.com thread = Task(uid, pid, tgid, task_name, False, tick) 6569935Sdam.sunwoo@arm.com uid += 1 6579935Sdam.sunwoo@arm.com thread_dict[pid] = thread 6589935Sdam.sunwoo@arm.com process_dict[tgid].children.append(thread) 6599935Sdam.sunwoo@arm.com else: 6609935Sdam.sunwoo@arm.com if thread_dict[pid].task_name != task_name: 6619935Sdam.sunwoo@arm.com thread_dict[pid].task_name = task_name 6629935Sdam.sunwoo@arm.com 6639935Sdam.sunwoo@arm.com if args.verbose: 6649935Sdam.sunwoo@arm.com print tick, uid, cpu_id, pid, tgid, task_name 6659935Sdam.sunwoo@arm.com 6669935Sdam.sunwoo@arm.com task = thread_dict[pid] 6679935Sdam.sunwoo@arm.com event = Event(tick, task) 6689935Sdam.sunwoo@arm.com event_list[cpu_id].append(event) 6699935Sdam.sunwoo@arm.com unified_event_list.append(event) 6709935Sdam.sunwoo@arm.com 6719935Sdam.sunwoo@arm.com if len(unified_event_list) == num_events: 6729935Sdam.sunwoo@arm.com print "Truncating at", num_events, "events!" 6739935Sdam.sunwoo@arm.com break 6749935Sdam.sunwoo@arm.com print "Found %d events." % len(unified_event_list) 6759935Sdam.sunwoo@arm.com 6769935Sdam.sunwoo@arm.com for process in process_list: 6779935Sdam.sunwoo@arm.com if process.pid > 9990: # fix up framebuffer ticks 6789935Sdam.sunwoo@arm.com process.tick = start_tick 6799935Sdam.sunwoo@arm.com print process.uid, process.pid, process.tgid, \ 6809935Sdam.sunwoo@arm.com process.task_name, str(process.tick) 6819935Sdam.sunwoo@arm.com for thread in process.children: 6829935Sdam.sunwoo@arm.com if thread.pid > 9990: 6839935Sdam.sunwoo@arm.com thread.tick = start_tick 6849935Sdam.sunwoo@arm.com print "\t", thread.uid, thread.pid, thread.tgid, \ 6859935Sdam.sunwoo@arm.com thread.task_name, str(thread.tick) 6869935Sdam.sunwoo@arm.com 6879935Sdam.sunwoo@arm.com end_tick = tick 6889935Sdam.sunwoo@arm.com 6899935Sdam.sunwoo@arm.com print "Start tick:", start_tick 6909935Sdam.sunwoo@arm.com print "End tick: ", end_tick 6919935Sdam.sunwoo@arm.com print "" 6929935Sdam.sunwoo@arm.com 6939935Sdam.sunwoo@arm.com return 6949935Sdam.sunwoo@arm.com 6959935Sdam.sunwoo@arm.com 6969935Sdam.sunwoo@arm.comdef initOutput(output_path): 6979935Sdam.sunwoo@arm.com if not os.path.exists(output_path): 6989935Sdam.sunwoo@arm.com os.mkdir(output_path) 6999935Sdam.sunwoo@arm.com 7009935Sdam.sunwoo@arm.comdef ticksToNs(tick): 7019935Sdam.sunwoo@arm.com if ticks_in_ns < 0: 7029935Sdam.sunwoo@arm.com print "ticks_in_ns not set properly!" 7039935Sdam.sunwoo@arm.com sys.exit(1) 7049935Sdam.sunwoo@arm.com 7059935Sdam.sunwoo@arm.com return tick / ticks_in_ns 7069935Sdam.sunwoo@arm.com 7079935Sdam.sunwoo@arm.comdef writeXmlFile(xml, filename): 7089935Sdam.sunwoo@arm.com f = open(filename, "w") 7099935Sdam.sunwoo@arm.com txt = ET.tostring(xml) 7109935Sdam.sunwoo@arm.com f.write(minidom.parseString(txt).toprettyxml()) 7119935Sdam.sunwoo@arm.com f.close() 7129935Sdam.sunwoo@arm.com 7139935Sdam.sunwoo@arm.com 7149935Sdam.sunwoo@arm.com# StatsEntry that contains individual statistics 7159935Sdam.sunwoo@arm.comclass StatsEntry(object): 71610354Sdam.sunwoo@arm.com def __init__(self, name, group, group_index, per_cpu, key): 7179935Sdam.sunwoo@arm.com 7189935Sdam.sunwoo@arm.com # Full name of statistics 7199935Sdam.sunwoo@arm.com self.name = name 7209935Sdam.sunwoo@arm.com 7219935Sdam.sunwoo@arm.com # Streamline group name that statistic will belong to 7229935Sdam.sunwoo@arm.com self.group = group 7239935Sdam.sunwoo@arm.com 7249935Sdam.sunwoo@arm.com # Index of statistics within group (used to change colors within groups) 7259935Sdam.sunwoo@arm.com self.group_index = group_index 7269935Sdam.sunwoo@arm.com 7279935Sdam.sunwoo@arm.com # Shorter name with "system" stripped off 7289935Sdam.sunwoo@arm.com # and symbols converted to alphanumerics 7299935Sdam.sunwoo@arm.com self.short_name = re.sub("system\.", "", name) 7309935Sdam.sunwoo@arm.com self.short_name = re.sub(":", "_", name) 7319935Sdam.sunwoo@arm.com 7329935Sdam.sunwoo@arm.com # Regex for this stat (string version used to construct union regex) 7339935Sdam.sunwoo@arm.com self.regex_string = "^" + name + "\s+([\d\.]+)" 7349935Sdam.sunwoo@arm.com self.regex = re.compile("^" + name + "\s+([\d\.e\-]+)\s+# (.*)$", re.M) 7359935Sdam.sunwoo@arm.com self.description = "" 7369935Sdam.sunwoo@arm.com 7379935Sdam.sunwoo@arm.com # Whether this stat is use per CPU or not 7389935Sdam.sunwoo@arm.com self.per_cpu = per_cpu 7399935Sdam.sunwoo@arm.com 7409935Sdam.sunwoo@arm.com # Key used in .apc protocol (as described in captured.xml) 7419935Sdam.sunwoo@arm.com self.key = key 7429935Sdam.sunwoo@arm.com 7439935Sdam.sunwoo@arm.com # List of values of stat per timestamp 7449935Sdam.sunwoo@arm.com self.values = [] 7459935Sdam.sunwoo@arm.com 7469935Sdam.sunwoo@arm.com # Whether this stat has been found for the current timestamp 7479935Sdam.sunwoo@arm.com self.found = False 7489935Sdam.sunwoo@arm.com 7499935Sdam.sunwoo@arm.com # Whether this stat has been found at least once 7509935Sdam.sunwoo@arm.com # (to suppress too many warnings) 7519935Sdam.sunwoo@arm.com self.not_found_at_least_once = False 7529935Sdam.sunwoo@arm.com 7539935Sdam.sunwoo@arm.com # Field used to hold ElementTree subelement for this stat 7549935Sdam.sunwoo@arm.com self.ET_element = None 7559935Sdam.sunwoo@arm.com 7569935Sdam.sunwoo@arm.com # Create per-CPU stat name and regex, etc. 7579935Sdam.sunwoo@arm.com if self.per_cpu: 7589935Sdam.sunwoo@arm.com self.per_cpu_regex_string = [] 7599935Sdam.sunwoo@arm.com self.per_cpu_regex = [] 7609935Sdam.sunwoo@arm.com self.per_cpu_name = [] 7619935Sdam.sunwoo@arm.com self.per_cpu_found = [] 7629935Sdam.sunwoo@arm.com for i in range(num_cpus): 76310354Sdam.sunwoo@arm.com if num_cpus > 1: 76410354Sdam.sunwoo@arm.com per_cpu_name = re.sub("#", str(i), self.name) 7659935Sdam.sunwoo@arm.com else: 76610354Sdam.sunwoo@arm.com per_cpu_name = re.sub("#", "", self.name) 7679935Sdam.sunwoo@arm.com 7689935Sdam.sunwoo@arm.com self.per_cpu_name.append(per_cpu_name) 7699935Sdam.sunwoo@arm.com print "\t", per_cpu_name 7709935Sdam.sunwoo@arm.com 7719935Sdam.sunwoo@arm.com self.per_cpu_regex_string.\ 7729935Sdam.sunwoo@arm.com append("^" + per_cpu_name + "\s+[\d\.]+") 7739935Sdam.sunwoo@arm.com self.per_cpu_regex.append(re.compile("^" + per_cpu_name + \ 7749935Sdam.sunwoo@arm.com "\s+([\d\.e\-]+)\s+# (.*)$", re.M)) 7759935Sdam.sunwoo@arm.com self.values.append([]) 7769935Sdam.sunwoo@arm.com self.per_cpu_found.append(False) 7779935Sdam.sunwoo@arm.com 7789935Sdam.sunwoo@arm.com def append_value(self, val, per_cpu_index = None): 7799935Sdam.sunwoo@arm.com if self.per_cpu: 7809935Sdam.sunwoo@arm.com self.values[per_cpu_index].append(str(val)) 7819935Sdam.sunwoo@arm.com else: 7829935Sdam.sunwoo@arm.com self.values.append(str(val)) 7839935Sdam.sunwoo@arm.com 7849935Sdam.sunwoo@arm.com# Global stats object that contains the list of stats entries 7859935Sdam.sunwoo@arm.com# and other utility functions 7869935Sdam.sunwoo@arm.comclass Stats(object): 7879935Sdam.sunwoo@arm.com def __init__(self): 7889935Sdam.sunwoo@arm.com self.stats_list = [] 7899935Sdam.sunwoo@arm.com self.tick_list = [] 7909935Sdam.sunwoo@arm.com self.next_key = 1 7919935Sdam.sunwoo@arm.com 79210354Sdam.sunwoo@arm.com def register(self, name, group, group_index, per_cpu): 7939935Sdam.sunwoo@arm.com print "registering stat:", name, "group:", group, group_index 7949935Sdam.sunwoo@arm.com self.stats_list.append(StatsEntry(name, group, group_index, per_cpu, \ 79510354Sdam.sunwoo@arm.com self.next_key)) 7969935Sdam.sunwoo@arm.com self.next_key += 1 7979935Sdam.sunwoo@arm.com 7989935Sdam.sunwoo@arm.com # Union of all stats to accelerate parsing speed 7999935Sdam.sunwoo@arm.com def createStatsRegex(self): 8009935Sdam.sunwoo@arm.com regex_strings = []; 8019935Sdam.sunwoo@arm.com print "\nnum entries in stats_list", len(self.stats_list) 8029935Sdam.sunwoo@arm.com for entry in self.stats_list: 8039935Sdam.sunwoo@arm.com if entry.per_cpu: 8049935Sdam.sunwoo@arm.com for i in range(num_cpus): 8059935Sdam.sunwoo@arm.com regex_strings.append(entry.per_cpu_regex_string[i]) 8069935Sdam.sunwoo@arm.com else: 8079935Sdam.sunwoo@arm.com regex_strings.append(entry.regex_string) 8089935Sdam.sunwoo@arm.com 8099935Sdam.sunwoo@arm.com self.regex = re.compile('|'.join(regex_strings)) 8109935Sdam.sunwoo@arm.com 8119935Sdam.sunwoo@arm.com 8129935Sdam.sunwoo@arm.comdef registerStats(config_file): 8139935Sdam.sunwoo@arm.com print "===============================" 8149935Sdam.sunwoo@arm.com print "Parsing stats config.ini file..." 8159935Sdam.sunwoo@arm.com print config_file 8169935Sdam.sunwoo@arm.com print "===============================" 8179935Sdam.sunwoo@arm.com 8189935Sdam.sunwoo@arm.com config = ConfigParser() 8199935Sdam.sunwoo@arm.com if not config.read(config_file): 8209935Sdam.sunwoo@arm.com print "ERROR: config file '", config_file, "' not found!" 8219935Sdam.sunwoo@arm.com sys.exit(1) 8229935Sdam.sunwoo@arm.com 8239935Sdam.sunwoo@arm.com print "\nRegistering Stats..." 8249935Sdam.sunwoo@arm.com 8259935Sdam.sunwoo@arm.com stats = Stats() 8269935Sdam.sunwoo@arm.com 8279935Sdam.sunwoo@arm.com per_cpu_stat_groups = config.options('PER_CPU_STATS') 8289935Sdam.sunwoo@arm.com for group in per_cpu_stat_groups: 8299935Sdam.sunwoo@arm.com i = 0 8309935Sdam.sunwoo@arm.com per_cpu_stats_list = config.get('PER_CPU_STATS', group).split('\n') 8319935Sdam.sunwoo@arm.com for item in per_cpu_stats_list: 8329935Sdam.sunwoo@arm.com if item: 83310354Sdam.sunwoo@arm.com stats.register(item, group, i, True) 8349935Sdam.sunwoo@arm.com i += 1 8359935Sdam.sunwoo@arm.com 8369935Sdam.sunwoo@arm.com per_l2_stat_groups = config.options('PER_L2_STATS') 8379935Sdam.sunwoo@arm.com for group in per_l2_stat_groups: 8389935Sdam.sunwoo@arm.com i = 0 8399935Sdam.sunwoo@arm.com per_l2_stats_list = config.get('PER_L2_STATS', group).split('\n') 8409935Sdam.sunwoo@arm.com for item in per_l2_stats_list: 8419935Sdam.sunwoo@arm.com if item: 8429935Sdam.sunwoo@arm.com for l2 in range(num_l2): 8439935Sdam.sunwoo@arm.com if num_l2 > 1: 84410354Sdam.sunwoo@arm.com name = re.sub("#", str(l2), item) 84510354Sdam.sunwoo@arm.com else: 84610354Sdam.sunwoo@arm.com name = re.sub("#", "", item) 84710354Sdam.sunwoo@arm.com stats.register(name, group, i, False) 8489935Sdam.sunwoo@arm.com i += 1 8499935Sdam.sunwoo@arm.com 8509935Sdam.sunwoo@arm.com other_stat_groups = config.options('OTHER_STATS') 8519935Sdam.sunwoo@arm.com for group in other_stat_groups: 8529935Sdam.sunwoo@arm.com i = 0 8539935Sdam.sunwoo@arm.com other_stats_list = config.get('OTHER_STATS', group).split('\n') 8549935Sdam.sunwoo@arm.com for item in other_stats_list: 8559935Sdam.sunwoo@arm.com if item: 85610354Sdam.sunwoo@arm.com stats.register(item, group, i, False) 8579935Sdam.sunwoo@arm.com i += 1 8589935Sdam.sunwoo@arm.com 8599935Sdam.sunwoo@arm.com stats.createStatsRegex() 8609935Sdam.sunwoo@arm.com 8619935Sdam.sunwoo@arm.com return stats 8629935Sdam.sunwoo@arm.com 8639935Sdam.sunwoo@arm.com# Parse and read in gem5 stats file 8649935Sdam.sunwoo@arm.com# Streamline counters are organized per CPU 8659935Sdam.sunwoo@arm.comdef readGem5Stats(stats, gem5_stats_file): 8669935Sdam.sunwoo@arm.com print "\n===============================" 8679935Sdam.sunwoo@arm.com print "Parsing gem5 stats file..." 8689935Sdam.sunwoo@arm.com print gem5_stats_file 8699935Sdam.sunwoo@arm.com print "===============================\n" 8709935Sdam.sunwoo@arm.com ext = os.path.splitext(gem5_stats_file)[1] 8719935Sdam.sunwoo@arm.com 8729935Sdam.sunwoo@arm.com window_start_regex = \ 8739935Sdam.sunwoo@arm.com re.compile("^---------- Begin Simulation Statistics ----------") 8749935Sdam.sunwoo@arm.com window_end_regex = \ 8759935Sdam.sunwoo@arm.com re.compile("^---------- End Simulation Statistics ----------") 8769935Sdam.sunwoo@arm.com final_tick_regex = re.compile("^final_tick\s+(\d+)") 8779935Sdam.sunwoo@arm.com 8789935Sdam.sunwoo@arm.com global ticks_in_ns 8799935Sdam.sunwoo@arm.com sim_freq_regex = re.compile("^sim_freq\s+(\d+)") 8809935Sdam.sunwoo@arm.com sim_freq = -1 8819935Sdam.sunwoo@arm.com 8829935Sdam.sunwoo@arm.com try: 8839935Sdam.sunwoo@arm.com if ext == ".gz": 8849935Sdam.sunwoo@arm.com f = gzip.open(gem5_stats_file, "r") 8859935Sdam.sunwoo@arm.com else: 8869935Sdam.sunwoo@arm.com f = open(gem5_stats_file, "r") 8879935Sdam.sunwoo@arm.com except: 8889935Sdam.sunwoo@arm.com print "ERROR opening stats file", gem5_stats_file, "!" 8899935Sdam.sunwoo@arm.com sys.exit(1) 8909935Sdam.sunwoo@arm.com 8919935Sdam.sunwoo@arm.com stats_not_found_list = stats.stats_list[:] 8929935Sdam.sunwoo@arm.com window_num = 0 8939935Sdam.sunwoo@arm.com 8949935Sdam.sunwoo@arm.com while (True): 8959935Sdam.sunwoo@arm.com error = False 8969935Sdam.sunwoo@arm.com try: 8979935Sdam.sunwoo@arm.com line = f.readline() 8989935Sdam.sunwoo@arm.com except IOError: 8999935Sdam.sunwoo@arm.com print "" 9009935Sdam.sunwoo@arm.com print "WARNING: IO error in stats file" 9019935Sdam.sunwoo@arm.com print "(gzip stream not closed properly?)...continuing for now" 9029935Sdam.sunwoo@arm.com error = True 9039935Sdam.sunwoo@arm.com if not line: 9049935Sdam.sunwoo@arm.com break 9059935Sdam.sunwoo@arm.com 9069935Sdam.sunwoo@arm.com # Find out how many gem5 ticks in 1ns 9079935Sdam.sunwoo@arm.com if sim_freq < 0: 9089935Sdam.sunwoo@arm.com m = sim_freq_regex.match(line) 9099935Sdam.sunwoo@arm.com if m: 9109935Sdam.sunwoo@arm.com sim_freq = int(m.group(1)) # ticks in 1 sec 9119935Sdam.sunwoo@arm.com ticks_in_ns = int(sim_freq / 1e9) 9129935Sdam.sunwoo@arm.com print "Simulation frequency found! 1 tick == %e sec\n" \ 9139935Sdam.sunwoo@arm.com % (1.0 / sim_freq) 9149935Sdam.sunwoo@arm.com 9159935Sdam.sunwoo@arm.com # Final tick in gem5 stats: current absolute timestamp 9169935Sdam.sunwoo@arm.com m = final_tick_regex.match(line) 9179935Sdam.sunwoo@arm.com if m: 9189935Sdam.sunwoo@arm.com tick = int(m.group(1)) 9199935Sdam.sunwoo@arm.com if tick > end_tick: 9209935Sdam.sunwoo@arm.com break 9219935Sdam.sunwoo@arm.com stats.tick_list.append(tick) 9229935Sdam.sunwoo@arm.com 9239935Sdam.sunwoo@arm.com 9249935Sdam.sunwoo@arm.com if (window_end_regex.match(line) or error): 9259935Sdam.sunwoo@arm.com if args.verbose: 9269935Sdam.sunwoo@arm.com print "new window" 9279935Sdam.sunwoo@arm.com for stat in stats.stats_list: 9289935Sdam.sunwoo@arm.com if stat.per_cpu: 9299935Sdam.sunwoo@arm.com for i in range(num_cpus): 9309935Sdam.sunwoo@arm.com if not stat.per_cpu_found[i]: 9319935Sdam.sunwoo@arm.com if not stat.not_found_at_least_once: 9329935Sdam.sunwoo@arm.com print "WARNING: stat not found in window #", \ 9339935Sdam.sunwoo@arm.com window_num, ":", stat.per_cpu_name[i] 9349935Sdam.sunwoo@arm.com print "suppressing further warnings for " + \ 9359935Sdam.sunwoo@arm.com "this stat" 9369935Sdam.sunwoo@arm.com stat.not_found_at_least_once = True 9379935Sdam.sunwoo@arm.com stat.values[i].append(str(0)) 9389935Sdam.sunwoo@arm.com stat.per_cpu_found[i] = False 9399935Sdam.sunwoo@arm.com else: 9409935Sdam.sunwoo@arm.com if not stat.found: 9419935Sdam.sunwoo@arm.com if not stat.not_found_at_least_once: 9429935Sdam.sunwoo@arm.com print "WARNING: stat not found in window #", \ 9439935Sdam.sunwoo@arm.com window_num, ":", stat.name 9449935Sdam.sunwoo@arm.com print "suppressing further warnings for this stat" 9459935Sdam.sunwoo@arm.com stat.not_found_at_least_once = True 9469935Sdam.sunwoo@arm.com stat.values.append(str(0)) 9479935Sdam.sunwoo@arm.com stat.found = False 9489935Sdam.sunwoo@arm.com stats_not_found_list = stats.stats_list[:] 9499935Sdam.sunwoo@arm.com window_num += 1 9509935Sdam.sunwoo@arm.com if error: 9519935Sdam.sunwoo@arm.com break 9529935Sdam.sunwoo@arm.com 9539935Sdam.sunwoo@arm.com # Do a single regex of the union of all stats first for speed 9549935Sdam.sunwoo@arm.com if stats.regex.match(line): 9559935Sdam.sunwoo@arm.com # Then loop through only the stats we haven't seen in this window 9569935Sdam.sunwoo@arm.com for stat in stats_not_found_list[:]: 9579935Sdam.sunwoo@arm.com if stat.per_cpu: 9589935Sdam.sunwoo@arm.com for i in range(num_cpus): 9599935Sdam.sunwoo@arm.com m = stat.per_cpu_regex[i].match(line) 9609935Sdam.sunwoo@arm.com if m: 9619935Sdam.sunwoo@arm.com if stat.name == "ipc": 9629935Sdam.sunwoo@arm.com value = str(int(float(m.group(1)) * 1000)) 9639935Sdam.sunwoo@arm.com else: 9649935Sdam.sunwoo@arm.com value = str(int(float(m.group(1)))) 9659935Sdam.sunwoo@arm.com if args.verbose: 9669935Sdam.sunwoo@arm.com print stat.per_cpu_name[i], value 9679935Sdam.sunwoo@arm.com stat.values[i].append(value) 9689935Sdam.sunwoo@arm.com stat.per_cpu_found[i] = True 9699935Sdam.sunwoo@arm.com all_found = True 9709935Sdam.sunwoo@arm.com for j in range(num_cpus): 9719935Sdam.sunwoo@arm.com if not stat.per_cpu_found[j]: 9729935Sdam.sunwoo@arm.com all_found = False 9739935Sdam.sunwoo@arm.com if all_found: 9749935Sdam.sunwoo@arm.com stats_not_found_list.remove(stat) 9759935Sdam.sunwoo@arm.com if stat.description == "": 9769935Sdam.sunwoo@arm.com stat.description = m.group(2) 9779935Sdam.sunwoo@arm.com else: 9789935Sdam.sunwoo@arm.com m = stat.regex.match(line) 9799935Sdam.sunwoo@arm.com if m: 9809935Sdam.sunwoo@arm.com value = str(int(float(m.group(1)))) 9819935Sdam.sunwoo@arm.com if args.verbose: 9829935Sdam.sunwoo@arm.com print stat.name, value 9839935Sdam.sunwoo@arm.com stat.values.append(value) 9849935Sdam.sunwoo@arm.com stat.found = True 9859935Sdam.sunwoo@arm.com stats_not_found_list.remove(stat) 9869935Sdam.sunwoo@arm.com if stat.description == "": 9879935Sdam.sunwoo@arm.com stat.description = m.group(2) 9889935Sdam.sunwoo@arm.com f.close() 9899935Sdam.sunwoo@arm.com 9909935Sdam.sunwoo@arm.com 9919935Sdam.sunwoo@arm.com# Create session.xml file in .apc folder 9929935Sdam.sunwoo@arm.comdef doSessionXML(output_path): 9939935Sdam.sunwoo@arm.com session_file = output_path + "/session.xml" 9949935Sdam.sunwoo@arm.com 9959935Sdam.sunwoo@arm.com xml = ET.Element("session") 9969935Sdam.sunwoo@arm.com 9979935Sdam.sunwoo@arm.com xml.set("version", "1") 9989935Sdam.sunwoo@arm.com xml.set("call_stack_unwinding", "no") 9999935Sdam.sunwoo@arm.com xml.set("parse_debug_info", "no") 10009935Sdam.sunwoo@arm.com xml.set("high_resolution", "yes") 10019935Sdam.sunwoo@arm.com xml.set("buffer_mode", "streaming") 10029935Sdam.sunwoo@arm.com xml.set("sample_rate", "low") 10039935Sdam.sunwoo@arm.com 10049935Sdam.sunwoo@arm.com # Setting duration to zero for now. Doesn't affect visualization. 10059935Sdam.sunwoo@arm.com xml.set("duration", "0") 10069935Sdam.sunwoo@arm.com 10079935Sdam.sunwoo@arm.com xml.set("target_host", "") 10089935Sdam.sunwoo@arm.com xml.set("target_port", "8080") 10099935Sdam.sunwoo@arm.com 10109935Sdam.sunwoo@arm.com writeXmlFile(xml, session_file) 10119935Sdam.sunwoo@arm.com 10129935Sdam.sunwoo@arm.com 10139935Sdam.sunwoo@arm.com# Create captured.xml file in .apc folder 10149935Sdam.sunwoo@arm.comdef doCapturedXML(output_path, stats): 10159935Sdam.sunwoo@arm.com captured_file = output_path + "/captured.xml" 10169935Sdam.sunwoo@arm.com 10179935Sdam.sunwoo@arm.com xml = ET.Element("captured") 10189935Sdam.sunwoo@arm.com xml.set("version", "1") 101910016Sdam.sunwoo@arm.com xml.set("protocol", "17") 102010016Sdam.sunwoo@arm.com xml.set("backtrace_processing", "none") 10219935Sdam.sunwoo@arm.com 10229935Sdam.sunwoo@arm.com target = ET.SubElement(xml, "target") 10239935Sdam.sunwoo@arm.com target.set("name", "gem5") 10249935Sdam.sunwoo@arm.com target.set("sample_rate", "1000") 10259935Sdam.sunwoo@arm.com target.set("cores", str(num_cpus)) 10269935Sdam.sunwoo@arm.com 10279935Sdam.sunwoo@arm.com counters = ET.SubElement(xml, "counters") 10289935Sdam.sunwoo@arm.com for stat in stats.stats_list: 10299935Sdam.sunwoo@arm.com s = ET.SubElement(counters, "counter") 10309935Sdam.sunwoo@arm.com stat_name = re.sub("\.", "_", stat.short_name) 103110354Sdam.sunwoo@arm.com stat_name = re.sub("#", "", stat_name) 10329935Sdam.sunwoo@arm.com s.set("title", stat.group) 10339935Sdam.sunwoo@arm.com s.set("name", stat_name) 10349935Sdam.sunwoo@arm.com s.set("color", "0x00000000") 10359935Sdam.sunwoo@arm.com s.set("key", "0x%08x" % stat.key) 10369935Sdam.sunwoo@arm.com s.set("type", stat_name) 10379935Sdam.sunwoo@arm.com s.set("event", "0x00000000") 10389935Sdam.sunwoo@arm.com if stat.per_cpu: 10399935Sdam.sunwoo@arm.com s.set("per_cpu", "yes") 10409935Sdam.sunwoo@arm.com else: 10419935Sdam.sunwoo@arm.com s.set("per_cpu", "no") 10429935Sdam.sunwoo@arm.com s.set("display", "") 10439935Sdam.sunwoo@arm.com s.set("units", "") 10449935Sdam.sunwoo@arm.com s.set("average_selection", "no") 10459935Sdam.sunwoo@arm.com s.set("description", stat.description) 10469935Sdam.sunwoo@arm.com 10479935Sdam.sunwoo@arm.com writeXmlFile(xml, captured_file) 10489935Sdam.sunwoo@arm.com 10499935Sdam.sunwoo@arm.com# Writes out Streamline cookies (unique IDs per process/thread) 10509935Sdam.sunwoo@arm.comdef writeCookiesThreads(blob): 10519935Sdam.sunwoo@arm.com thread_list = [] 10529935Sdam.sunwoo@arm.com for process in process_list: 10539935Sdam.sunwoo@arm.com if process.uid > 0: 10549935Sdam.sunwoo@arm.com print "cookie", process.task_name, process.uid 10559935Sdam.sunwoo@arm.com writeBinary(blob, cookieNameFrame(process.uid, process.task_name)) 10569935Sdam.sunwoo@arm.com 10579935Sdam.sunwoo@arm.com # pid and tgid need to be positive values -- no longer true? 10589935Sdam.sunwoo@arm.com for thread in process.children: 10599935Sdam.sunwoo@arm.com thread_list.append(thread) 10609935Sdam.sunwoo@arm.com 10619935Sdam.sunwoo@arm.com # Threads need to be sorted in timestamp order 10629935Sdam.sunwoo@arm.com thread_list.sort(key = lambda x: x.tick) 10639935Sdam.sunwoo@arm.com for thread in thread_list: 10649935Sdam.sunwoo@arm.com print "thread", thread.task_name, (ticksToNs(thread.tick)),\ 10659935Sdam.sunwoo@arm.com thread.tgid, thread.pid 10669935Sdam.sunwoo@arm.com writeBinary(blob, threadNameFrame(ticksToNs(thread.tick),\ 10679935Sdam.sunwoo@arm.com thread.pid, thread.task_name)) 10689935Sdam.sunwoo@arm.com 10699935Sdam.sunwoo@arm.com# Writes context switch info as Streamline scheduling events 10709935Sdam.sunwoo@arm.comdef writeSchedEvents(blob): 10719935Sdam.sunwoo@arm.com for cpu in range(num_cpus): 10729935Sdam.sunwoo@arm.com for event in event_list[cpu]: 10739935Sdam.sunwoo@arm.com timestamp = ticksToNs(event.tick) 10749935Sdam.sunwoo@arm.com pid = event.task.tgid 10759935Sdam.sunwoo@arm.com tid = event.task.pid 10769935Sdam.sunwoo@arm.com if process_dict.has_key(event.task.tgid): 10779935Sdam.sunwoo@arm.com cookie = process_dict[event.task.tgid].uid 10789935Sdam.sunwoo@arm.com else: 10799935Sdam.sunwoo@arm.com cookie = 0 10809935Sdam.sunwoo@arm.com 10819935Sdam.sunwoo@arm.com # State: 10829935Sdam.sunwoo@arm.com # 0: waiting on other event besides I/O 10839935Sdam.sunwoo@arm.com # 1: Contention/pre-emption 10849935Sdam.sunwoo@arm.com # 2: Waiting on I/O 10859935Sdam.sunwoo@arm.com # 3: Waiting on mutex 10869935Sdam.sunwoo@arm.com # Hardcoding to 0 for now. Other states not implemented yet. 10879935Sdam.sunwoo@arm.com state = 0 10889935Sdam.sunwoo@arm.com 10899935Sdam.sunwoo@arm.com if args.verbose: 10909935Sdam.sunwoo@arm.com print cpu, timestamp, pid, tid, cookie 10919935Sdam.sunwoo@arm.com 10929935Sdam.sunwoo@arm.com writeBinary(blob,\ 10939935Sdam.sunwoo@arm.com schedSwitchFrame(cpu, timestamp, pid, tid, cookie, state)) 10949935Sdam.sunwoo@arm.com 10959935Sdam.sunwoo@arm.com# Writes selected gem5 statistics as Streamline counters 10969935Sdam.sunwoo@arm.comdef writeCounters(blob, stats): 10979935Sdam.sunwoo@arm.com timestamp_list = [] 10989935Sdam.sunwoo@arm.com for tick in stats.tick_list: 10999935Sdam.sunwoo@arm.com if tick > end_tick: 11009935Sdam.sunwoo@arm.com break 11019935Sdam.sunwoo@arm.com timestamp_list.append(ticksToNs(tick)) 11029935Sdam.sunwoo@arm.com 11039935Sdam.sunwoo@arm.com for stat in stats.stats_list: 11049935Sdam.sunwoo@arm.com if stat.per_cpu: 11059935Sdam.sunwoo@arm.com stat_length = len(stat.values[0]) 11069935Sdam.sunwoo@arm.com else: 11079935Sdam.sunwoo@arm.com stat_length = len(stat.values) 11089935Sdam.sunwoo@arm.com 11099935Sdam.sunwoo@arm.com for n in range(len(timestamp_list)): 11109935Sdam.sunwoo@arm.com for stat in stats.stats_list: 11119935Sdam.sunwoo@arm.com if stat.per_cpu: 11129935Sdam.sunwoo@arm.com for i in range(num_cpus): 11139935Sdam.sunwoo@arm.com writeBinary(blob, counterFrame(timestamp_list[n], i, \ 11149935Sdam.sunwoo@arm.com stat.key, int(float(stat.values[i][n])))) 11159935Sdam.sunwoo@arm.com else: 11169935Sdam.sunwoo@arm.com writeBinary(blob, counterFrame(timestamp_list[n], 0, \ 11179935Sdam.sunwoo@arm.com stat.key, int(float(stat.values[n])))) 11189935Sdam.sunwoo@arm.com 11199935Sdam.sunwoo@arm.com# Streamline can display LCD frame buffer dumps (gzipped bmp) 11209935Sdam.sunwoo@arm.com# This function converts the frame buffer dumps to the Streamline format 11219935Sdam.sunwoo@arm.comdef writeVisualAnnotations(blob, input_path, output_path): 11229935Sdam.sunwoo@arm.com frame_path = input_path + "/frames_system.vncserver" 11239935Sdam.sunwoo@arm.com if not os.path.exists(frame_path): 11249935Sdam.sunwoo@arm.com return 11259935Sdam.sunwoo@arm.com 11269935Sdam.sunwoo@arm.com frame_count = 0 11279935Sdam.sunwoo@arm.com file_list = os.listdir(frame_path) 11289935Sdam.sunwoo@arm.com file_list.sort() 11299935Sdam.sunwoo@arm.com re_fb = re.compile("fb\.(\d+)\.(\d+)\.bmp.gz") 11309935Sdam.sunwoo@arm.com 11319935Sdam.sunwoo@arm.com # Use first non-negative pid to tag visual annotations 11329935Sdam.sunwoo@arm.com annotate_pid = -1 11339935Sdam.sunwoo@arm.com for e in unified_event_list: 11349935Sdam.sunwoo@arm.com pid = e.task.pid 11359935Sdam.sunwoo@arm.com if pid >= 0: 11369935Sdam.sunwoo@arm.com annotate_pid = pid 11379935Sdam.sunwoo@arm.com break 11389935Sdam.sunwoo@arm.com 11399935Sdam.sunwoo@arm.com for fn in file_list: 11409935Sdam.sunwoo@arm.com m = re_fb.match(fn) 11419935Sdam.sunwoo@arm.com if m: 11429935Sdam.sunwoo@arm.com seq = m.group(1) 11439935Sdam.sunwoo@arm.com tick = int(m.group(2)) 11449935Sdam.sunwoo@arm.com if tick > end_tick: 11459935Sdam.sunwoo@arm.com break 11469935Sdam.sunwoo@arm.com frame_count += 1 11479935Sdam.sunwoo@arm.com 11489935Sdam.sunwoo@arm.com userspace_body = [] 11499935Sdam.sunwoo@arm.com userspace_body += packed32(0x1C) # escape code 11509935Sdam.sunwoo@arm.com userspace_body += packed32(0x04) # visual code 11519935Sdam.sunwoo@arm.com 11529935Sdam.sunwoo@arm.com text_annotation = "image_" + str(ticksToNs(tick)) + ".bmp.gz" 11539935Sdam.sunwoo@arm.com userspace_body += int16(len(text_annotation)) 11549935Sdam.sunwoo@arm.com userspace_body += utf8StringList(text_annotation) 11559935Sdam.sunwoo@arm.com 11569935Sdam.sunwoo@arm.com if gzipped_bmp_supported: 11579935Sdam.sunwoo@arm.com # copy gzipped bmp directly 11589935Sdam.sunwoo@arm.com bytes_read = open(frame_path + "/" + fn, "rb").read() 11599935Sdam.sunwoo@arm.com else: 11609935Sdam.sunwoo@arm.com # copy uncompressed bmp 11619935Sdam.sunwoo@arm.com bytes_read = gzip.open(frame_path + "/" + fn, "rb").read() 11629935Sdam.sunwoo@arm.com 11639935Sdam.sunwoo@arm.com userspace_body += int32(len(bytes_read)) 11649935Sdam.sunwoo@arm.com userspace_body += bytes_read 11659935Sdam.sunwoo@arm.com 11669935Sdam.sunwoo@arm.com writeBinary(blob, annotateFrame(0, annotate_pid, ticksToNs(tick), \ 11679935Sdam.sunwoo@arm.com len(userspace_body), userspace_body)) 11689935Sdam.sunwoo@arm.com 11699935Sdam.sunwoo@arm.com print "\nfound", frame_count, "frames for visual annotation.\n" 11709935Sdam.sunwoo@arm.com 11719935Sdam.sunwoo@arm.com 11729935Sdam.sunwoo@arm.comdef createApcProject(input_path, output_path, stats): 11739935Sdam.sunwoo@arm.com initOutput(output_path) 11749935Sdam.sunwoo@arm.com 11759935Sdam.sunwoo@arm.com blob = open(output_path + "/0000000000", "wb") 11769935Sdam.sunwoo@arm.com 11779935Sdam.sunwoo@arm.com # Summary frame takes current system time and system uptime. 11789935Sdam.sunwoo@arm.com # Filling in with random values for now. 11799935Sdam.sunwoo@arm.com writeBinary(blob, summaryFrame(1234, 5678)) 11809935Sdam.sunwoo@arm.com 11819935Sdam.sunwoo@arm.com writeCookiesThreads(blob) 11829935Sdam.sunwoo@arm.com 11839935Sdam.sunwoo@arm.com print "writing Events" 11849935Sdam.sunwoo@arm.com writeSchedEvents(blob) 11859935Sdam.sunwoo@arm.com 11869935Sdam.sunwoo@arm.com print "writing Counters" 11879935Sdam.sunwoo@arm.com writeCounters(blob, stats) 11889935Sdam.sunwoo@arm.com 11899935Sdam.sunwoo@arm.com print "writing Visual Annotations" 11909935Sdam.sunwoo@arm.com writeVisualAnnotations(blob, input_path, output_path) 11919935Sdam.sunwoo@arm.com 11929935Sdam.sunwoo@arm.com doSessionXML(output_path) 11939935Sdam.sunwoo@arm.com doCapturedXML(output_path, stats) 11949935Sdam.sunwoo@arm.com 11959935Sdam.sunwoo@arm.com blob.close() 11969935Sdam.sunwoo@arm.com 11979935Sdam.sunwoo@arm.com 11989935Sdam.sunwoo@arm.com 11999935Sdam.sunwoo@arm.com####################### 12009935Sdam.sunwoo@arm.com# Main Routine 12019935Sdam.sunwoo@arm.com 12029935Sdam.sunwoo@arm.cominput_path = args.input_path 12039935Sdam.sunwoo@arm.comoutput_path = args.output_path 12049935Sdam.sunwoo@arm.com 12059935Sdam.sunwoo@arm.com#### 12069935Sdam.sunwoo@arm.com# Make sure input path exists 12079935Sdam.sunwoo@arm.com#### 12089935Sdam.sunwoo@arm.comif not os.path.exists(input_path): 12099935Sdam.sunwoo@arm.com print "ERROR: Input path %s does not exist!" % input_path 12109935Sdam.sunwoo@arm.com sys.exit(1) 12119935Sdam.sunwoo@arm.com 12129935Sdam.sunwoo@arm.com#### 12139935Sdam.sunwoo@arm.com# Parse gem5 configuration file to find # of CPUs and L2s 12149935Sdam.sunwoo@arm.com#### 12159935Sdam.sunwoo@arm.com(num_cpus, num_l2) = parseConfig(input_path + "/config.ini") 12169935Sdam.sunwoo@arm.com 12179935Sdam.sunwoo@arm.com#### 12189935Sdam.sunwoo@arm.com# Parse task file to find process/thread info 12199935Sdam.sunwoo@arm.com#### 12209935Sdam.sunwoo@arm.comparseProcessInfo(input_path + "/system.tasks.txt") 12219935Sdam.sunwoo@arm.com 12229935Sdam.sunwoo@arm.com#### 12239935Sdam.sunwoo@arm.com# Parse stat config file and register stats 12249935Sdam.sunwoo@arm.com#### 12259935Sdam.sunwoo@arm.comstat_config_file = args.stat_config_file 12269935Sdam.sunwoo@arm.comstats = registerStats(stat_config_file) 12279935Sdam.sunwoo@arm.com 12289935Sdam.sunwoo@arm.com#### 12299935Sdam.sunwoo@arm.com# Parse gem5 stats 12309935Sdam.sunwoo@arm.com#### 12319935Sdam.sunwoo@arm.com# Check if both stats.txt and stats.txt.gz exist and warn if both exist 12329935Sdam.sunwoo@arm.comif os.path.exists(input_path + "/stats.txt") and \ 12339935Sdam.sunwoo@arm.com os.path.exists(input_path + "/stats.txt.gz"): 12349935Sdam.sunwoo@arm.com print "WARNING: Both stats.txt.gz and stats.txt exist. \ 12359935Sdam.sunwoo@arm.com Using stats.txt.gz by default." 12369935Sdam.sunwoo@arm.com 12379935Sdam.sunwoo@arm.comgem5_stats_file = input_path + "/stats.txt.gz" 12389935Sdam.sunwoo@arm.comif not os.path.exists(gem5_stats_file): 12399935Sdam.sunwoo@arm.com gem5_stats_file = input_path + "/stats.txt" 12409935Sdam.sunwoo@arm.comif not os.path.exists(gem5_stats_file): 12419935Sdam.sunwoo@arm.com print "ERROR: stats.txt[.gz] file does not exist in %s!" % input_path 12429935Sdam.sunwoo@arm.com sys.exit(1) 12439935Sdam.sunwoo@arm.com 12449935Sdam.sunwoo@arm.comreadGem5Stats(stats, gem5_stats_file) 12459935Sdam.sunwoo@arm.com 12469935Sdam.sunwoo@arm.com#### 12479935Sdam.sunwoo@arm.com# Create Streamline .apc project folder 12489935Sdam.sunwoo@arm.com#### 12499935Sdam.sunwoo@arm.comcreateApcProject(input_path, output_path, stats) 12509935Sdam.sunwoo@arm.com 12519935Sdam.sunwoo@arm.comprint "All done!" 1252