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