Simulation.py revision 11688
13931Ssaidi@eecs.umich.edu# Copyright (c) 2012-2013 ARM Limited
23388Sgblack@eecs.umich.edu# All rights reserved
33388Sgblack@eecs.umich.edu#
43388Sgblack@eecs.umich.edu# The license below extends only to copyright in the software and shall
53388Sgblack@eecs.umich.edu# not be construed as granting a license to any other intellectual
63388Sgblack@eecs.umich.edu# property including but not limited to intellectual property relating
73388Sgblack@eecs.umich.edu# to a hardware implementation of the functionality of the software
83388Sgblack@eecs.umich.edu# licensed hereunder.  You may use the software subject to the license
93388Sgblack@eecs.umich.edu# terms below provided that you ensure that this notice is replicated
103388Sgblack@eecs.umich.edu# unmodified and in its entirety in all distributions of the software,
113388Sgblack@eecs.umich.edu# modified or unmodified, in source code or in binary form.
123388Sgblack@eecs.umich.edu#
133388Sgblack@eecs.umich.edu# Copyright (c) 2006-2008 The Regents of The University of Michigan
143388Sgblack@eecs.umich.edu# Copyright (c) 2010 Advanced Micro Devices, Inc.
153388Sgblack@eecs.umich.edu# All rights reserved.
163388Sgblack@eecs.umich.edu#
173388Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
183388Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
193388Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
203388Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
213388Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
223388Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
233388Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
243388Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
253388Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
263388Sgblack@eecs.umich.edu# this software without specific prior written permission.
273388Sgblack@eecs.umich.edu#
283388Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293388Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303388Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313388Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323388Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333388Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343388Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353388Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363441Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373441Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383441Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393441Sgblack@eecs.umich.edu#
403441Sgblack@eecs.umich.edu# Authors: Lisa Hsu
413441Sgblack@eecs.umich.edu
423441Sgblack@eecs.umich.eduimport sys
433441Sgblack@eecs.umich.edufrom os import getcwd
443441Sgblack@eecs.umich.edufrom os.path import join as joinpath
453441Sgblack@eecs.umich.edu
463441Sgblack@eecs.umich.edufrom common import CpuConfig
473441Sgblack@eecs.umich.edufrom common import MemConfig
483441Sgblack@eecs.umich.edu
493441Sgblack@eecs.umich.eduimport m5
503441Sgblack@eecs.umich.edufrom m5.defines import buildEnv
513441Sgblack@eecs.umich.edufrom m5.objects import *
523441Sgblack@eecs.umich.edufrom m5.util import *
533441Sgblack@eecs.umich.edu
543441Sgblack@eecs.umich.eduaddToPath('../common')
553441Sgblack@eecs.umich.edu
563441Sgblack@eecs.umich.edudef getCPUClass(cpu_type):
573441Sgblack@eecs.umich.edu    """Returns the required cpu class and the mode of operation."""
583441Sgblack@eecs.umich.edu    cls = CpuConfig.get(cpu_type)
593441Sgblack@eecs.umich.edu    return cls, cls.memory_mode()
603441Sgblack@eecs.umich.edu
613441Sgblack@eecs.umich.edudef setCPUClass(options):
623441Sgblack@eecs.umich.edu    """Returns two cpu classes and the initial mode of operation.
633441Sgblack@eecs.umich.edu
643441Sgblack@eecs.umich.edu       Restoring from a checkpoint or fast forwarding through a benchmark
653441Sgblack@eecs.umich.edu       can be done using one type of cpu, and then the actual
663441Sgblack@eecs.umich.edu       simulation can be carried out using another type. This function
673441Sgblack@eecs.umich.edu       returns these two types of cpus and the initial mode of operation
683441Sgblack@eecs.umich.edu       depending on the options provided.
693441Sgblack@eecs.umich.edu    """
703441Sgblack@eecs.umich.edu
713441Sgblack@eecs.umich.edu    TmpClass, test_mem_mode = getCPUClass(options.cpu_type)
723441Sgblack@eecs.umich.edu    CPUClass = None
733441Sgblack@eecs.umich.edu    if TmpClass.require_caches() and \
743441Sgblack@eecs.umich.edu            not options.caches and not options.ruby:
753441Sgblack@eecs.umich.edu        fatal("%s must be used with caches" % options.cpu_type)
763441Sgblack@eecs.umich.edu
773441Sgblack@eecs.umich.edu    if options.checkpoint_restore != None:
783441Sgblack@eecs.umich.edu        if options.restore_with_cpu != options.cpu_type:
793627Sgblack@eecs.umich.edu            CPUClass = TmpClass
803441Sgblack@eecs.umich.edu            TmpClass, test_mem_mode = getCPUClass(options.restore_with_cpu)
813441Sgblack@eecs.umich.edu    elif options.fast_forward:
827741Sgblack@eecs.umich.edu        CPUClass = TmpClass
833627Sgblack@eecs.umich.edu        TmpClass = AtomicSimpleCPU
843441Sgblack@eecs.umich.edu        test_mem_mode = 'atomic'
853441Sgblack@eecs.umich.edu
863627Sgblack@eecs.umich.edu    return (TmpClass, test_mem_mode, CPUClass)
877741Sgblack@eecs.umich.edu
883627Sgblack@eecs.umich.edudef setMemClass(options):
893627Sgblack@eecs.umich.edu    """Returns a memory controller class."""
903627Sgblack@eecs.umich.edu
913627Sgblack@eecs.umich.edu    return MemConfig.get(options.mem_type)
923627Sgblack@eecs.umich.edu
937741Sgblack@eecs.umich.edudef setWorkCountOptions(system, options):
943441Sgblack@eecs.umich.edu    if options.work_item_id != None:
953627Sgblack@eecs.umich.edu        system.work_item_id = options.work_item_id
963441Sgblack@eecs.umich.edu    if options.num_work_ids != None:
973441Sgblack@eecs.umich.edu        system.num_work_ids = options.num_work_ids
983441Sgblack@eecs.umich.edu    if options.work_begin_cpu_id_exit != None:
993441Sgblack@eecs.umich.edu        system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit
1003441Sgblack@eecs.umich.edu    if options.work_end_exit_count != None:
1013441Sgblack@eecs.umich.edu        system.work_end_exit_count = options.work_end_exit_count
1023441Sgblack@eecs.umich.edu    if options.work_end_checkpoint_count != None:
1033441Sgblack@eecs.umich.edu        system.work_end_ckpt_count = options.work_end_checkpoint_count
1043441Sgblack@eecs.umich.edu    if options.work_begin_exit_count != None:
1053441Sgblack@eecs.umich.edu        system.work_begin_exit_count = options.work_begin_exit_count
1063441Sgblack@eecs.umich.edu    if options.work_begin_checkpoint_count != None:
1073441Sgblack@eecs.umich.edu        system.work_begin_ckpt_count = options.work_begin_checkpoint_count
1083441Sgblack@eecs.umich.edu    if options.work_cpus_checkpoint_count != None:
1097741Sgblack@eecs.umich.edu        system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count
1103627Sgblack@eecs.umich.edu
1113441Sgblack@eecs.umich.edudef findCptDir(options, cptdir, testsys):
1123441Sgblack@eecs.umich.edu    """Figures out the directory from which the checkpointed state is read.
1133627Sgblack@eecs.umich.edu
1147741Sgblack@eecs.umich.edu    There are two different ways in which the directories holding checkpoints
1153627Sgblack@eecs.umich.edu    can be named --
1163627Sgblack@eecs.umich.edu    1. cpt.<benchmark name>.<instruction count when the checkpoint was taken>
1173627Sgblack@eecs.umich.edu    2. cpt.<some number, usually the tick value when the checkpoint was taken>
1187741Sgblack@eecs.umich.edu
1193627Sgblack@eecs.umich.edu    This function parses through the options to figure out which one of the
1203441Sgblack@eecs.umich.edu    above should be used for selecting the checkpoint, and then figures out
1213627Sgblack@eecs.umich.edu    the appropriate directory.
1227741Sgblack@eecs.umich.edu    """
1233441Sgblack@eecs.umich.edu
1243627Sgblack@eecs.umich.edu    from os.path import isdir, exists
1253441Sgblack@eecs.umich.edu    from os import listdir
1263441Sgblack@eecs.umich.edu    import re
1273441Sgblack@eecs.umich.edu
1283441Sgblack@eecs.umich.edu    if not isdir(cptdir):
1293441Sgblack@eecs.umich.edu        fatal("checkpoint dir %s does not exist!", cptdir)
1303441Sgblack@eecs.umich.edu
1317741Sgblack@eecs.umich.edu    cpt_starttick = 0
1323388Sgblack@eecs.umich.edu    if options.at_instruction or options.simpoint:
13310196SCurtis.Dunham@arm.com        inst = options.checkpoint_restore
1343388Sgblack@eecs.umich.edu        if options.simpoint:
1353388Sgblack@eecs.umich.edu            # assume workload 0 has the simpoint
1363388Sgblack@eecs.umich.edu            if testsys.cpu[0].workload[0].simpoint == 0:
1373388Sgblack@eecs.umich.edu                fatal('Unable to find simpoint')
1383931Ssaidi@eecs.umich.edu            inst += int(testsys.cpu[0].workload[0].simpoint)
1393388Sgblack@eecs.umich.edu
1403388Sgblack@eecs.umich.edu        checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst))
1413388Sgblack@eecs.umich.edu        if not exists(checkpoint_dir):
1423766Sgblack@eecs.umich.edu            fatal("Unable to find checkpoint directory %s", checkpoint_dir)
1433391Sgblack@eecs.umich.edu
1447741Sgblack@eecs.umich.edu    elif options.restore_simpoint_checkpoint:
1454648Sgblack@eecs.umich.edu        # Restore from SimPoint checkpoints
1468442Sgblack@eecs.umich.edu        # Assumes that the checkpoint dir names are formatted as follows:
1473391Sgblack@eecs.umich.edu        dirs = listdir(cptdir)
1487741Sgblack@eecs.umich.edu        expr = re.compile('cpt\.simpoint_(\d+)_inst_(\d+)' +
1493391Sgblack@eecs.umich.edu                    '_weight_([\d\.e\-]+)_interval_(\d+)_warmup_(\d+)')
1503391Sgblack@eecs.umich.edu        cpts = []
1517741Sgblack@eecs.umich.edu        for dir in dirs:
1527741Sgblack@eecs.umich.edu            match = expr.match(dir)
1537741Sgblack@eecs.umich.edu            if match:
1543388Sgblack@eecs.umich.edu                cpts.append(dir)
1553388Sgblack@eecs.umich.edu        cpts.sort()
1563388Sgblack@eecs.umich.edu
1573388Sgblack@eecs.umich.edu        cpt_num = options.checkpoint_restore
1583792Sgblack@eecs.umich.edu        if cpt_num > len(cpts):
1593388Sgblack@eecs.umich.edu            fatal('Checkpoint %d not found', cpt_num)
1603792Sgblack@eecs.umich.edu        checkpoint_dir = joinpath(cptdir, cpts[cpt_num - 1])
16110196SCurtis.Dunham@arm.com        match = expr.match(cpts[cpt_num - 1])
1623388Sgblack@eecs.umich.edu        if match:
1633388Sgblack@eecs.umich.edu            index = int(match.group(1))
1643388Sgblack@eecs.umich.edu            start_inst = int(match.group(2))
1653388Sgblack@eecs.umich.edu            weight_inst = float(match.group(3))
1663931Ssaidi@eecs.umich.edu            interval_length = int(match.group(4))
1673792Sgblack@eecs.umich.edu            warmup_length = int(match.group(5))
1683792Sgblack@eecs.umich.edu        print "Resuming from", checkpoint_dir
1693388Sgblack@eecs.umich.edu        simpoint_start_insts = []
1703766Sgblack@eecs.umich.edu        simpoint_start_insts.append(warmup_length)
1713391Sgblack@eecs.umich.edu        simpoint_start_insts.append(warmup_length + interval_length)
1727741Sgblack@eecs.umich.edu        testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
1734648Sgblack@eecs.umich.edu        if testsys.switch_cpus != None:
1748442Sgblack@eecs.umich.edu            testsys.switch_cpus[0].simpoint_start_insts = simpoint_start_insts
1753391Sgblack@eecs.umich.edu
1763388Sgblack@eecs.umich.edu        print "Resuming from SimPoint",
1773388Sgblack@eecs.umich.edu        print "#%d, start_inst:%d, weight:%f, interval:%d, warmup:%d" % \
1783792Sgblack@eecs.umich.edu            (index, start_inst, weight_inst, interval_length, warmup_length)
1793388Sgblack@eecs.umich.edu
1803792Sgblack@eecs.umich.edu    else:
18110196SCurtis.Dunham@arm.com        dirs = listdir(cptdir)
1823388Sgblack@eecs.umich.edu        expr = re.compile('cpt\.([0-9]+)')
1833388Sgblack@eecs.umich.edu        cpts = []
1843388Sgblack@eecs.umich.edu        for dir in dirs:
1853792Sgblack@eecs.umich.edu            match = expr.match(dir)
1863792Sgblack@eecs.umich.edu            if match:
1878442Sgblack@eecs.umich.edu                cpts.append(match.group(1))
1883388Sgblack@eecs.umich.edu
1897741Sgblack@eecs.umich.edu        cpts.sort(lambda a,b: cmp(long(a), long(b)))
1903792Sgblack@eecs.umich.edu
1913388Sgblack@eecs.umich.edu        cpt_num = options.checkpoint_restore
1923388Sgblack@eecs.umich.edu        if cpt_num > len(cpts):
1933388Sgblack@eecs.umich.edu            fatal('Checkpoint %d not found', cpt_num)
1943388Sgblack@eecs.umich.edu
1953388Sgblack@eecs.umich.edu        cpt_starttick = int(cpts[cpt_num - 1])
1967741Sgblack@eecs.umich.edu        checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])
1973388Sgblack@eecs.umich.edu
19810196SCurtis.Dunham@arm.com    return cpt_starttick, checkpoint_dir
1993388Sgblack@eecs.umich.edu
2003388Sgblack@eecs.umich.edudef scriptCheckpoints(options, maxtick, cptdir):
2013388Sgblack@eecs.umich.edu    if options.at_instruction or options.simpoint:
2027741Sgblack@eecs.umich.edu        checkpoint_inst = int(options.take_checkpoints)
2037741Sgblack@eecs.umich.edu
2043439Sgblack@eecs.umich.edu        # maintain correct offset if we restored from some instruction
2053388Sgblack@eecs.umich.edu        if options.checkpoint_restore != None:
2063931Ssaidi@eecs.umich.edu            checkpoint_inst += options.checkpoint_restore
2073388Sgblack@eecs.umich.edu
2083388Sgblack@eecs.umich.edu        print "Creating checkpoint at inst:%d" % (checkpoint_inst)
2093388Sgblack@eecs.umich.edu        exit_event = m5.simulate()
2103766Sgblack@eecs.umich.edu        exit_cause = exit_event.getCause()
2113391Sgblack@eecs.umich.edu        print "exit cause = %s" % exit_cause
2127741Sgblack@eecs.umich.edu
2133391Sgblack@eecs.umich.edu        # skip checkpoint instructions should they exist
2143391Sgblack@eecs.umich.edu        while exit_cause == "checkpoint":
2157741Sgblack@eecs.umich.edu            exit_event = m5.simulate()
2164648Sgblack@eecs.umich.edu            exit_cause = exit_event.getCause()
2178442Sgblack@eecs.umich.edu
2183388Sgblack@eecs.umich.edu        if exit_cause == "a thread reached the max instruction count":
2197741Sgblack@eecs.umich.edu            m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \
2207741Sgblack@eecs.umich.edu                    (options.bench, checkpoint_inst)))
2217741Sgblack@eecs.umich.edu            print "Checkpoint written."
2223388Sgblack@eecs.umich.edu
2233388Sgblack@eecs.umich.edu    else:
2243388Sgblack@eecs.umich.edu        when, period = options.take_checkpoints.split(",", 1)
2253388Sgblack@eecs.umich.edu        when = int(when)
2263792Sgblack@eecs.umich.edu        period = int(period)
2273388Sgblack@eecs.umich.edu        num_checkpoints = 0
2283792Sgblack@eecs.umich.edu
22910196SCurtis.Dunham@arm.com        exit_event = m5.simulate(when - m5.curTick())
2303388Sgblack@eecs.umich.edu        exit_cause = exit_event.getCause()
2313388Sgblack@eecs.umich.edu        while exit_cause == "checkpoint":
2323388Sgblack@eecs.umich.edu            exit_event = m5.simulate(when - m5.curTick())
2333439Sgblack@eecs.umich.edu            exit_cause = exit_event.getCause()
2343388Sgblack@eecs.umich.edu
2353931Ssaidi@eecs.umich.edu        if exit_cause == "simulate() limit reached":
2363388Sgblack@eecs.umich.edu            m5.checkpoint(joinpath(cptdir, "cpt.%d"))
2374040Ssaidi@eecs.umich.edu            num_checkpoints += 1
2383388Sgblack@eecs.umich.edu
2393388Sgblack@eecs.umich.edu        sim_ticks = when
2403766Sgblack@eecs.umich.edu        max_checkpoints = options.max_checkpoints
2413391Sgblack@eecs.umich.edu
2427741Sgblack@eecs.umich.edu        while num_checkpoints < max_checkpoints and \
2433391Sgblack@eecs.umich.edu                exit_cause == "simulate() limit reached":
2443391Sgblack@eecs.umich.edu            if (sim_ticks + period) > maxtick:
2457741Sgblack@eecs.umich.edu                exit_event = m5.simulate(maxtick - sim_ticks)
2464648Sgblack@eecs.umich.edu                exit_cause = exit_event.getCause()
2478442Sgblack@eecs.umich.edu                break
2483388Sgblack@eecs.umich.edu            else:
2493388Sgblack@eecs.umich.edu                exit_event = m5.simulate(period)
2503388Sgblack@eecs.umich.edu                exit_cause = exit_event.getCause()
2513792Sgblack@eecs.umich.edu                sim_ticks += period
2523388Sgblack@eecs.umich.edu                while exit_event.getCause() == "checkpoint":
2533792Sgblack@eecs.umich.edu                    exit_event = m5.simulate(sim_ticks - m5.curTick())
25410196SCurtis.Dunham@arm.com                if exit_event.getCause() == "simulate() limit reached":
2553388Sgblack@eecs.umich.edu                    m5.checkpoint(joinpath(cptdir, "cpt.%d"))
2563388Sgblack@eecs.umich.edu                    num_checkpoints += 1
2573388Sgblack@eecs.umich.edu
2583388Sgblack@eecs.umich.edu    return exit_event
2593388Sgblack@eecs.umich.edu
2603388Sgblack@eecs.umich.edudef benchCheckpoints(options, maxtick, cptdir):
2618342Sksewell@umich.edu    exit_event = m5.simulate(maxtick - m5.curTick())
2628342Sksewell@umich.edu    exit_cause = exit_event.getCause()
26310196SCurtis.Dunham@arm.com
2648342Sksewell@umich.edu    num_checkpoints = 0
2658342Sksewell@umich.edu    max_checkpoints = options.max_checkpoints
2668342Sksewell@umich.edu
2678342Sksewell@umich.edu    while exit_cause == "checkpoint":
2688342Sksewell@umich.edu        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
2698342Sksewell@umich.edu        num_checkpoints += 1
2708342Sksewell@umich.edu        if num_checkpoints == max_checkpoints:
2718342Sksewell@umich.edu            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
2728342Sksewell@umich.edu            break
2738342Sksewell@umich.edu
2748342Sksewell@umich.edu        exit_event = m5.simulate(maxtick - m5.curTick())
2758342Sksewell@umich.edu        exit_cause = exit_event.getCause()
2768342Sksewell@umich.edu
2778342Sksewell@umich.edu    return exit_event
2788342Sksewell@umich.edu
2798342Sksewell@umich.edu# Set up environment for taking SimPoint checkpoints
2808342Sksewell@umich.edu# Expecting SimPoint files generated by SimPoint 3.2
2818342Sksewell@umich.edudef parseSimpointAnalysisFile(options, testsys):
2828342Sksewell@umich.edu    import re
2838342Sksewell@umich.edu
2848342Sksewell@umich.edu    simpoint_filename, weight_filename, interval_length, warmup_length = \
2858342Sksewell@umich.edu        options.take_simpoint_checkpoints.split(",", 3)
2868342Sksewell@umich.edu    print "simpoint analysis file:", simpoint_filename
2877741Sgblack@eecs.umich.edu    print "simpoint weight file:", weight_filename
2883388Sgblack@eecs.umich.edu    print "interval length:", interval_length
2893388Sgblack@eecs.umich.edu    print "warmup length:", warmup_length
2903388Sgblack@eecs.umich.edu
2913388Sgblack@eecs.umich.edu    interval_length = int(interval_length)
2927741Sgblack@eecs.umich.edu    warmup_length = int(warmup_length)
2933388Sgblack@eecs.umich.edu
2943388Sgblack@eecs.umich.edu    # Simpoint analysis output starts interval counts with 0.
2953388Sgblack@eecs.umich.edu    simpoints = []
2963388Sgblack@eecs.umich.edu    simpoint_start_insts = []
2977741Sgblack@eecs.umich.edu
2983391Sgblack@eecs.umich.edu    # Read in SimPoint analysis files
2993792Sgblack@eecs.umich.edu    simpoint_file = open(simpoint_filename)
3003792Sgblack@eecs.umich.edu    weight_file = open(weight_filename)
3014040Ssaidi@eecs.umich.edu    while True:
3023391Sgblack@eecs.umich.edu        line = simpoint_file.readline()
3033391Sgblack@eecs.umich.edu        if not line:
3043391Sgblack@eecs.umich.edu            break
3057741Sgblack@eecs.umich.edu        m = re.match("(\d+)\s+(\d+)", line)
30610474Sandreas.hansson@arm.com        if m:
3077741Sgblack@eecs.umich.edu            interval = int(m.group(1))
30810474Sandreas.hansson@arm.com        else:
3093391Sgblack@eecs.umich.edu            fatal('unrecognized line in simpoint file!')
3103835Sgblack@eecs.umich.edu
3117741Sgblack@eecs.umich.edu        line = weight_file.readline()
31210474Sandreas.hansson@arm.com        if not line:
3137741Sgblack@eecs.umich.edu            fatal('not enough lines in simpoint weight file!')
31410474Sandreas.hansson@arm.com        m = re.match("([0-9\.e\-]+)\s+(\d+)", line)
3153835Sgblack@eecs.umich.edu        if m:
3163391Sgblack@eecs.umich.edu            weight = float(m.group(1))
3173391Sgblack@eecs.umich.edu        else:
3183391Sgblack@eecs.umich.edu            fatal('unrecognized line in simpoint weight file!')
3193391Sgblack@eecs.umich.edu
3208829Sgblack@eecs.umich.edu        if (interval * interval_length - warmup_length > 0):
3217741Sgblack@eecs.umich.edu            starting_inst_count = \
3228829Sgblack@eecs.umich.edu                interval * interval_length - warmup_length
32310474Sandreas.hansson@arm.com            actual_warmup_length = warmup_length
3248829Sgblack@eecs.umich.edu        else:
32510474Sandreas.hansson@arm.com            # Not enough room for proper warmup
3263391Sgblack@eecs.umich.edu            # Just starting from the beginning
3273391Sgblack@eecs.umich.edu            starting_inst_count = 0
3284648Sgblack@eecs.umich.edu            actual_warmup_length = interval * interval_length
3298795Sgblack@eecs.umich.edu
3308829Sgblack@eecs.umich.edu        simpoints.append((interval, weight, starting_inst_count,
3314648Sgblack@eecs.umich.edu            actual_warmup_length))
3323391Sgblack@eecs.umich.edu
3333391Sgblack@eecs.umich.edu    # Sort SimPoints by starting inst count
3347741Sgblack@eecs.umich.edu    simpoints.sort(key=lambda obj: obj[2])
3357741Sgblack@eecs.umich.edu    for s in simpoints:
3363391Sgblack@eecs.umich.edu        interval, weight, starting_inst_count, actual_warmup_length = s
3373391Sgblack@eecs.umich.edu        print str(interval), str(weight), starting_inst_count, \
3383616Sgblack@eecs.umich.edu            actual_warmup_length
3393391Sgblack@eecs.umich.edu        simpoint_start_insts.append(starting_inst_count)
3403391Sgblack@eecs.umich.edu
3417741Sgblack@eecs.umich.edu    print "Total # of simpoints:", len(simpoints)
3427741Sgblack@eecs.umich.edu    testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
3437741Sgblack@eecs.umich.edu
3447741Sgblack@eecs.umich.edu    return (simpoints, interval_length)
3457741Sgblack@eecs.umich.edu
3463388Sgblack@eecs.umich.edudef takeSimpointCheckpoints(simpoints, interval_length, cptdir):
3473949Sgblack@eecs.umich.edu    num_checkpoints = 0
3483810Sgblack@eecs.umich.edu    index = 0
3493792Sgblack@eecs.umich.edu    last_chkpnt_inst_count = -1
3503792Sgblack@eecs.umich.edu    for simpoint in simpoints:
3513792Sgblack@eecs.umich.edu        interval, weight, starting_inst_count, actual_warmup_length = simpoint
3523439Sgblack@eecs.umich.edu        if starting_inst_count == last_chkpnt_inst_count:
3533439Sgblack@eecs.umich.edu            # checkpoint starting point same as last time
3544040Ssaidi@eecs.umich.edu            # (when warmup period longer than starting point)
3553810Sgblack@eecs.umich.edu            exit_cause = "simpoint starting point found"
3563388Sgblack@eecs.umich.edu            code = 0
3573388Sgblack@eecs.umich.edu        else:
3583388Sgblack@eecs.umich.edu            exit_event = m5.simulate()
3593388Sgblack@eecs.umich.edu
3604040Ssaidi@eecs.umich.edu            # skip checkpoint instructions should they exist
3614648Sgblack@eecs.umich.edu            while exit_event.getCause() == "checkpoint":
3624648Sgblack@eecs.umich.edu                print "Found 'checkpoint' exit event...ignoring..."
3633792Sgblack@eecs.umich.edu                exit_event = m5.simulate()
3643810Sgblack@eecs.umich.edu
3653388Sgblack@eecs.umich.edu            exit_cause = exit_event.getCause()
3663388Sgblack@eecs.umich.edu            code = exit_event.getCode()
367
368        if exit_cause == "simpoint starting point found":
369            m5.checkpoint(joinpath(cptdir,
370                "cpt.simpoint_%02d_inst_%d_weight_%f_interval_%d_warmup_%d"
371                % (index, starting_inst_count, weight, interval_length,
372                actual_warmup_length)))
373            print "Checkpoint #%d written. start inst:%d weight:%f" % \
374                (num_checkpoints, starting_inst_count, weight)
375            num_checkpoints += 1
376            last_chkpnt_inst_count = starting_inst_count
377        else:
378            break
379        index += 1
380
381    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
382    print "%d checkpoints taken" % num_checkpoints
383    sys.exit(code)
384
385def restoreSimpointCheckpoint():
386    exit_event = m5.simulate()
387    exit_cause = exit_event.getCause()
388
389    if exit_cause == "simpoint starting point found":
390        print "Warmed up! Dumping and resetting stats!"
391        m5.stats.dump()
392        m5.stats.reset()
393
394        exit_event = m5.simulate()
395        exit_cause = exit_event.getCause()
396
397        if exit_cause == "simpoint starting point found":
398            print "Done running SimPoint!"
399            sys.exit(exit_event.getCode())
400
401    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
402    sys.exit(exit_event.getCode())
403
404def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq):
405    print "starting switch loop"
406    while True:
407        exit_event = m5.simulate(switch_freq)
408        exit_cause = exit_event.getCause()
409
410        if exit_cause != "simulate() limit reached":
411            return exit_event
412
413        m5.switchCpus(testsys, repeat_switch_cpu_list)
414
415        tmp_cpu_list = []
416        for old_cpu, new_cpu in repeat_switch_cpu_list:
417            tmp_cpu_list.append((new_cpu, old_cpu))
418        repeat_switch_cpu_list = tmp_cpu_list
419
420        if (maxtick - m5.curTick()) <= switch_freq:
421            exit_event = m5.simulate(maxtick - m5.curTick())
422            return exit_event
423
424def run(options, root, testsys, cpu_class):
425    if options.checkpoint_dir:
426        cptdir = options.checkpoint_dir
427    elif m5.options.outdir:
428        cptdir = m5.options.outdir
429    else:
430        cptdir = getcwd()
431
432    if options.fast_forward and options.checkpoint_restore != None:
433        fatal("Can't specify both --fast-forward and --checkpoint-restore")
434
435    if options.standard_switch and not options.caches:
436        fatal("Must specify --caches when using --standard-switch")
437
438    if options.standard_switch and options.repeat_switch:
439        fatal("Can't specify both --standard-switch and --repeat-switch")
440
441    if options.repeat_switch and options.take_checkpoints:
442        fatal("Can't specify both --repeat-switch and --take-checkpoints")
443
444    np = options.num_cpus
445    switch_cpus = None
446
447    if options.prog_interval:
448        for i in xrange(np):
449            testsys.cpu[i].progress_interval = options.prog_interval
450
451    if options.maxinsts:
452        for i in xrange(np):
453            testsys.cpu[i].max_insts_any_thread = options.maxinsts
454
455    if cpu_class:
456        switch_cpus = [cpu_class(switched_out=True, cpu_id=(i))
457                       for i in xrange(np)]
458
459        for i in xrange(np):
460            if options.fast_forward:
461                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
462            switch_cpus[i].system = testsys
463            switch_cpus[i].workload = testsys.cpu[i].workload
464            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
465            switch_cpus[i].progress_interval = \
466                testsys.cpu[i].progress_interval
467            # simulation period
468            if options.maxinsts:
469                switch_cpus[i].max_insts_any_thread = options.maxinsts
470            # Add checker cpu if selected
471            if options.checker:
472                switch_cpus[i].addCheckerCpu()
473
474        # If elastic tracing is enabled attach the elastic trace probe
475        # to the switch CPUs
476        if options.elastic_trace_en:
477            CpuConfig.config_etrace(cpu_class, switch_cpus, options)
478
479        testsys.switch_cpus = switch_cpus
480        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
481
482    if options.repeat_switch:
483        switch_class = getCPUClass(options.cpu_type)[0]
484        if switch_class.require_caches() and \
485                not options.caches:
486            print "%s: Must be used with caches" % str(switch_class)
487            sys.exit(1)
488        if not switch_class.support_take_over():
489            print "%s: CPU switching not supported" % str(switch_class)
490            sys.exit(1)
491
492        repeat_switch_cpus = [switch_class(switched_out=True, \
493                                               cpu_id=(i)) for i in xrange(np)]
494
495        for i in xrange(np):
496            repeat_switch_cpus[i].system = testsys
497            repeat_switch_cpus[i].workload = testsys.cpu[i].workload
498            repeat_switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
499
500            if options.maxinsts:
501                repeat_switch_cpus[i].max_insts_any_thread = options.maxinsts
502
503            if options.checker:
504                repeat_switch_cpus[i].addCheckerCpu()
505
506        testsys.repeat_switch_cpus = repeat_switch_cpus
507
508        if cpu_class:
509            repeat_switch_cpu_list = [(switch_cpus[i], repeat_switch_cpus[i])
510                                      for i in xrange(np)]
511        else:
512            repeat_switch_cpu_list = [(testsys.cpu[i], repeat_switch_cpus[i])
513                                      for i in xrange(np)]
514
515    if options.standard_switch:
516        switch_cpus = [TimingSimpleCPU(switched_out=True, cpu_id=(i))
517                       for i in xrange(np)]
518        switch_cpus_1 = [DerivO3CPU(switched_out=True, cpu_id=(i))
519                        for i in xrange(np)]
520
521        for i in xrange(np):
522            switch_cpus[i].system =  testsys
523            switch_cpus_1[i].system =  testsys
524            switch_cpus[i].workload = testsys.cpu[i].workload
525            switch_cpus_1[i].workload = testsys.cpu[i].workload
526            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
527            switch_cpus_1[i].clk_domain = testsys.cpu[i].clk_domain
528
529            # if restoring, make atomic cpu simulate only a few instructions
530            if options.checkpoint_restore != None:
531                testsys.cpu[i].max_insts_any_thread = 1
532            # Fast forward to specified location if we are not restoring
533            elif options.fast_forward:
534                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
535            # Fast forward to a simpoint (warning: time consuming)
536            elif options.simpoint:
537                if testsys.cpu[i].workload[0].simpoint == 0:
538                    fatal('simpoint not found')
539                testsys.cpu[i].max_insts_any_thread = \
540                    testsys.cpu[i].workload[0].simpoint
541            # No distance specified, just switch
542            else:
543                testsys.cpu[i].max_insts_any_thread = 1
544
545            # warmup period
546            if options.warmup_insts:
547                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
548
549            # simulation period
550            if options.maxinsts:
551                switch_cpus_1[i].max_insts_any_thread = options.maxinsts
552
553            # attach the checker cpu if selected
554            if options.checker:
555                switch_cpus[i].addCheckerCpu()
556                switch_cpus_1[i].addCheckerCpu()
557
558        testsys.switch_cpus = switch_cpus
559        testsys.switch_cpus_1 = switch_cpus_1
560        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
561        switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)]
562
563    # set the checkpoint in the cpu before m5.instantiate is called
564    if options.take_checkpoints != None and \
565           (options.simpoint or options.at_instruction):
566        offset = int(options.take_checkpoints)
567        # Set an instruction break point
568        if options.simpoint:
569            for i in xrange(np):
570                if testsys.cpu[i].workload[0].simpoint == 0:
571                    fatal('no simpoint for testsys.cpu[%d].workload[0]', i)
572                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
573                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
574                # used for output below
575                options.take_checkpoints = checkpoint_inst
576        else:
577            options.take_checkpoints = offset
578            # Set all test cpus with the right number of instructions
579            # for the upcoming simulation
580            for i in xrange(np):
581                testsys.cpu[i].max_insts_any_thread = offset
582
583    if options.take_simpoint_checkpoints != None:
584        simpoints, interval_length = parseSimpointAnalysisFile(options, testsys)
585
586    checkpoint_dir = None
587    if options.checkpoint_restore:
588        cpt_starttick, checkpoint_dir = findCptDir(options, cptdir, testsys)
589    m5.instantiate(checkpoint_dir)
590
591    # Initialization is complete.  If we're not in control of simulation
592    # (that is, if we're a slave simulator acting as a component in another
593    #  'master' simulator) then we're done here.  The other simulator will
594    # call simulate() directly. --initialize-only is used to indicate this.
595    if options.initialize_only:
596        return
597
598    # Handle the max tick settings now that tick frequency was resolved
599    # during system instantiation
600    # NOTE: the maxtick variable here is in absolute ticks, so it must
601    # include any simulated ticks before a checkpoint
602    explicit_maxticks = 0
603    maxtick_from_abs = m5.MaxTick
604    maxtick_from_rel = m5.MaxTick
605    maxtick_from_maxtime = m5.MaxTick
606    if options.abs_max_tick:
607        maxtick_from_abs = options.abs_max_tick
608        explicit_maxticks += 1
609    if options.rel_max_tick:
610        maxtick_from_rel = options.rel_max_tick
611        if options.checkpoint_restore:
612            # NOTE: this may need to be updated if checkpoints ever store
613            # the ticks per simulated second
614            maxtick_from_rel += cpt_starttick
615            if options.at_instruction or options.simpoint:
616                warn("Relative max tick specified with --at-instruction or" \
617                     " --simpoint\n      These options don't specify the " \
618                     "checkpoint start tick, so assuming\n      you mean " \
619                     "absolute max tick")
620        explicit_maxticks += 1
621    if options.maxtime:
622        maxtick_from_maxtime = m5.ticks.fromSeconds(options.maxtime)
623        explicit_maxticks += 1
624    if explicit_maxticks > 1:
625        warn("Specified multiple of --abs-max-tick, --rel-max-tick, --maxtime."\
626             " Using least")
627    maxtick = min([maxtick_from_abs, maxtick_from_rel, maxtick_from_maxtime])
628
629    if options.checkpoint_restore != None and maxtick < cpt_starttick:
630        fatal("Bad maxtick (%d) specified: " \
631              "Checkpoint starts starts from tick: %d", maxtick, cpt_starttick)
632
633    if options.standard_switch or cpu_class:
634        if options.standard_switch:
635            print "Switch at instruction count:%s" % \
636                    str(testsys.cpu[0].max_insts_any_thread)
637            exit_event = m5.simulate()
638        elif cpu_class and options.fast_forward:
639            print "Switch at instruction count:%s" % \
640                    str(testsys.cpu[0].max_insts_any_thread)
641            exit_event = m5.simulate()
642        else:
643            print "Switch at curTick count:%s" % str(10000)
644            exit_event = m5.simulate(10000)
645        print "Switched CPUS @ tick %s" % (m5.curTick())
646
647        m5.switchCpus(testsys, switch_cpu_list)
648
649        if options.standard_switch:
650            print "Switch at instruction count:%d" % \
651                    (testsys.switch_cpus[0].max_insts_any_thread)
652
653            #warmup instruction count may have already been set
654            if options.warmup_insts:
655                exit_event = m5.simulate()
656            else:
657                exit_event = m5.simulate(options.standard_switch)
658            print "Switching CPUS @ tick %s" % (m5.curTick())
659            print "Simulation ends instruction count:%d" % \
660                    (testsys.switch_cpus_1[0].max_insts_any_thread)
661            m5.switchCpus(testsys, switch_cpu_list1)
662
663    # If we're taking and restoring checkpoints, use checkpoint_dir
664    # option only for finding the checkpoints to restore from.  This
665    # lets us test checkpointing by restoring from one set of
666    # checkpoints, generating a second set, and then comparing them.
667    if (options.take_checkpoints or options.take_simpoint_checkpoints) \
668        and options.checkpoint_restore:
669
670        if m5.options.outdir:
671            cptdir = m5.options.outdir
672        else:
673            cptdir = getcwd()
674
675    if options.take_checkpoints != None :
676        # Checkpoints being taken via the command line at <when> and at
677        # subsequent periods of <period>.  Checkpoint instructions
678        # received from the benchmark running are ignored and skipped in
679        # favor of command line checkpoint instructions.
680        exit_event = scriptCheckpoints(options, maxtick, cptdir)
681
682    # Take SimPoint checkpoints
683    elif options.take_simpoint_checkpoints != None:
684        takeSimpointCheckpoints(simpoints, interval_length, cptdir)
685
686    # Restore from SimPoint checkpoints
687    elif options.restore_simpoint_checkpoint != None:
688        restoreSimpointCheckpoint()
689
690    else:
691        if options.fast_forward:
692            m5.stats.reset()
693        print "**** REAL SIMULATION ****"
694
695        # If checkpoints are being taken, then the checkpoint instruction
696        # will occur in the benchmark code it self.
697        if options.repeat_switch and maxtick > options.repeat_switch:
698            exit_event = repeatSwitch(testsys, repeat_switch_cpu_list,
699                                      maxtick, options.repeat_switch)
700        else:
701            exit_event = benchCheckpoints(options, maxtick, cptdir)
702
703    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause())
704    if options.checkpoint_at_end:
705        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
706
707    if not m5.options.interactive:
708        sys.exit(exit_event.getCode())
709