Simulation.py revision 8919
15081Sgblack@eecs.umich.edu# Copyright (c) 2006-2008 The Regents of The University of Michigan
25081Sgblack@eecs.umich.edu# Copyright (c) 2010 Advanced Micro Devices, Inc.
35081Sgblack@eecs.umich.edu# All rights reserved.
45081Sgblack@eecs.umich.edu#
55081Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
65081Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
75081Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
85081Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
95081Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
105081Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
115081Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
125081Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
135081Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
145081Sgblack@eecs.umich.edu# this software without specific prior written permission.
155081Sgblack@eecs.umich.edu#
165081Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175081Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185081Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195081Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205081Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215081Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225081Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235081Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245081Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255081Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265081Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275081Sgblack@eecs.umich.edu#
285081Sgblack@eecs.umich.edu# Authors: Lisa Hsu
295081Sgblack@eecs.umich.edu
305081Sgblack@eecs.umich.edufrom os import getcwd
315081Sgblack@eecs.umich.edufrom os.path import join as joinpath
325081Sgblack@eecs.umich.edu
335081Sgblack@eecs.umich.eduimport m5
345081Sgblack@eecs.umich.edufrom m5.defines import buildEnv
355081Sgblack@eecs.umich.edufrom m5.objects import *
365081Sgblack@eecs.umich.edufrom m5.util import *
375081Sgblack@eecs.umich.edufrom O3_ARM_v7a import *
385081Sgblack@eecs.umich.edu
395081Sgblack@eecs.umich.eduaddToPath('../common')
405081Sgblack@eecs.umich.edu
415081Sgblack@eecs.umich.edudef setCPUClass(options):
425081Sgblack@eecs.umich.edu
435081Sgblack@eecs.umich.edu    atomic = False
445081Sgblack@eecs.umich.edu    if options.cpu_type == "timing":
455081Sgblack@eecs.umich.edu        class TmpClass(TimingSimpleCPU): pass
465081Sgblack@eecs.umich.edu    elif options.cpu_type == "detailed" or options.cpu_type == "arm_detailed":
475081Sgblack@eecs.umich.edu        if not options.caches and not options.ruby:
485081Sgblack@eecs.umich.edu            print "O3 CPU must be used with caches"
495081Sgblack@eecs.umich.edu            sys.exit(1)
505081Sgblack@eecs.umich.edu        if options.cpu_type == "arm_detailed":
515081Sgblack@eecs.umich.edu            class TmpClass(O3_ARM_v7a_3): pass
525081Sgblack@eecs.umich.edu        else:
535081Sgblack@eecs.umich.edu            class TmpClass(DerivO3CPU): pass
545081Sgblack@eecs.umich.edu    elif options.cpu_type == "inorder":
555081Sgblack@eecs.umich.edu        if not options.caches:
565081Sgblack@eecs.umich.edu            print "InOrder CPU must be used with caches"
575081Sgblack@eecs.umich.edu            sys.exit(1)
585081Sgblack@eecs.umich.edu        class TmpClass(InOrderCPU): pass
595081Sgblack@eecs.umich.edu    else:
605081Sgblack@eecs.umich.edu        class TmpClass(AtomicSimpleCPU): pass
615081Sgblack@eecs.umich.edu        atomic = True
625081Sgblack@eecs.umich.edu
635081Sgblack@eecs.umich.edu    CPUClass = None
645081Sgblack@eecs.umich.edu    test_mem_mode = 'atomic'
655081Sgblack@eecs.umich.edu
665081Sgblack@eecs.umich.edu    if not atomic:
675081Sgblack@eecs.umich.edu        if options.checkpoint_restore != None:
685081Sgblack@eecs.umich.edu            if options.restore_with_cpu != options.cpu_type:
695081Sgblack@eecs.umich.edu                CPUClass = TmpClass
705081Sgblack@eecs.umich.edu                class TmpClass(AtomicSimpleCPU): pass
715081Sgblack@eecs.umich.edu            else:
725081Sgblack@eecs.umich.edu                if options.restore_with_cpu != "atomic":
735081Sgblack@eecs.umich.edu                    test_mem_mode = 'timing'
745081Sgblack@eecs.umich.edu
755081Sgblack@eecs.umich.edu        elif options.fast_forward:
765081Sgblack@eecs.umich.edu            CPUClass = TmpClass
775081Sgblack@eecs.umich.edu            class TmpClass(AtomicSimpleCPU): pass
785081Sgblack@eecs.umich.edu        else:
795081Sgblack@eecs.umich.edu            test_mem_mode = 'timing'
805081Sgblack@eecs.umich.edu
815081Sgblack@eecs.umich.edu    return (TmpClass, test_mem_mode, CPUClass)
825081Sgblack@eecs.umich.edu
835081Sgblack@eecs.umich.edudef setWorkCountOptions(system, options):
845081Sgblack@eecs.umich.edu    if options.work_item_id != None:
855081Sgblack@eecs.umich.edu        system.work_item_id = options.work_item_id
865081Sgblack@eecs.umich.edu    if options.work_begin_cpu_id_exit != None:
875081Sgblack@eecs.umich.edu        system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit
885081Sgblack@eecs.umich.edu    if options.work_end_exit_count != None:
895081Sgblack@eecs.umich.edu        system.work_end_exit_count = options.work_end_exit_count
905081Sgblack@eecs.umich.edu    if options.work_end_checkpoint_count != None:
915081Sgblack@eecs.umich.edu        system.work_end_ckpt_count = options.work_end_checkpoint_count
925081Sgblack@eecs.umich.edu    if options.work_begin_exit_count != None:
935081Sgblack@eecs.umich.edu        system.work_begin_exit_count = options.work_begin_exit_count
945081Sgblack@eecs.umich.edu    if options.work_begin_checkpoint_count != None:
955081Sgblack@eecs.umich.edu        system.work_begin_ckpt_count = options.work_begin_checkpoint_count
965081Sgblack@eecs.umich.edu    if options.work_cpus_checkpoint_count != None:
975081Sgblack@eecs.umich.edu        system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count
985081Sgblack@eecs.umich.edu
995081Sgblack@eecs.umich.edudef run(options, root, testsys, cpu_class):
1005081Sgblack@eecs.umich.edu    if options.maxtick:
1015081Sgblack@eecs.umich.edu        maxtick = options.maxtick
1025081Sgblack@eecs.umich.edu    elif options.maxtime:
1035081Sgblack@eecs.umich.edu        simtime = m5.ticks.seconds(simtime)
1045081Sgblack@eecs.umich.edu        print "simulating for: ", simtime
1055081Sgblack@eecs.umich.edu        maxtick = simtime
1065081Sgblack@eecs.umich.edu    else:
1075081Sgblack@eecs.umich.edu        maxtick = m5.MaxTick
1085081Sgblack@eecs.umich.edu
1095081Sgblack@eecs.umich.edu    if options.checkpoint_dir:
1105081Sgblack@eecs.umich.edu        cptdir = options.checkpoint_dir
1115081Sgblack@eecs.umich.edu    elif m5.options.outdir:
1125081Sgblack@eecs.umich.edu        cptdir = m5.options.outdir
1135081Sgblack@eecs.umich.edu    else:
1145081Sgblack@eecs.umich.edu        cptdir = getcwd()
1155081Sgblack@eecs.umich.edu
1165081Sgblack@eecs.umich.edu    if options.fast_forward and options.checkpoint_restore != None:
1175081Sgblack@eecs.umich.edu        fatal("Can't specify both --fast-forward and --checkpoint-restore")
1185081Sgblack@eecs.umich.edu
1195081Sgblack@eecs.umich.edu    if options.standard_switch and not options.caches:
1205081Sgblack@eecs.umich.edu        fatal("Must specify --caches when using --standard-switch")
1215081Sgblack@eecs.umich.edu
1225081Sgblack@eecs.umich.edu    np = options.num_cpus
1235081Sgblack@eecs.umich.edu    max_checkpoints = options.max_checkpoints
1245081Sgblack@eecs.umich.edu    switch_cpus = None
1255081Sgblack@eecs.umich.edu
1265081Sgblack@eecs.umich.edu    if options.prog_interval:
1275081Sgblack@eecs.umich.edu        for i in xrange(np):
1285081Sgblack@eecs.umich.edu            testsys.cpu[i].progress_interval = options.prog_interval
1295081Sgblack@eecs.umich.edu
1305081Sgblack@eecs.umich.edu    if options.maxinsts:
1315081Sgblack@eecs.umich.edu        for i in xrange(np):
1325081Sgblack@eecs.umich.edu            testsys.cpu[i].max_insts_any_thread = options.maxinsts
1335081Sgblack@eecs.umich.edu
1345081Sgblack@eecs.umich.edu    if cpu_class:
1355081Sgblack@eecs.umich.edu        switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i))
1365081Sgblack@eecs.umich.edu                       for i in xrange(np)]
1375081Sgblack@eecs.umich.edu
1385081Sgblack@eecs.umich.edu        for i in xrange(np):
1395081Sgblack@eecs.umich.edu            if options.fast_forward:
1405081Sgblack@eecs.umich.edu                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
1415081Sgblack@eecs.umich.edu            switch_cpus[i].system =  testsys
1425081Sgblack@eecs.umich.edu            switch_cpus[i].workload = testsys.cpu[i].workload
1435081Sgblack@eecs.umich.edu            switch_cpus[i].clock = testsys.cpu[0].clock
1445081Sgblack@eecs.umich.edu            # simulation period
1455081Sgblack@eecs.umich.edu            if options.maxinsts:
1465081Sgblack@eecs.umich.edu                switch_cpus[i].max_insts_any_thread = options.maxinsts
1475081Sgblack@eecs.umich.edu            # Add checker cpu if selected
1485081Sgblack@eecs.umich.edu            if options.checker:
1495081Sgblack@eecs.umich.edu                switch_cpus[i].addCheckerCpu()
1505081Sgblack@eecs.umich.edu
1515081Sgblack@eecs.umich.edu        testsys.switch_cpus = switch_cpus
1525081Sgblack@eecs.umich.edu        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
1535081Sgblack@eecs.umich.edu
1545081Sgblack@eecs.umich.edu    if options.standard_switch:
1555081Sgblack@eecs.umich.edu        if not options.caches:
1565081Sgblack@eecs.umich.edu            # O3 CPU must have a cache to work.
1575081Sgblack@eecs.umich.edu            print "O3 CPU must be used with caches"
1585081Sgblack@eecs.umich.edu            sys.exit(1)
1595081Sgblack@eecs.umich.edu
1605081Sgblack@eecs.umich.edu        switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i))
1615081Sgblack@eecs.umich.edu                       for i in xrange(np)]
1625081Sgblack@eecs.umich.edu        switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i))
1635081Sgblack@eecs.umich.edu                        for i in xrange(np)]
1645081Sgblack@eecs.umich.edu
1655081Sgblack@eecs.umich.edu        for i in xrange(np):
1665081Sgblack@eecs.umich.edu            switch_cpus[i].system =  testsys
1675081Sgblack@eecs.umich.edu            switch_cpus_1[i].system =  testsys
1685081Sgblack@eecs.umich.edu            switch_cpus[i].workload = testsys.cpu[i].workload
1695081Sgblack@eecs.umich.edu            switch_cpus_1[i].workload = testsys.cpu[i].workload
1705081Sgblack@eecs.umich.edu            switch_cpus[i].clock = testsys.cpu[0].clock
1715081Sgblack@eecs.umich.edu            switch_cpus_1[i].clock = testsys.cpu[0].clock
1725081Sgblack@eecs.umich.edu
1735081Sgblack@eecs.umich.edu            # if restoring, make atomic cpu simulate only a few instructions
1745081Sgblack@eecs.umich.edu            if options.checkpoint_restore != None:
1755081Sgblack@eecs.umich.edu                testsys.cpu[i].max_insts_any_thread = 1
1765081Sgblack@eecs.umich.edu            # Fast forward to specified location if we are not restoring
1775081Sgblack@eecs.umich.edu            elif options.fast_forward:
1785081Sgblack@eecs.umich.edu                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
1795081Sgblack@eecs.umich.edu            # Fast forward to a simpoint (warning: time consuming)
1805081Sgblack@eecs.umich.edu            elif options.simpoint:
1815081Sgblack@eecs.umich.edu                if testsys.cpu[i].workload[0].simpoint == 0:
1825081Sgblack@eecs.umich.edu                    fatal('simpoint not found')
1835081Sgblack@eecs.umich.edu                testsys.cpu[i].max_insts_any_thread = \
1845081Sgblack@eecs.umich.edu                    testsys.cpu[i].workload[0].simpoint
1855081Sgblack@eecs.umich.edu            # No distance specified, just switch
1865081Sgblack@eecs.umich.edu            else:
1875081Sgblack@eecs.umich.edu                testsys.cpu[i].max_insts_any_thread = 1
1885081Sgblack@eecs.umich.edu
1895081Sgblack@eecs.umich.edu            # warmup period
1905081Sgblack@eecs.umich.edu            if options.warmup_insts:
1915081Sgblack@eecs.umich.edu                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
1925081Sgblack@eecs.umich.edu
1935081Sgblack@eecs.umich.edu            # simulation period
1945081Sgblack@eecs.umich.edu            if options.maxinsts:
1955081Sgblack@eecs.umich.edu                switch_cpus_1[i].max_insts_any_thread = options.maxinsts
1965081Sgblack@eecs.umich.edu
1975081Sgblack@eecs.umich.edu            # attach the checker cpu if selected
1985081Sgblack@eecs.umich.edu            if options.checker:
1995081Sgblack@eecs.umich.edu                switch_cpus[i].addCheckerCpu()
2005081Sgblack@eecs.umich.edu                switch_cpus_1[i].addCheckerCpu()
2015081Sgblack@eecs.umich.edu
2025081Sgblack@eecs.umich.edu        testsys.switch_cpus = switch_cpus
2035081Sgblack@eecs.umich.edu        testsys.switch_cpus_1 = switch_cpus_1
2045081Sgblack@eecs.umich.edu        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
2055081Sgblack@eecs.umich.edu        switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)]
2065081Sgblack@eecs.umich.edu
2075081Sgblack@eecs.umich.edu    # set the checkpoint in the cpu before m5.instantiate is called
2085081Sgblack@eecs.umich.edu    if options.take_checkpoints != None and \
2095081Sgblack@eecs.umich.edu           (options.simpoint or options.at_instruction):
2105081Sgblack@eecs.umich.edu        offset = int(options.take_checkpoints)
2115081Sgblack@eecs.umich.edu        # Set an instruction break point
2125081Sgblack@eecs.umich.edu        if options.simpoint:
2135081Sgblack@eecs.umich.edu            for i in xrange(np):
2145081Sgblack@eecs.umich.edu                if testsys.cpu[i].workload[0].simpoint == 0:
2155081Sgblack@eecs.umich.edu                    fatal('no simpoint for testsys.cpu[%d].workload[0]', i)
2165081Sgblack@eecs.umich.edu                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
2175081Sgblack@eecs.umich.edu                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
2185081Sgblack@eecs.umich.edu                # used for output below
2195081Sgblack@eecs.umich.edu                options.take_checkpoints = checkpoint_inst
2205081Sgblack@eecs.umich.edu        else:
2215081Sgblack@eecs.umich.edu            options.take_checkpoints = offset
2225081Sgblack@eecs.umich.edu            # Set all test cpus with the right number of instructions
2235081Sgblack@eecs.umich.edu            # for the upcoming simulation
2245081Sgblack@eecs.umich.edu            for i in xrange(np):
2255081Sgblack@eecs.umich.edu                testsys.cpu[i].max_insts_any_thread = offset
2265081Sgblack@eecs.umich.edu
2275081Sgblack@eecs.umich.edu    checkpoint_dir = None
2285081Sgblack@eecs.umich.edu    if options.checkpoint_restore != None:
2295081Sgblack@eecs.umich.edu        from os.path import isdir, exists
2305081Sgblack@eecs.umich.edu        from os import listdir
2315081Sgblack@eecs.umich.edu        import re
2325081Sgblack@eecs.umich.edu
2335081Sgblack@eecs.umich.edu        if not isdir(cptdir):
2345081Sgblack@eecs.umich.edu            fatal("checkpoint dir %s does not exist!", cptdir)
2355081Sgblack@eecs.umich.edu
2365081Sgblack@eecs.umich.edu        if options.at_instruction or options.simpoint:
2375081Sgblack@eecs.umich.edu            inst = options.checkpoint_restore
2385081Sgblack@eecs.umich.edu            if options.simpoint:
2395081Sgblack@eecs.umich.edu                # assume workload 0 has the simpoint
2405081Sgblack@eecs.umich.edu                if testsys.cpu[0].workload[0].simpoint == 0:
2415081Sgblack@eecs.umich.edu                    fatal('Unable to find simpoint')
2425081Sgblack@eecs.umich.edu                inst += int(testsys.cpu[0].workload[0].simpoint)
2435081Sgblack@eecs.umich.edu
2445081Sgblack@eecs.umich.edu            checkpoint_dir = joinpath(cptdir,
2455081Sgblack@eecs.umich.edu                                      "cpt.%s.%s" % (options.bench, inst))
2465081Sgblack@eecs.umich.edu            if not exists(checkpoint_dir):
2475081Sgblack@eecs.umich.edu                fatal("Unable to find checkpoint directory %s", checkpoint_dir)
248        else:
249            dirs = listdir(cptdir)
250            expr = re.compile('cpt\.([0-9]*)')
251            cpts = []
252            for dir in dirs:
253                match = expr.match(dir)
254                if match:
255                    cpts.append(match.group(1))
256
257            cpts.sort(lambda a,b: cmp(long(a), long(b)))
258
259            cpt_num = options.checkpoint_restore
260
261            if cpt_num > len(cpts):
262                fatal('Checkpoint %d not found', cpt_num)
263
264            ## Adjust max tick based on our starting tick
265            maxtick = maxtick - int(cpts[cpt_num - 1])
266            checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])
267
268    m5.instantiate(checkpoint_dir)
269
270    if options.standard_switch or cpu_class:
271        if options.standard_switch:
272            print "Switch at instruction count:%s" % \
273                    str(testsys.cpu[0].max_insts_any_thread)
274            exit_event = m5.simulate()
275        elif cpu_class and options.fast_forward:
276            print "Switch at instruction count:%s" % \
277                    str(testsys.cpu[0].max_insts_any_thread)
278            exit_event = m5.simulate()
279        else:
280            print "Switch at curTick count:%s" % str(10000)
281            exit_event = m5.simulate(10000)
282        print "Switched CPUS @ tick %s" % (m5.curTick())
283
284        # when you change to Timing (or Atomic), you halt the system
285        # given as argument.  When you are finished with the system
286        # changes (including switchCpus), you must resume the system
287        # manually.  You DON'T need to resume after just switching
288        # CPUs if you haven't changed anything on the system level.
289
290        m5.changeToTiming(testsys)
291        m5.switchCpus(switch_cpu_list)
292        m5.resume(testsys)
293
294        if options.standard_switch:
295            print "Switch at instruction count:%d" % \
296                    (testsys.switch_cpus[0].max_insts_any_thread)
297
298            #warmup instruction count may have already been set
299            if options.warmup_insts:
300                exit_event = m5.simulate()
301            else:
302                exit_event = m5.simulate(options.warmup)
303            print "Switching CPUS @ tick %s" % (m5.curTick())
304            print "Simulation ends instruction count:%d" % \
305                    (testsys.switch_cpus_1[0].max_insts_any_thread)
306            m5.drain(testsys)
307            m5.switchCpus(switch_cpu_list1)
308            m5.resume(testsys)
309
310    num_checkpoints = 0
311    exit_cause = ''
312
313    # If we're taking and restoring checkpoints, use checkpoint_dir
314    # option only for finding the checkpoints to restore from.  This
315    # lets us test checkpointing by restoring from one set of
316    # checkpoints, generating a second set, and then comparing them.
317    if options.take_checkpoints and options.checkpoint_restore:
318        if m5.options.outdir:
319            cptdir = m5.options.outdir
320        else:
321            cptdir = getcwd()
322
323    # Checkpoints being taken via the command line at <when> and at
324    # subsequent periods of <period>.  Checkpoint instructions
325    # received from the benchmark running are ignored and skipped in
326    # favor of command line checkpoint instructions.
327    if options.take_checkpoints != None :
328        if options.at_instruction or options.simpoint:
329            checkpoint_inst = int(options.take_checkpoints)
330
331            # maintain correct offset if we restored from some instruction
332            if options.checkpoint_restore != None:
333                checkpoint_inst += options.checkpoint_restore
334
335            print "Creating checkpoint at inst:%d" % (checkpoint_inst)
336            exit_event = m5.simulate()
337            print "exit cause = %s" % (exit_event.getCause())
338
339            # skip checkpoint instructions should they exist
340            while exit_event.getCause() == "checkpoint":
341                exit_event = m5.simulate()
342
343            if exit_event.getCause() == \
344                   "a thread reached the max instruction count":
345                m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \
346                        (options.bench, checkpoint_inst)))
347                print "Checkpoint written."
348                num_checkpoints += 1
349
350            if exit_event.getCause() == "user interrupt received":
351                exit_cause = exit_event.getCause();
352        else:
353            when, period = options.take_checkpoints.split(",", 1)
354            when = int(when)
355            period = int(period)
356
357            exit_event = m5.simulate(when)
358            while exit_event.getCause() == "checkpoint":
359                exit_event = m5.simulate(when - m5.curTick())
360
361            if exit_event.getCause() == "simulate() limit reached":
362                m5.checkpoint(joinpath(cptdir, "cpt.%d"))
363                num_checkpoints += 1
364
365            sim_ticks = when
366            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
367            while num_checkpoints < max_checkpoints and \
368                    exit_event.getCause() == "simulate() limit reached":
369                if (sim_ticks + period) > maxtick:
370                    exit_event = m5.simulate(maxtick - sim_ticks)
371                    exit_cause = exit_event.getCause()
372                    break
373                else:
374                    exit_event = m5.simulate(period)
375                    sim_ticks += period
376                    while exit_event.getCause() == "checkpoint":
377                        exit_event = m5.simulate(sim_ticks - m5.curTick())
378                    if exit_event.getCause() == "simulate() limit reached":
379                        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
380                        num_checkpoints += 1
381
382            if exit_event.getCause() != "simulate() limit reached":
383                exit_cause = exit_event.getCause();
384
385    else: # no checkpoints being taken via this script
386        if options.fast_forward:
387            m5.stats.reset()
388        print "**** REAL SIMULATION ****"
389        exit_event = m5.simulate(maxtick)
390
391        while exit_event.getCause() == "checkpoint":
392            m5.checkpoint(joinpath(cptdir, "cpt.%d"))
393            num_checkpoints += 1
394            if num_checkpoints == max_checkpoints:
395                exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
396                break
397
398            exit_event = m5.simulate(maxtick - m5.curTick())
399            exit_cause = exit_event.getCause()
400
401    if exit_cause == '':
402        exit_cause = exit_event.getCause()
403    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
404
405    if options.checkpoint_at_end:
406        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
407
408