Simulation.py revision 12395:322bb93e5f06
1# Copyright (c) 2012-2013 ARM Limited
2# All rights reserved
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder.  You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2006-2008 The Regents of The University of Michigan
14# Copyright (c) 2010 Advanced Micro Devices, Inc.
15# All rights reserved.
16#
17# Redistribution and use in source and binary forms, with or without
18# modification, are permitted provided that the following conditions are
19# met: redistributions of source code must retain the above copyright
20# notice, this list of conditions and the following disclaimer;
21# redistributions in binary form must reproduce the above copyright
22# notice, this list of conditions and the following disclaimer in the
23# documentation and/or other materials provided with the distribution;
24# neither the name of the copyright holders nor the names of its
25# contributors may be used to endorse or promote products derived from
26# this software without specific prior written permission.
27#
28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39#
40# Authors: Lisa Hsu
41
42import sys
43from os import getcwd
44from os.path import join as joinpath
45
46from common import CpuConfig
47from common import MemConfig
48
49import m5
50from m5.defines import buildEnv
51from m5.objects import *
52from m5.util import *
53
54addToPath('../common')
55
56def getCPUClass(cpu_type):
57    """Returns the required cpu class and the mode of operation."""
58    cls = CpuConfig.get(cpu_type)
59    return cls, cls.memory_mode()
60
61def setCPUClass(options):
62    """Returns two cpu classes and the initial mode of operation.
63
64       Restoring from a checkpoint or fast forwarding through a benchmark
65       can be done using one type of cpu, and then the actual
66       simulation can be carried out using another type. This function
67       returns these two types of cpus and the initial mode of operation
68       depending on the options provided.
69    """
70
71    TmpClass, test_mem_mode = getCPUClass(options.cpu_type)
72    CPUClass = None
73    if TmpClass.require_caches() and \
74            not options.caches and not options.ruby:
75        fatal("%s must be used with caches" % options.cpu_type)
76
77    if options.checkpoint_restore != None:
78        if options.restore_with_cpu != options.cpu_type:
79            CPUClass = TmpClass
80            TmpClass, test_mem_mode = getCPUClass(options.restore_with_cpu)
81    elif options.fast_forward:
82        CPUClass = TmpClass
83        TmpClass = AtomicSimpleCPU
84        test_mem_mode = 'atomic'
85
86    # Ruby only supports atomic accesses in noncaching mode
87    if test_mem_mode == 'atomic' and options.ruby:
88        warn("Memory mode will be changed to atomic_noncaching")
89        test_mem_mode = 'atomic_noncaching'
90
91    return (TmpClass, test_mem_mode, CPUClass)
92
93def setMemClass(options):
94    """Returns a memory controller class."""
95
96    return MemConfig.get(options.mem_type)
97
98def setWorkCountOptions(system, options):
99    if options.work_item_id != None:
100        system.work_item_id = options.work_item_id
101    if options.num_work_ids != None:
102        system.num_work_ids = options.num_work_ids
103    if options.work_begin_cpu_id_exit != None:
104        system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit
105    if options.work_end_exit_count != None:
106        system.work_end_exit_count = options.work_end_exit_count
107    if options.work_end_checkpoint_count != None:
108        system.work_end_ckpt_count = options.work_end_checkpoint_count
109    if options.work_begin_exit_count != None:
110        system.work_begin_exit_count = options.work_begin_exit_count
111    if options.work_begin_checkpoint_count != None:
112        system.work_begin_ckpt_count = options.work_begin_checkpoint_count
113    if options.work_cpus_checkpoint_count != None:
114        system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count
115
116def findCptDir(options, cptdir, testsys):
117    """Figures out the directory from which the checkpointed state is read.
118
119    There are two different ways in which the directories holding checkpoints
120    can be named --
121    1. cpt.<benchmark name>.<instruction count when the checkpoint was taken>
122    2. cpt.<some number, usually the tick value when the checkpoint was taken>
123
124    This function parses through the options to figure out which one of the
125    above should be used for selecting the checkpoint, and then figures out
126    the appropriate directory.
127    """
128
129    from os.path import isdir, exists
130    from os import listdir
131    import re
132
133    if not isdir(cptdir):
134        fatal("checkpoint dir %s does not exist!", cptdir)
135
136    cpt_starttick = 0
137    if options.at_instruction or options.simpoint:
138        inst = options.checkpoint_restore
139        if options.simpoint:
140            # assume workload 0 has the simpoint
141            if testsys.cpu[0].workload[0].simpoint == 0:
142                fatal('Unable to find simpoint')
143            inst += int(testsys.cpu[0].workload[0].simpoint)
144
145        checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst))
146        if not exists(checkpoint_dir):
147            fatal("Unable to find checkpoint directory %s", checkpoint_dir)
148
149    elif options.restore_simpoint_checkpoint:
150        # Restore from SimPoint checkpoints
151        # Assumes that the checkpoint dir names are formatted as follows:
152        dirs = listdir(cptdir)
153        expr = re.compile('cpt\.simpoint_(\d+)_inst_(\d+)' +
154                    '_weight_([\d\.e\-]+)_interval_(\d+)_warmup_(\d+)')
155        cpts = []
156        for dir in dirs:
157            match = expr.match(dir)
158            if match:
159                cpts.append(dir)
160        cpts.sort()
161
162        cpt_num = options.checkpoint_restore
163        if cpt_num > len(cpts):
164            fatal('Checkpoint %d not found', cpt_num)
165        checkpoint_dir = joinpath(cptdir, cpts[cpt_num - 1])
166        match = expr.match(cpts[cpt_num - 1])
167        if match:
168            index = int(match.group(1))
169            start_inst = int(match.group(2))
170            weight_inst = float(match.group(3))
171            interval_length = int(match.group(4))
172            warmup_length = int(match.group(5))
173        print "Resuming from", checkpoint_dir
174        simpoint_start_insts = []
175        simpoint_start_insts.append(warmup_length)
176        simpoint_start_insts.append(warmup_length + interval_length)
177        testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
178        if testsys.switch_cpus != None:
179            testsys.switch_cpus[0].simpoint_start_insts = simpoint_start_insts
180
181        print "Resuming from SimPoint",
182        print "#%d, start_inst:%d, weight:%f, interval:%d, warmup:%d" % \
183            (index, start_inst, weight_inst, interval_length, warmup_length)
184
185    else:
186        dirs = listdir(cptdir)
187        expr = re.compile('cpt\.([0-9]+)')
188        cpts = []
189        for dir in dirs:
190            match = expr.match(dir)
191            if match:
192                cpts.append(match.group(1))
193
194        cpts.sort(lambda a,b: cmp(long(a), long(b)))
195
196        cpt_num = options.checkpoint_restore
197        if cpt_num > len(cpts):
198            fatal('Checkpoint %d not found', cpt_num)
199
200        cpt_starttick = int(cpts[cpt_num - 1])
201        checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])
202
203    return cpt_starttick, checkpoint_dir
204
205def scriptCheckpoints(options, maxtick, cptdir):
206    if options.at_instruction or options.simpoint:
207        checkpoint_inst = int(options.take_checkpoints)
208
209        # maintain correct offset if we restored from some instruction
210        if options.checkpoint_restore != None:
211            checkpoint_inst += options.checkpoint_restore
212
213        print "Creating checkpoint at inst:%d" % (checkpoint_inst)
214        exit_event = m5.simulate()
215        exit_cause = exit_event.getCause()
216        print "exit cause = %s" % exit_cause
217
218        # skip checkpoint instructions should they exist
219        while exit_cause == "checkpoint":
220            exit_event = m5.simulate()
221            exit_cause = exit_event.getCause()
222
223        if exit_cause == "a thread reached the max instruction count":
224            m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \
225                    (options.bench, checkpoint_inst)))
226            print "Checkpoint written."
227
228    else:
229        when, period = options.take_checkpoints.split(",", 1)
230        when = int(when)
231        period = int(period)
232        num_checkpoints = 0
233
234        exit_event = m5.simulate(when - m5.curTick())
235        exit_cause = exit_event.getCause()
236        while exit_cause == "checkpoint":
237            exit_event = m5.simulate(when - m5.curTick())
238            exit_cause = exit_event.getCause()
239
240        if exit_cause == "simulate() limit reached":
241            m5.checkpoint(joinpath(cptdir, "cpt.%d"))
242            num_checkpoints += 1
243
244        sim_ticks = when
245        max_checkpoints = options.max_checkpoints
246
247        while num_checkpoints < max_checkpoints and \
248                exit_cause == "simulate() limit reached":
249            if (sim_ticks + period) > maxtick:
250                exit_event = m5.simulate(maxtick - sim_ticks)
251                exit_cause = exit_event.getCause()
252                break
253            else:
254                exit_event = m5.simulate(period)
255                exit_cause = exit_event.getCause()
256                sim_ticks += period
257                while exit_event.getCause() == "checkpoint":
258                    exit_event = m5.simulate(sim_ticks - m5.curTick())
259                if exit_event.getCause() == "simulate() limit reached":
260                    m5.checkpoint(joinpath(cptdir, "cpt.%d"))
261                    num_checkpoints += 1
262
263    return exit_event
264
265def benchCheckpoints(options, maxtick, cptdir):
266    exit_event = m5.simulate(maxtick - m5.curTick())
267    exit_cause = exit_event.getCause()
268
269    num_checkpoints = 0
270    max_checkpoints = options.max_checkpoints
271
272    while exit_cause == "checkpoint":
273        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
274        num_checkpoints += 1
275        if num_checkpoints == max_checkpoints:
276            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
277            break
278
279        exit_event = m5.simulate(maxtick - m5.curTick())
280        exit_cause = exit_event.getCause()
281
282    return exit_event
283
284# Set up environment for taking SimPoint checkpoints
285# Expecting SimPoint files generated by SimPoint 3.2
286def parseSimpointAnalysisFile(options, testsys):
287    import re
288
289    simpoint_filename, weight_filename, interval_length, warmup_length = \
290        options.take_simpoint_checkpoints.split(",", 3)
291    print "simpoint analysis file:", simpoint_filename
292    print "simpoint weight file:", weight_filename
293    print "interval length:", interval_length
294    print "warmup length:", warmup_length
295
296    interval_length = int(interval_length)
297    warmup_length = int(warmup_length)
298
299    # Simpoint analysis output starts interval counts with 0.
300    simpoints = []
301    simpoint_start_insts = []
302
303    # Read in SimPoint analysis files
304    simpoint_file = open(simpoint_filename)
305    weight_file = open(weight_filename)
306    while True:
307        line = simpoint_file.readline()
308        if not line:
309            break
310        m = re.match("(\d+)\s+(\d+)", line)
311        if m:
312            interval = int(m.group(1))
313        else:
314            fatal('unrecognized line in simpoint file!')
315
316        line = weight_file.readline()
317        if not line:
318            fatal('not enough lines in simpoint weight file!')
319        m = re.match("([0-9\.e\-]+)\s+(\d+)", line)
320        if m:
321            weight = float(m.group(1))
322        else:
323            fatal('unrecognized line in simpoint weight file!')
324
325        if (interval * interval_length - warmup_length > 0):
326            starting_inst_count = \
327                interval * interval_length - warmup_length
328            actual_warmup_length = warmup_length
329        else:
330            # Not enough room for proper warmup
331            # Just starting from the beginning
332            starting_inst_count = 0
333            actual_warmup_length = interval * interval_length
334
335        simpoints.append((interval, weight, starting_inst_count,
336            actual_warmup_length))
337
338    # Sort SimPoints by starting inst count
339    simpoints.sort(key=lambda obj: obj[2])
340    for s in simpoints:
341        interval, weight, starting_inst_count, actual_warmup_length = s
342        print str(interval), str(weight), starting_inst_count, \
343            actual_warmup_length
344        simpoint_start_insts.append(starting_inst_count)
345
346    print "Total # of simpoints:", len(simpoints)
347    testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
348
349    return (simpoints, interval_length)
350
351def takeSimpointCheckpoints(simpoints, interval_length, cptdir):
352    num_checkpoints = 0
353    index = 0
354    last_chkpnt_inst_count = -1
355    for simpoint in simpoints:
356        interval, weight, starting_inst_count, actual_warmup_length = simpoint
357        if starting_inst_count == last_chkpnt_inst_count:
358            # checkpoint starting point same as last time
359            # (when warmup period longer than starting point)
360            exit_cause = "simpoint starting point found"
361            code = 0
362        else:
363            exit_event = m5.simulate()
364
365            # skip checkpoint instructions should they exist
366            while exit_event.getCause() == "checkpoint":
367                print "Found 'checkpoint' exit event...ignoring..."
368                exit_event = m5.simulate()
369
370            exit_cause = exit_event.getCause()
371            code = exit_event.getCode()
372
373        if exit_cause == "simpoint starting point found":
374            m5.checkpoint(joinpath(cptdir,
375                "cpt.simpoint_%02d_inst_%d_weight_%f_interval_%d_warmup_%d"
376                % (index, starting_inst_count, weight, interval_length,
377                actual_warmup_length)))
378            print "Checkpoint #%d written. start inst:%d weight:%f" % \
379                (num_checkpoints, starting_inst_count, weight)
380            num_checkpoints += 1
381            last_chkpnt_inst_count = starting_inst_count
382        else:
383            break
384        index += 1
385
386    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
387    print "%d checkpoints taken" % num_checkpoints
388    sys.exit(code)
389
390def restoreSimpointCheckpoint():
391    exit_event = m5.simulate()
392    exit_cause = exit_event.getCause()
393
394    if exit_cause == "simpoint starting point found":
395        print "Warmed up! Dumping and resetting stats!"
396        m5.stats.dump()
397        m5.stats.reset()
398
399        exit_event = m5.simulate()
400        exit_cause = exit_event.getCause()
401
402        if exit_cause == "simpoint starting point found":
403            print "Done running SimPoint!"
404            sys.exit(exit_event.getCode())
405
406    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
407    sys.exit(exit_event.getCode())
408
409def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq):
410    print "starting switch loop"
411    while True:
412        exit_event = m5.simulate(switch_freq)
413        exit_cause = exit_event.getCause()
414
415        if exit_cause != "simulate() limit reached":
416            return exit_event
417
418        m5.switchCpus(testsys, repeat_switch_cpu_list)
419
420        tmp_cpu_list = []
421        for old_cpu, new_cpu in repeat_switch_cpu_list:
422            tmp_cpu_list.append((new_cpu, old_cpu))
423        repeat_switch_cpu_list = tmp_cpu_list
424
425        if (maxtick - m5.curTick()) <= switch_freq:
426            exit_event = m5.simulate(maxtick - m5.curTick())
427            return exit_event
428
429def run(options, root, testsys, cpu_class):
430    if options.checkpoint_dir:
431        cptdir = options.checkpoint_dir
432    elif m5.options.outdir:
433        cptdir = m5.options.outdir
434    else:
435        cptdir = getcwd()
436
437    if options.fast_forward and options.checkpoint_restore != None:
438        fatal("Can't specify both --fast-forward and --checkpoint-restore")
439
440    if options.standard_switch and not options.caches:
441        fatal("Must specify --caches when using --standard-switch")
442
443    if options.standard_switch and options.repeat_switch:
444        fatal("Can't specify both --standard-switch and --repeat-switch")
445
446    if options.repeat_switch and options.take_checkpoints:
447        fatal("Can't specify both --repeat-switch and --take-checkpoints")
448
449    np = options.num_cpus
450    switch_cpus = None
451
452    if options.prog_interval:
453        for i in xrange(np):
454            testsys.cpu[i].progress_interval = options.prog_interval
455
456    if options.maxinsts:
457        for i in xrange(np):
458            testsys.cpu[i].max_insts_any_thread = options.maxinsts
459
460    if cpu_class:
461        switch_cpus = [cpu_class(switched_out=True, cpu_id=(i))
462                       for i in xrange(np)]
463
464        for i in xrange(np):
465            if options.fast_forward:
466                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
467            switch_cpus[i].system = testsys
468            switch_cpus[i].workload = testsys.cpu[i].workload
469            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
470            switch_cpus[i].progress_interval = \
471                testsys.cpu[i].progress_interval
472            switch_cpus[i].isa = testsys.cpu[i].isa
473            # simulation period
474            if options.maxinsts:
475                switch_cpus[i].max_insts_any_thread = options.maxinsts
476            # Add checker cpu if selected
477            if options.checker:
478                switch_cpus[i].addCheckerCpu()
479
480        # If elastic tracing is enabled attach the elastic trace probe
481        # to the switch CPUs
482        if options.elastic_trace_en:
483            CpuConfig.config_etrace(cpu_class, switch_cpus, options)
484
485        testsys.switch_cpus = switch_cpus
486        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
487
488    if options.repeat_switch:
489        switch_class = getCPUClass(options.cpu_type)[0]
490        if switch_class.require_caches() and \
491                not options.caches:
492            print "%s: Must be used with caches" % str(switch_class)
493            sys.exit(1)
494        if not switch_class.support_take_over():
495            print "%s: CPU switching not supported" % str(switch_class)
496            sys.exit(1)
497
498        repeat_switch_cpus = [switch_class(switched_out=True, \
499                                               cpu_id=(i)) for i in xrange(np)]
500
501        for i in xrange(np):
502            repeat_switch_cpus[i].system = testsys
503            repeat_switch_cpus[i].workload = testsys.cpu[i].workload
504            repeat_switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
505            repeat_switch_cpus[i].isa = testsys.cpu[i].isa
506
507            if options.maxinsts:
508                repeat_switch_cpus[i].max_insts_any_thread = options.maxinsts
509
510            if options.checker:
511                repeat_switch_cpus[i].addCheckerCpu()
512
513        testsys.repeat_switch_cpus = repeat_switch_cpus
514
515        if cpu_class:
516            repeat_switch_cpu_list = [(switch_cpus[i], repeat_switch_cpus[i])
517                                      for i in xrange(np)]
518        else:
519            repeat_switch_cpu_list = [(testsys.cpu[i], repeat_switch_cpus[i])
520                                      for i in xrange(np)]
521
522    if options.standard_switch:
523        switch_cpus = [TimingSimpleCPU(switched_out=True, cpu_id=(i))
524                       for i in xrange(np)]
525        switch_cpus_1 = [DerivO3CPU(switched_out=True, cpu_id=(i))
526                        for i in xrange(np)]
527
528        for i in xrange(np):
529            switch_cpus[i].system =  testsys
530            switch_cpus_1[i].system =  testsys
531            switch_cpus[i].workload = testsys.cpu[i].workload
532            switch_cpus_1[i].workload = testsys.cpu[i].workload
533            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
534            switch_cpus_1[i].clk_domain = testsys.cpu[i].clk_domain
535            switch_cpus[i].isa = testsys.cpu[i].isa
536            switch_cpus_1[i].isa = testsys.cpu[i].isa
537
538            # if restoring, make atomic cpu simulate only a few instructions
539            if options.checkpoint_restore != None:
540                testsys.cpu[i].max_insts_any_thread = 1
541            # Fast forward to specified location if we are not restoring
542            elif options.fast_forward:
543                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
544            # Fast forward to a simpoint (warning: time consuming)
545            elif options.simpoint:
546                if testsys.cpu[i].workload[0].simpoint == 0:
547                    fatal('simpoint not found')
548                testsys.cpu[i].max_insts_any_thread = \
549                    testsys.cpu[i].workload[0].simpoint
550            # No distance specified, just switch
551            else:
552                testsys.cpu[i].max_insts_any_thread = 1
553
554            # warmup period
555            if options.warmup_insts:
556                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
557
558            # simulation period
559            if options.maxinsts:
560                switch_cpus_1[i].max_insts_any_thread = options.maxinsts
561
562            # attach the checker cpu if selected
563            if options.checker:
564                switch_cpus[i].addCheckerCpu()
565                switch_cpus_1[i].addCheckerCpu()
566
567        testsys.switch_cpus = switch_cpus
568        testsys.switch_cpus_1 = switch_cpus_1
569        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
570        switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)]
571
572    # set the checkpoint in the cpu before m5.instantiate is called
573    if options.take_checkpoints != None and \
574           (options.simpoint or options.at_instruction):
575        offset = int(options.take_checkpoints)
576        # Set an instruction break point
577        if options.simpoint:
578            for i in xrange(np):
579                if testsys.cpu[i].workload[0].simpoint == 0:
580                    fatal('no simpoint for testsys.cpu[%d].workload[0]', i)
581                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
582                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
583                # used for output below
584                options.take_checkpoints = checkpoint_inst
585        else:
586            options.take_checkpoints = offset
587            # Set all test cpus with the right number of instructions
588            # for the upcoming simulation
589            for i in xrange(np):
590                testsys.cpu[i].max_insts_any_thread = offset
591
592    if options.take_simpoint_checkpoints != None:
593        simpoints, interval_length = parseSimpointAnalysisFile(options, testsys)
594
595    checkpoint_dir = None
596    if options.checkpoint_restore:
597        cpt_starttick, checkpoint_dir = findCptDir(options, cptdir, testsys)
598    m5.instantiate(checkpoint_dir)
599
600    # Initialization is complete.  If we're not in control of simulation
601    # (that is, if we're a slave simulator acting as a component in another
602    #  'master' simulator) then we're done here.  The other simulator will
603    # call simulate() directly. --initialize-only is used to indicate this.
604    if options.initialize_only:
605        return
606
607    # Handle the max tick settings now that tick frequency was resolved
608    # during system instantiation
609    # NOTE: the maxtick variable here is in absolute ticks, so it must
610    # include any simulated ticks before a checkpoint
611    explicit_maxticks = 0
612    maxtick_from_abs = m5.MaxTick
613    maxtick_from_rel = m5.MaxTick
614    maxtick_from_maxtime = m5.MaxTick
615    if options.abs_max_tick:
616        maxtick_from_abs = options.abs_max_tick
617        explicit_maxticks += 1
618    if options.rel_max_tick:
619        maxtick_from_rel = options.rel_max_tick
620        if options.checkpoint_restore:
621            # NOTE: this may need to be updated if checkpoints ever store
622            # the ticks per simulated second
623            maxtick_from_rel += cpt_starttick
624            if options.at_instruction or options.simpoint:
625                warn("Relative max tick specified with --at-instruction or" \
626                     " --simpoint\n      These options don't specify the " \
627                     "checkpoint start tick, so assuming\n      you mean " \
628                     "absolute max tick")
629        explicit_maxticks += 1
630    if options.maxtime:
631        maxtick_from_maxtime = m5.ticks.fromSeconds(options.maxtime)
632        explicit_maxticks += 1
633    if explicit_maxticks > 1:
634        warn("Specified multiple of --abs-max-tick, --rel-max-tick, --maxtime."\
635             " Using least")
636    maxtick = min([maxtick_from_abs, maxtick_from_rel, maxtick_from_maxtime])
637
638    if options.checkpoint_restore != None and maxtick < cpt_starttick:
639        fatal("Bad maxtick (%d) specified: " \
640              "Checkpoint starts starts from tick: %d", maxtick, cpt_starttick)
641
642    if options.standard_switch or cpu_class:
643        if options.standard_switch:
644            print "Switch at instruction count:%s" % \
645                    str(testsys.cpu[0].max_insts_any_thread)
646            exit_event = m5.simulate()
647        elif cpu_class and options.fast_forward:
648            print "Switch at instruction count:%s" % \
649                    str(testsys.cpu[0].max_insts_any_thread)
650            exit_event = m5.simulate()
651        else:
652            print "Switch at curTick count:%s" % str(10000)
653            exit_event = m5.simulate(10000)
654        print "Switched CPUS @ tick %s" % (m5.curTick())
655
656        m5.switchCpus(testsys, switch_cpu_list)
657
658        if options.standard_switch:
659            print "Switch at instruction count:%d" % \
660                    (testsys.switch_cpus[0].max_insts_any_thread)
661
662            #warmup instruction count may have already been set
663            if options.warmup_insts:
664                exit_event = m5.simulate()
665            else:
666                exit_event = m5.simulate(options.standard_switch)
667            print "Switching CPUS @ tick %s" % (m5.curTick())
668            print "Simulation ends instruction count:%d" % \
669                    (testsys.switch_cpus_1[0].max_insts_any_thread)
670            m5.switchCpus(testsys, switch_cpu_list1)
671
672    # If we're taking and restoring checkpoints, use checkpoint_dir
673    # option only for finding the checkpoints to restore from.  This
674    # lets us test checkpointing by restoring from one set of
675    # checkpoints, generating a second set, and then comparing them.
676    if (options.take_checkpoints or options.take_simpoint_checkpoints) \
677        and options.checkpoint_restore:
678
679        if m5.options.outdir:
680            cptdir = m5.options.outdir
681        else:
682            cptdir = getcwd()
683
684    if options.take_checkpoints != None :
685        # Checkpoints being taken via the command line at <when> and at
686        # subsequent periods of <period>.  Checkpoint instructions
687        # received from the benchmark running are ignored and skipped in
688        # favor of command line checkpoint instructions.
689        exit_event = scriptCheckpoints(options, maxtick, cptdir)
690
691    # Take SimPoint checkpoints
692    elif options.take_simpoint_checkpoints != None:
693        takeSimpointCheckpoints(simpoints, interval_length, cptdir)
694
695    # Restore from SimPoint checkpoints
696    elif options.restore_simpoint_checkpoint != None:
697        restoreSimpointCheckpoint()
698
699    else:
700        if options.fast_forward:
701            m5.stats.reset()
702        print "**** REAL SIMULATION ****"
703
704        # If checkpoints are being taken, then the checkpoint instruction
705        # will occur in the benchmark code it self.
706        if options.repeat_switch and maxtick > options.repeat_switch:
707            exit_event = repeatSwitch(testsys, repeat_switch_cpu_list,
708                                      maxtick, options.repeat_switch)
709        else:
710            exit_event = benchCheckpoints(options, maxtick, cptdir)
711
712    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause())
713    if options.checkpoint_at_end:
714        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
715
716    if not m5.options.interactive:
717        sys.exit(exit_event.getCode())
718