113540Sandrea.mondelli@ucf.edu#!/usr/bin/env python2.7
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
14511686Sshawn.rosti@gmail.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
14911686Sshawn.rosti@gmail.com        while config.has_section("system.cpu" + str(num_cpus)):
1509935Sdam.sunwoo@arm.com            num_cpus += 1
1519935Sdam.sunwoo@arm.com
15211686Sshawn.rosti@gmail.com    if config.has_section("system.l2_cache"):
1539935Sdam.sunwoo@arm.com        num_l2 = 1
1549935Sdam.sunwoo@arm.com    else:
1559935Sdam.sunwoo@arm.com        num_l2 = 0
15611686Sshawn.rosti@gmail.com        while config.has_section("system.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