Simulation.py revision 13967:755cdc26b48d
14997Sgblack@eecs.umich.edu# Copyright (c) 2012-2013 ARM Limited
25268Sksewell@umich.edu# All rights reserved
35254Sksewell@umich.edu#
45254Sksewell@umich.edu# The license below extends only to copyright in the software and shall
54997Sgblack@eecs.umich.edu# not be construed as granting a license to any other intellectual
65254Sksewell@umich.edu# property including but not limited to intellectual property relating
75254Sksewell@umich.edu# to a hardware implementation of the functionality of the software
85254Sksewell@umich.edu# licensed hereunder.  You may use the software subject to the license
95254Sksewell@umich.edu# terms below provided that you ensure that this notice is replicated
105254Sksewell@umich.edu# unmodified and in its entirety in all distributions of the software,
115254Sksewell@umich.edu# modified or unmodified, in source code or in binary form.
125254Sksewell@umich.edu#
135254Sksewell@umich.edu# Copyright (c) 2006-2008 The Regents of The University of Michigan
145254Sksewell@umich.edu# Copyright (c) 2010 Advanced Micro Devices, Inc.
155254Sksewell@umich.edu# All rights reserved.
164997Sgblack@eecs.umich.edu#
175254Sksewell@umich.edu# Redistribution and use in source and binary forms, with or without
185254Sksewell@umich.edu# modification, are permitted provided that the following conditions are
195254Sksewell@umich.edu# met: redistributions of source code must retain the above copyright
205254Sksewell@umich.edu# notice, this list of conditions and the following disclaimer;
215254Sksewell@umich.edu# redistributions in binary form must reproduce the above copyright
225254Sksewell@umich.edu# notice, this list of conditions and the following disclaimer in the
235254Sksewell@umich.edu# documentation and/or other materials provided with the distribution;
245254Sksewell@umich.edu# neither the name of the copyright holders nor the names of its
255254Sksewell@umich.edu# contributors may be used to endorse or promote products derived from
265254Sksewell@umich.edu# this software without specific prior written permission.
275254Sksewell@umich.edu#
284997Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
295268Sksewell@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
305268Sksewell@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
315268Sksewell@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
328696Sguodeyuan@tsinghua.org.cn# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
338696Sguodeyuan@tsinghua.org.cn# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
344997Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
354997Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
365222Sksewell@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
375222Sksewell@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
384997Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
398229Snate@binkert.org#
408229Snate@binkert.org# Authors: Lisa Hsu
415222Sksewell@umich.edu
424997Sgblack@eecs.umich.edufrom __future__ import print_function
435222Sksewell@umich.edufrom __future__ import absolute_import
445222Sksewell@umich.edu
455222Sksewell@umich.eduimport sys
465222Sksewell@umich.edufrom os import getcwd
475222Sksewell@umich.edufrom os.path import join as joinpath
488232Snate@binkert.org
498232Snate@binkert.orgfrom . import CpuConfig
505224Sksewell@umich.edufrom . import BPConfig
515222Sksewell@umich.edufrom . import MemConfig
528229Snate@binkert.org
534997Sgblack@eecs.umich.eduimport m5
545222Sksewell@umich.edufrom m5.defines import buildEnv
555222Sksewell@umich.edufrom m5.objects import *
565019Sgblack@eecs.umich.edufrom m5.util import *
575222Sksewell@umich.edu
585222Sksewell@umich.eduaddToPath('../common')
595222Sksewell@umich.edu
605222Sksewell@umich.edudef getCPUClass(cpu_type):
615019Sgblack@eecs.umich.edu    """Returns the required cpu class and the mode of operation."""
625222Sksewell@umich.edu    cls = CpuConfig.get(cpu_type)
635358Sgblack@eecs.umich.edu    return cls, cls.memory_mode()
645222Sksewell@umich.edu
656378Sgblack@eecs.umich.edudef setCPUClass(options):
666378Sgblack@eecs.umich.edu    """Returns two cpu classes and the initial mode of operation.
676378Sgblack@eecs.umich.edu
685222Sksewell@umich.edu       Restoring from a checkpoint or fast forwarding through a benchmark
695222Sksewell@umich.edu       can be done using one type of cpu, and then the actual
705222Sksewell@umich.edu       simulation can be carried out using another type. This function
715222Sksewell@umich.edu       returns these two types of cpus and the initial mode of operation
725222Sksewell@umich.edu       depending on the options provided.
735222Sksewell@umich.edu    """
745222Sksewell@umich.edu
755222Sksewell@umich.edu    TmpClass, test_mem_mode = getCPUClass(options.cpu_type)
765222Sksewell@umich.edu    CPUClass = None
775222Sksewell@umich.edu    if TmpClass.require_caches() and \
785222Sksewell@umich.edu            not options.caches and not options.ruby:
795222Sksewell@umich.edu        fatal("%s must be used with caches" % options.cpu_type)
805222Sksewell@umich.edu
816378Sgblack@eecs.umich.edu    if options.checkpoint_restore != None:
825222Sksewell@umich.edu        if options.restore_with_cpu != options.cpu_type:
835222Sksewell@umich.edu            CPUClass = TmpClass
845222Sksewell@umich.edu            TmpClass, test_mem_mode = getCPUClass(options.restore_with_cpu)
855222Sksewell@umich.edu    elif options.fast_forward:
866378Sgblack@eecs.umich.edu        CPUClass = TmpClass
875222Sksewell@umich.edu        TmpClass = AtomicSimpleCPU
885222Sksewell@umich.edu        test_mem_mode = 'atomic'
895222Sksewell@umich.edu
905222Sksewell@umich.edu    # Ruby only supports atomic accesses in noncaching mode
915222Sksewell@umich.edu    if test_mem_mode == 'atomic' and options.ruby:
926378Sgblack@eecs.umich.edu        warn("Memory mode will be changed to atomic_noncaching")
936378Sgblack@eecs.umich.edu        test_mem_mode = 'atomic_noncaching'
946378Sgblack@eecs.umich.edu
955222Sksewell@umich.edu    return (TmpClass, test_mem_mode, CPUClass)
965222Sksewell@umich.edu
976378Sgblack@eecs.umich.edudef setMemClass(options):
985222Sksewell@umich.edu    """Returns a memory controller class."""
995222Sksewell@umich.edu
1005019Sgblack@eecs.umich.edu    return MemConfig.get(options.mem_type)
1015019Sgblack@eecs.umich.edu
1025222Sksewell@umich.edudef setWorkCountOptions(system, options):
1035222Sksewell@umich.edu    if options.work_item_id != None:
1045222Sksewell@umich.edu        system.work_item_id = options.work_item_id
1055222Sksewell@umich.edu    if options.num_work_ids != None:
1065222Sksewell@umich.edu        system.num_work_ids = options.num_work_ids
1076378Sgblack@eecs.umich.edu    if options.work_begin_cpu_id_exit != None:
1086378Sgblack@eecs.umich.edu        system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit
1095222Sksewell@umich.edu    if options.work_end_exit_count != None:
1105222Sksewell@umich.edu        system.work_end_exit_count = options.work_end_exit_count
1115222Sksewell@umich.edu    if options.work_end_checkpoint_count != None:
1125222Sksewell@umich.edu        system.work_end_ckpt_count = options.work_end_checkpoint_count
1135222Sksewell@umich.edu    if options.work_begin_exit_count != None:
1145222Sksewell@umich.edu        system.work_begin_exit_count = options.work_begin_exit_count
1156378Sgblack@eecs.umich.edu    if options.work_begin_checkpoint_count != None:
1166378Sgblack@eecs.umich.edu        system.work_begin_ckpt_count = options.work_begin_checkpoint_count
1175222Sksewell@umich.edu    if options.work_cpus_checkpoint_count != None:
1185222Sksewell@umich.edu        system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count
1196378Sgblack@eecs.umich.edu
1205222Sksewell@umich.edudef findCptDir(options, cptdir, testsys):
1215222Sksewell@umich.edu    """Figures out the directory from which the checkpointed state is read.
1225222Sksewell@umich.edu
1235222Sksewell@umich.edu    There are two different ways in which the directories holding checkpoints
1246378Sgblack@eecs.umich.edu    can be named --
1255222Sksewell@umich.edu    1. cpt.<benchmark name>.<instruction count when the checkpoint was taken>
1265222Sksewell@umich.edu    2. cpt.<some number, usually the tick value when the checkpoint was taken>
1275222Sksewell@umich.edu
1285222Sksewell@umich.edu    This function parses through the options to figure out which one of the
1296378Sgblack@eecs.umich.edu    above should be used for selecting the checkpoint, and then figures out
1306378Sgblack@eecs.umich.edu    the appropriate directory.
1316378Sgblack@eecs.umich.edu    """
1326378Sgblack@eecs.umich.edu
1335222Sksewell@umich.edu    from os.path import isdir, exists
1345222Sksewell@umich.edu    from os import listdir
1356378Sgblack@eecs.umich.edu    import re
1365222Sksewell@umich.edu
1375222Sksewell@umich.edu    if not isdir(cptdir):
1385222Sksewell@umich.edu        fatal("checkpoint dir %s does not exist!", cptdir)
1395222Sksewell@umich.edu
1405222Sksewell@umich.edu    cpt_starttick = 0
1415222Sksewell@umich.edu    if options.at_instruction or options.simpoint:
1426378Sgblack@eecs.umich.edu        inst = options.checkpoint_restore
1436378Sgblack@eecs.umich.edu        if options.simpoint:
1445222Sksewell@umich.edu            # assume workload 0 has the simpoint
1455222Sksewell@umich.edu            if testsys.cpu[0].workload[0].simpoint == 0:
1466378Sgblack@eecs.umich.edu                fatal('Unable to find simpoint')
1476378Sgblack@eecs.umich.edu            inst += int(testsys.cpu[0].workload[0].simpoint)
1486378Sgblack@eecs.umich.edu
1496378Sgblack@eecs.umich.edu        checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst))
1506378Sgblack@eecs.umich.edu        if not exists(checkpoint_dir):
15110824SAndreas.Sandberg@ARM.com            fatal("Unable to find checkpoint directory %s", checkpoint_dir)
1526378Sgblack@eecs.umich.edu
1536378Sgblack@eecs.umich.edu    elif options.restore_simpoint_checkpoint:
1545222Sksewell@umich.edu        # Restore from SimPoint checkpoints
1556378Sgblack@eecs.umich.edu        # Assumes that the checkpoint dir names are formatted as follows:
1566378Sgblack@eecs.umich.edu        dirs = listdir(cptdir)
1576378Sgblack@eecs.umich.edu        expr = re.compile('cpt\.simpoint_(\d+)_inst_(\d+)' +
1585222Sksewell@umich.edu                    '_weight_([\d\.e\-]+)_interval_(\d+)_warmup_(\d+)')
1596378Sgblack@eecs.umich.edu        cpts = []
1606378Sgblack@eecs.umich.edu        for dir in dirs:
1616378Sgblack@eecs.umich.edu            match = expr.match(dir)
1626378Sgblack@eecs.umich.edu            if match:
1636378Sgblack@eecs.umich.edu                cpts.append(dir)
1646378Sgblack@eecs.umich.edu        cpts.sort()
1656378Sgblack@eecs.umich.edu
1666378Sgblack@eecs.umich.edu        cpt_num = options.checkpoint_restore
1676378Sgblack@eecs.umich.edu        if cpt_num > len(cpts):
1686378Sgblack@eecs.umich.edu            fatal('Checkpoint %d not found', cpt_num)
1696378Sgblack@eecs.umich.edu        checkpoint_dir = joinpath(cptdir, cpts[cpt_num - 1])
1706378Sgblack@eecs.umich.edu        match = expr.match(cpts[cpt_num - 1])
1716378Sgblack@eecs.umich.edu        if match:
17210231Ssteve.reinhardt@amd.com            index = int(match.group(1))
1736378Sgblack@eecs.umich.edu            start_inst = int(match.group(2))
1746378Sgblack@eecs.umich.edu            weight_inst = float(match.group(3))
1756378Sgblack@eecs.umich.edu            interval_length = int(match.group(4))
1766378Sgblack@eecs.umich.edu            warmup_length = int(match.group(5))
1776378Sgblack@eecs.umich.edu        print("Resuming from", checkpoint_dir)
1786378Sgblack@eecs.umich.edu        simpoint_start_insts = []
1796378Sgblack@eecs.umich.edu        simpoint_start_insts.append(warmup_length)
1805222Sksewell@umich.edu        simpoint_start_insts.append(warmup_length + interval_length)
1815222Sksewell@umich.edu        testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
1825222Sksewell@umich.edu        if testsys.switch_cpus != None:
1835222Sksewell@umich.edu            testsys.switch_cpus[0].simpoint_start_insts = simpoint_start_insts
1845222Sksewell@umich.edu
1856378Sgblack@eecs.umich.edu        print("Resuming from SimPoint", end=' ')
1865222Sksewell@umich.edu        print("#%d, start_inst:%d, weight:%f, interval:%d, warmup:%d" %
1876378Sgblack@eecs.umich.edu            (index, start_inst, weight_inst, interval_length, warmup_length))
1885222Sksewell@umich.edu
1895222Sksewell@umich.edu    else:
1905222Sksewell@umich.edu        dirs = listdir(cptdir)
1915222Sksewell@umich.edu        expr = re.compile('cpt\.([0-9]+)')
1925222Sksewell@umich.edu        cpts = []
1935222Sksewell@umich.edu        for dir in dirs:
1946378Sgblack@eecs.umich.edu            match = expr.match(dir)
1955222Sksewell@umich.edu            if match:
1965222Sksewell@umich.edu                cpts.append(match.group(1))
1975222Sksewell@umich.edu
1985222Sksewell@umich.edu        cpts.sort(lambda a,b: cmp(long(a), long(b)))
1995222Sksewell@umich.edu
20010905Sandreas.sandberg@arm.com        cpt_num = options.checkpoint_restore
2015222Sksewell@umich.edu        if cpt_num > len(cpts):
2025222Sksewell@umich.edu            fatal('Checkpoint %d not found', cpt_num)
2035222Sksewell@umich.edu
2045222Sksewell@umich.edu        cpt_starttick = int(cpts[cpt_num - 1])
2055222Sksewell@umich.edu        checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])
20610905Sandreas.sandberg@arm.com
20710905Sandreas.sandberg@arm.com    return cpt_starttick, checkpoint_dir
2085222Sksewell@umich.edu
2095222Sksewell@umich.edudef scriptCheckpoints(options, maxtick, cptdir):
2105222Sksewell@umich.edu    if options.at_instruction or options.simpoint:
2115222Sksewell@umich.edu        checkpoint_inst = int(options.take_checkpoints)
21210905Sandreas.sandberg@arm.com
2135222Sksewell@umich.edu        # maintain correct offset if we restored from some instruction
2145222Sksewell@umich.edu        if options.checkpoint_restore != None:
2155222Sksewell@umich.edu            checkpoint_inst += options.checkpoint_restore
2165222Sksewell@umich.edu
2175222Sksewell@umich.edu        print("Creating checkpoint at inst:%d" % (checkpoint_inst))
21810905Sandreas.sandberg@arm.com        exit_event = m5.simulate()
21910905Sandreas.sandberg@arm.com        exit_cause = exit_event.getCause()
2205222Sksewell@umich.edu        print("exit cause = %s" % exit_cause)
2215222Sksewell@umich.edu
2225222Sksewell@umich.edu        # skip checkpoint instructions should they exist
2235222Sksewell@umich.edu        while exit_cause == "checkpoint":
2245222Sksewell@umich.edu            exit_event = m5.simulate()
2255222Sksewell@umich.edu            exit_cause = exit_event.getCause()
2265222Sksewell@umich.edu
2275222Sksewell@umich.edu        if exit_cause == "a thread reached the max instruction count":
2285222Sksewell@umich.edu            m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \
22911523Sdavid.guillen@arm.com                    (options.bench, checkpoint_inst)))
23011523Sdavid.guillen@arm.com            print("Checkpoint written.")
2315222Sksewell@umich.edu
2325222Sksewell@umich.edu    else:
2335222Sksewell@umich.edu        when, period = options.take_checkpoints.split(",", 1)
2345222Sksewell@umich.edu        when = int(when)
2355222Sksewell@umich.edu        period = int(period)
2365222Sksewell@umich.edu        num_checkpoints = 0
2375222Sksewell@umich.edu
2385222Sksewell@umich.edu        exit_event = m5.simulate(when - m5.curTick())
2395222Sksewell@umich.edu        exit_cause = exit_event.getCause()
2405222Sksewell@umich.edu        while exit_cause == "checkpoint":
2415222Sksewell@umich.edu            exit_event = m5.simulate(when - m5.curTick())
2425222Sksewell@umich.edu            exit_cause = exit_event.getCause()
2435222Sksewell@umich.edu
2445222Sksewell@umich.edu        if exit_cause == "simulate() limit reached":
2455222Sksewell@umich.edu            m5.checkpoint(joinpath(cptdir, "cpt.%d"))
2465222Sksewell@umich.edu            num_checkpoints += 1
2475222Sksewell@umich.edu
2485222Sksewell@umich.edu        sim_ticks = when
2495222Sksewell@umich.edu        max_checkpoints = options.max_checkpoints
2505222Sksewell@umich.edu
2515222Sksewell@umich.edu        while num_checkpoints < max_checkpoints and \
2525222Sksewell@umich.edu                exit_cause == "simulate() limit reached":
2535222Sksewell@umich.edu            if (sim_ticks + period) > maxtick:
2545222Sksewell@umich.edu                exit_event = m5.simulate(maxtick - sim_ticks)
2555222Sksewell@umich.edu                exit_cause = exit_event.getCause()
2565222Sksewell@umich.edu                break
2575222Sksewell@umich.edu            else:
2585222Sksewell@umich.edu                exit_event = m5.simulate(period)
2595222Sksewell@umich.edu                exit_cause = exit_event.getCause()
2605222Sksewell@umich.edu                sim_ticks += period
2615222Sksewell@umich.edu                while exit_event.getCause() == "checkpoint":
2625222Sksewell@umich.edu                    exit_event = m5.simulate(sim_ticks - m5.curTick())
2635222Sksewell@umich.edu                if exit_event.getCause() == "simulate() limit reached":
2645222Sksewell@umich.edu                    m5.checkpoint(joinpath(cptdir, "cpt.%d"))
2655222Sksewell@umich.edu                    num_checkpoints += 1
2665222Sksewell@umich.edu
2675222Sksewell@umich.edu    return exit_event
2685222Sksewell@umich.edu
2695222Sksewell@umich.edudef benchCheckpoints(options, maxtick, cptdir):
2705222Sksewell@umich.edu    exit_event = m5.simulate(maxtick - m5.curTick())
2715222Sksewell@umich.edu    exit_cause = exit_event.getCause()
2725222Sksewell@umich.edu
2735222Sksewell@umich.edu    num_checkpoints = 0
2745222Sksewell@umich.edu    max_checkpoints = options.max_checkpoints
2755222Sksewell@umich.edu
2765222Sksewell@umich.edu    while exit_cause == "checkpoint":
2775222Sksewell@umich.edu        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
2785222Sksewell@umich.edu        num_checkpoints += 1
2795222Sksewell@umich.edu        if num_checkpoints == max_checkpoints:
2805222Sksewell@umich.edu            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
2815222Sksewell@umich.edu            break
2825222Sksewell@umich.edu
2835222Sksewell@umich.edu        exit_event = m5.simulate(maxtick - m5.curTick())
2846022Sgblack@eecs.umich.edu        exit_cause = exit_event.getCause()
2855222Sksewell@umich.edu
2868806Sgblack@eecs.umich.edu    return exit_event
2878806Sgblack@eecs.umich.edu
2885224Sksewell@umich.edu# Set up environment for taking SimPoint checkpoints
2898806Sgblack@eecs.umich.edu# Expecting SimPoint files generated by SimPoint 3.2
2905224Sksewell@umich.edudef parseSimpointAnalysisFile(options, testsys):
2918806Sgblack@eecs.umich.edu    import re
2928806Sgblack@eecs.umich.edu
2938806Sgblack@eecs.umich.edu    simpoint_filename, weight_filename, interval_length, warmup_length = \
2948806Sgblack@eecs.umich.edu        options.take_simpoint_checkpoints.split(",", 3)
2958806Sgblack@eecs.umich.edu    print("simpoint analysis file:", simpoint_filename)
2965222Sksewell@umich.edu    print("simpoint weight file:", weight_filename)
2975222Sksewell@umich.edu    print("interval length:", interval_length)
2985222Sksewell@umich.edu    print("warmup length:", warmup_length)
2996022Sgblack@eecs.umich.edu
3005222Sksewell@umich.edu    interval_length = int(interval_length)
3018806Sgblack@eecs.umich.edu    warmup_length = int(warmup_length)
3028806Sgblack@eecs.umich.edu
3038767Sgblack@eecs.umich.edu    # Simpoint analysis output starts interval counts with 0.
3048806Sgblack@eecs.umich.edu    simpoints = []
3058767Sgblack@eecs.umich.edu    simpoint_start_insts = []
3068806Sgblack@eecs.umich.edu
3078806Sgblack@eecs.umich.edu    # Read in SimPoint analysis files
3088806Sgblack@eecs.umich.edu    simpoint_file = open(simpoint_filename)
3098806Sgblack@eecs.umich.edu    weight_file = open(weight_filename)
3108806Sgblack@eecs.umich.edu    while True:
3115222Sksewell@umich.edu        line = simpoint_file.readline()
3125222Sksewell@umich.edu        if not line:
3136022Sgblack@eecs.umich.edu            break
3146023Snate@binkert.org        m = re.match("(\d+)\s+(\d+)", line)
3156022Sgblack@eecs.umich.edu        if m:
3166023Snate@binkert.org            interval = int(m.group(1))
3176022Sgblack@eecs.umich.edu        else:
3186022Sgblack@eecs.umich.edu            fatal('unrecognized line in simpoint file!')
3196023Snate@binkert.org
3206022Sgblack@eecs.umich.edu        line = weight_file.readline()
3216022Sgblack@eecs.umich.edu        if not line:
3225894Sgblack@eecs.umich.edu            fatal('not enough lines in simpoint weight file!')
3236022Sgblack@eecs.umich.edu        m = re.match("([0-9\.e\-]+)\s+(\d+)", line)
3246023Snate@binkert.org        if m:
3255894Sgblack@eecs.umich.edu            weight = float(m.group(1))
3265894Sgblack@eecs.umich.edu        else:
3276023Snate@binkert.org            fatal('unrecognized line in simpoint weight file!')
3285894Sgblack@eecs.umich.edu
3295894Sgblack@eecs.umich.edu        if (interval * interval_length - warmup_length > 0):
3308888Sgeoffrey.blake@arm.com            starting_inst_count = \
3318888Sgeoffrey.blake@arm.com                interval * interval_length - warmup_length
3328888Sgeoffrey.blake@arm.com            actual_warmup_length = warmup_length
3338888Sgeoffrey.blake@arm.com        else:
3348888Sgeoffrey.blake@arm.com            # Not enough room for proper warmup
3358888Sgeoffrey.blake@arm.com            # Just starting from the beginning
3368888Sgeoffrey.blake@arm.com            starting_inst_count = 0
3379738Sandreas@sandberg.pp.se            actual_warmup_length = interval * interval_length
3389738Sandreas@sandberg.pp.se
3399738Sandreas@sandberg.pp.se        simpoints.append((interval, weight, starting_inst_count,
3409738Sandreas@sandberg.pp.se            actual_warmup_length))
3419738Sandreas@sandberg.pp.se
3429738Sandreas@sandberg.pp.se    # Sort SimPoints by starting inst count
3435222Sksewell@umich.edu    simpoints.sort(key=lambda obj: obj[2])
3445222Sksewell@umich.edu    for s in simpoints:
3455222Sksewell@umich.edu        interval, weight, starting_inst_count, actual_warmup_length = s
3465222Sksewell@umich.edu        print(str(interval), str(weight), starting_inst_count,
3476378Sgblack@eecs.umich.edu            actual_warmup_length)
3485222Sksewell@umich.edu        simpoint_start_insts.append(starting_inst_count)
3495222Sksewell@umich.edu
3505222Sksewell@umich.edu    print("Total # of simpoints:", len(simpoints))
3515222Sksewell@umich.edu    testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
3525222Sksewell@umich.edu
3535222Sksewell@umich.edu    return (simpoints, interval_length)
3544997Sgblack@eecs.umich.edu
3556022Sgblack@eecs.umich.edudef takeSimpointCheckpoints(simpoints, interval_length, cptdir):
3566022Sgblack@eecs.umich.edu    num_checkpoints = 0
3574997Sgblack@eecs.umich.edu    index = 0
3586378Sgblack@eecs.umich.edu    last_chkpnt_inst_count = -1
3594997Sgblack@eecs.umich.edu    for simpoint in simpoints:
360        interval, weight, starting_inst_count, actual_warmup_length = simpoint
361        if starting_inst_count == last_chkpnt_inst_count:
362            # checkpoint starting point same as last time
363            # (when warmup period longer than starting point)
364            exit_cause = "simpoint starting point found"
365            code = 0
366        else:
367            exit_event = m5.simulate()
368
369            # skip checkpoint instructions should they exist
370            while exit_event.getCause() == "checkpoint":
371                print("Found 'checkpoint' exit event...ignoring...")
372                exit_event = m5.simulate()
373
374            exit_cause = exit_event.getCause()
375            code = exit_event.getCode()
376
377        if exit_cause == "simpoint starting point found":
378            m5.checkpoint(joinpath(cptdir,
379                "cpt.simpoint_%02d_inst_%d_weight_%f_interval_%d_warmup_%d"
380                % (index, starting_inst_count, weight, interval_length,
381                actual_warmup_length)))
382            print("Checkpoint #%d written. start inst:%d weight:%f" %
383                (num_checkpoints, starting_inst_count, weight))
384            num_checkpoints += 1
385            last_chkpnt_inst_count = starting_inst_count
386        else:
387            break
388        index += 1
389
390    print('Exiting @ tick %i because %s' % (m5.curTick(), exit_cause))
391    print("%d checkpoints taken" % num_checkpoints)
392    sys.exit(code)
393
394def restoreSimpointCheckpoint():
395    exit_event = m5.simulate()
396    exit_cause = exit_event.getCause()
397
398    if exit_cause == "simpoint starting point found":
399        print("Warmed up! Dumping and resetting stats!")
400        m5.stats.dump()
401        m5.stats.reset()
402
403        exit_event = m5.simulate()
404        exit_cause = exit_event.getCause()
405
406        if exit_cause == "simpoint starting point found":
407            print("Done running SimPoint!")
408            sys.exit(exit_event.getCode())
409
410    print('Exiting @ tick %i because %s' % (m5.curTick(), exit_cause))
411    sys.exit(exit_event.getCode())
412
413def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq):
414    print("starting switch loop")
415    while True:
416        exit_event = m5.simulate(switch_freq)
417        exit_cause = exit_event.getCause()
418
419        if exit_cause != "simulate() limit reached":
420            return exit_event
421
422        m5.switchCpus(testsys, repeat_switch_cpu_list)
423
424        tmp_cpu_list = []
425        for old_cpu, new_cpu in repeat_switch_cpu_list:
426            tmp_cpu_list.append((new_cpu, old_cpu))
427        repeat_switch_cpu_list = tmp_cpu_list
428
429        if (maxtick - m5.curTick()) <= switch_freq:
430            exit_event = m5.simulate(maxtick - m5.curTick())
431            return exit_event
432
433def run(options, root, testsys, cpu_class):
434    if options.checkpoint_dir:
435        cptdir = options.checkpoint_dir
436    elif m5.options.outdir:
437        cptdir = m5.options.outdir
438    else:
439        cptdir = getcwd()
440
441    if options.fast_forward and options.checkpoint_restore != None:
442        fatal("Can't specify both --fast-forward and --checkpoint-restore")
443
444    if options.standard_switch and not options.caches:
445        fatal("Must specify --caches when using --standard-switch")
446
447    if options.standard_switch and options.repeat_switch:
448        fatal("Can't specify both --standard-switch and --repeat-switch")
449
450    if options.repeat_switch and options.take_checkpoints:
451        fatal("Can't specify both --repeat-switch and --take-checkpoints")
452
453    np = options.num_cpus
454    switch_cpus = None
455
456    if options.prog_interval:
457        for i in range(np):
458            testsys.cpu[i].progress_interval = options.prog_interval
459
460    if options.maxinsts:
461        for i in range(np):
462            testsys.cpu[i].max_insts_any_thread = options.maxinsts
463
464    if cpu_class:
465        switch_cpus = [cpu_class(switched_out=True, cpu_id=(i))
466                       for i in range(np)]
467
468        for i in range(np):
469            if options.fast_forward:
470                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
471            switch_cpus[i].system = testsys
472            switch_cpus[i].workload = testsys.cpu[i].workload
473            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
474            switch_cpus[i].progress_interval = \
475                testsys.cpu[i].progress_interval
476            switch_cpus[i].isa = testsys.cpu[i].isa
477            # simulation period
478            if options.maxinsts:
479                switch_cpus[i].max_insts_any_thread = options.maxinsts
480            # Add checker cpu if selected
481            if options.checker:
482                switch_cpus[i].addCheckerCpu()
483            if options.bp_type:
484                bpClass = BPConfig.get(options.bp_type)
485                switch_cpus[i].branchPred = bpClass()
486            if options.indirect_bp_type:
487                IndirectBPClass = \
488                    BPConfig.get_indirect(options.indirect_bp_type)
489                switch_cpus[i].branchPred.indirectBranchPred = \
490                    IndirectBPClass()
491
492        # If elastic tracing is enabled attach the elastic trace probe
493        # to the switch CPUs
494        if options.elastic_trace_en:
495            CpuConfig.config_etrace(cpu_class, switch_cpus, options)
496
497        testsys.switch_cpus = switch_cpus
498        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in range(np)]
499
500    if options.repeat_switch:
501        switch_class = getCPUClass(options.cpu_type)[0]
502        if switch_class.require_caches() and \
503                not options.caches:
504            print("%s: Must be used with caches" % str(switch_class))
505            sys.exit(1)
506        if not switch_class.support_take_over():
507            print("%s: CPU switching not supported" % str(switch_class))
508            sys.exit(1)
509
510        repeat_switch_cpus = [switch_class(switched_out=True, \
511                                               cpu_id=(i)) for i in range(np)]
512
513        for i in range(np):
514            repeat_switch_cpus[i].system = testsys
515            repeat_switch_cpus[i].workload = testsys.cpu[i].workload
516            repeat_switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
517            repeat_switch_cpus[i].isa = testsys.cpu[i].isa
518
519            if options.maxinsts:
520                repeat_switch_cpus[i].max_insts_any_thread = options.maxinsts
521
522            if options.checker:
523                repeat_switch_cpus[i].addCheckerCpu()
524
525        testsys.repeat_switch_cpus = repeat_switch_cpus
526
527        if cpu_class:
528            repeat_switch_cpu_list = [(switch_cpus[i], repeat_switch_cpus[i])
529                                      for i in range(np)]
530        else:
531            repeat_switch_cpu_list = [(testsys.cpu[i], repeat_switch_cpus[i])
532                                      for i in range(np)]
533
534    if options.standard_switch:
535        switch_cpus = [TimingSimpleCPU(switched_out=True, cpu_id=(i))
536                       for i in range(np)]
537        switch_cpus_1 = [DerivO3CPU(switched_out=True, cpu_id=(i))
538                        for i in range(np)]
539
540        for i in range(np):
541            switch_cpus[i].system =  testsys
542            switch_cpus_1[i].system =  testsys
543            switch_cpus[i].workload = testsys.cpu[i].workload
544            switch_cpus_1[i].workload = testsys.cpu[i].workload
545            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
546            switch_cpus_1[i].clk_domain = testsys.cpu[i].clk_domain
547            switch_cpus[i].isa = testsys.cpu[i].isa
548            switch_cpus_1[i].isa = testsys.cpu[i].isa
549
550            # if restoring, make atomic cpu simulate only a few instructions
551            if options.checkpoint_restore != None:
552                testsys.cpu[i].max_insts_any_thread = 1
553            # Fast forward to specified location if we are not restoring
554            elif options.fast_forward:
555                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
556            # Fast forward to a simpoint (warning: time consuming)
557            elif options.simpoint:
558                if testsys.cpu[i].workload[0].simpoint == 0:
559                    fatal('simpoint not found')
560                testsys.cpu[i].max_insts_any_thread = \
561                    testsys.cpu[i].workload[0].simpoint
562            # No distance specified, just switch
563            else:
564                testsys.cpu[i].max_insts_any_thread = 1
565
566            # warmup period
567            if options.warmup_insts:
568                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
569
570            # simulation period
571            if options.maxinsts:
572                switch_cpus_1[i].max_insts_any_thread = options.maxinsts
573
574            # attach the checker cpu if selected
575            if options.checker:
576                switch_cpus[i].addCheckerCpu()
577                switch_cpus_1[i].addCheckerCpu()
578
579        testsys.switch_cpus = switch_cpus
580        testsys.switch_cpus_1 = switch_cpus_1
581        switch_cpu_list = [
582            (testsys.cpu[i], switch_cpus[i]) for i in range(np)
583        ]
584        switch_cpu_list1 = [
585            (switch_cpus[i], switch_cpus_1[i]) for i in range(np)
586        ]
587
588    # set the checkpoint in the cpu before m5.instantiate is called
589    if options.take_checkpoints != None and \
590           (options.simpoint or options.at_instruction):
591        offset = int(options.take_checkpoints)
592        # Set an instruction break point
593        if options.simpoint:
594            for i in range(np):
595                if testsys.cpu[i].workload[0].simpoint == 0:
596                    fatal('no simpoint for testsys.cpu[%d].workload[0]', i)
597                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
598                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
599                # used for output below
600                options.take_checkpoints = checkpoint_inst
601        else:
602            options.take_checkpoints = offset
603            # Set all test cpus with the right number of instructions
604            # for the upcoming simulation
605            for i in range(np):
606                testsys.cpu[i].max_insts_any_thread = offset
607
608    if options.take_simpoint_checkpoints != None:
609        simpoints, interval_length = parseSimpointAnalysisFile(options, testsys)
610
611    checkpoint_dir = None
612    if options.checkpoint_restore:
613        cpt_starttick, checkpoint_dir = findCptDir(options, cptdir, testsys)
614    root.apply_config(options.param)
615    m5.instantiate(checkpoint_dir)
616
617    # Initialization is complete.  If we're not in control of simulation
618    # (that is, if we're a slave simulator acting as a component in another
619    #  'master' simulator) then we're done here.  The other simulator will
620    # call simulate() directly. --initialize-only is used to indicate this.
621    if options.initialize_only:
622        return
623
624    # Handle the max tick settings now that tick frequency was resolved
625    # during system instantiation
626    # NOTE: the maxtick variable here is in absolute ticks, so it must
627    # include any simulated ticks before a checkpoint
628    explicit_maxticks = 0
629    maxtick_from_abs = m5.MaxTick
630    maxtick_from_rel = m5.MaxTick
631    maxtick_from_maxtime = m5.MaxTick
632    if options.abs_max_tick:
633        maxtick_from_abs = options.abs_max_tick
634        explicit_maxticks += 1
635    if options.rel_max_tick:
636        maxtick_from_rel = options.rel_max_tick
637        if options.checkpoint_restore:
638            # NOTE: this may need to be updated if checkpoints ever store
639            # the ticks per simulated second
640            maxtick_from_rel += cpt_starttick
641            if options.at_instruction or options.simpoint:
642                warn("Relative max tick specified with --at-instruction or" \
643                     " --simpoint\n      These options don't specify the " \
644                     "checkpoint start tick, so assuming\n      you mean " \
645                     "absolute max tick")
646        explicit_maxticks += 1
647    if options.maxtime:
648        maxtick_from_maxtime = m5.ticks.fromSeconds(options.maxtime)
649        explicit_maxticks += 1
650    if explicit_maxticks > 1:
651        warn("Specified multiple of --abs-max-tick, --rel-max-tick, --maxtime."\
652             " Using least")
653    maxtick = min([maxtick_from_abs, maxtick_from_rel, maxtick_from_maxtime])
654
655    if options.checkpoint_restore != None and maxtick < cpt_starttick:
656        fatal("Bad maxtick (%d) specified: " \
657              "Checkpoint starts starts from tick: %d", maxtick, cpt_starttick)
658
659    if options.standard_switch or cpu_class:
660        if options.standard_switch:
661            print("Switch at instruction count:%s" %
662                    str(testsys.cpu[0].max_insts_any_thread))
663            exit_event = m5.simulate()
664        elif cpu_class and options.fast_forward:
665            print("Switch at instruction count:%s" %
666                    str(testsys.cpu[0].max_insts_any_thread))
667            exit_event = m5.simulate()
668        else:
669            print("Switch at curTick count:%s" % str(10000))
670            exit_event = m5.simulate(10000)
671        print("Switched CPUS @ tick %s" % (m5.curTick()))
672
673        m5.switchCpus(testsys, switch_cpu_list)
674
675        if options.standard_switch:
676            print("Switch at instruction count:%d" %
677                    (testsys.switch_cpus[0].max_insts_any_thread))
678
679            #warmup instruction count may have already been set
680            if options.warmup_insts:
681                exit_event = m5.simulate()
682            else:
683                exit_event = m5.simulate(options.standard_switch)
684            print("Switching CPUS @ tick %s" % (m5.curTick()))
685            print("Simulation ends instruction count:%d" %
686                    (testsys.switch_cpus_1[0].max_insts_any_thread))
687            m5.switchCpus(testsys, switch_cpu_list1)
688
689    # If we're taking and restoring checkpoints, use checkpoint_dir
690    # option only for finding the checkpoints to restore from.  This
691    # lets us test checkpointing by restoring from one set of
692    # checkpoints, generating a second set, and then comparing them.
693    if (options.take_checkpoints or options.take_simpoint_checkpoints) \
694        and options.checkpoint_restore:
695
696        if m5.options.outdir:
697            cptdir = m5.options.outdir
698        else:
699            cptdir = getcwd()
700
701    if options.take_checkpoints != None :
702        # Checkpoints being taken via the command line at <when> and at
703        # subsequent periods of <period>.  Checkpoint instructions
704        # received from the benchmark running are ignored and skipped in
705        # favor of command line checkpoint instructions.
706        exit_event = scriptCheckpoints(options, maxtick, cptdir)
707
708    # Take SimPoint checkpoints
709    elif options.take_simpoint_checkpoints != None:
710        takeSimpointCheckpoints(simpoints, interval_length, cptdir)
711
712    # Restore from SimPoint checkpoints
713    elif options.restore_simpoint_checkpoint != None:
714        restoreSimpointCheckpoint()
715
716    else:
717        if options.fast_forward:
718            m5.stats.reset()
719        print("**** REAL SIMULATION ****")
720
721        # If checkpoints are being taken, then the checkpoint instruction
722        # will occur in the benchmark code it self.
723        if options.repeat_switch and maxtick > options.repeat_switch:
724            exit_event = repeatSwitch(testsys, repeat_switch_cpu_list,
725                                      maxtick, options.repeat_switch)
726        else:
727            exit_event = benchCheckpoints(options, maxtick, cptdir)
728
729    print('Exiting @ tick %i because %s' %
730          (m5.curTick(), exit_event.getCause()))
731    if options.checkpoint_at_end:
732        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
733
734    if exit_event.getCode() != 0:
735        print("Simulated exit code not 0! Exit code is", exit_event.getCode())
736