Simulation.py revision 11688
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    return (TmpClass, test_mem_mode, CPUClass)
87
88def setMemClass(options):
89    """Returns a memory controller class."""
90
91    return MemConfig.get(options.mem_type)
92
93def setWorkCountOptions(system, options):
94    if options.work_item_id != None:
95        system.work_item_id = options.work_item_id
96    if options.num_work_ids != None:
97        system.num_work_ids = options.num_work_ids
98    if options.work_begin_cpu_id_exit != None:
99        system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit
100    if options.work_end_exit_count != None:
101        system.work_end_exit_count = options.work_end_exit_count
102    if options.work_end_checkpoint_count != None:
103        system.work_end_ckpt_count = options.work_end_checkpoint_count
104    if options.work_begin_exit_count != None:
105        system.work_begin_exit_count = options.work_begin_exit_count
106    if options.work_begin_checkpoint_count != None:
107        system.work_begin_ckpt_count = options.work_begin_checkpoint_count
108    if options.work_cpus_checkpoint_count != None:
109        system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count
110
111def findCptDir(options, cptdir, testsys):
112    """Figures out the directory from which the checkpointed state is read.
113
114    There are two different ways in which the directories holding checkpoints
115    can be named --
116    1. cpt.<benchmark name>.<instruction count when the checkpoint was taken>
117    2. cpt.<some number, usually the tick value when the checkpoint was taken>
118
119    This function parses through the options to figure out which one of the
120    above should be used for selecting the checkpoint, and then figures out
121    the appropriate directory.
122    """
123
124    from os.path import isdir, exists
125    from os import listdir
126    import re
127
128    if not isdir(cptdir):
129        fatal("checkpoint dir %s does not exist!", cptdir)
130
131    cpt_starttick = 0
132    if options.at_instruction or options.simpoint:
133        inst = options.checkpoint_restore
134        if options.simpoint:
135            # assume workload 0 has the simpoint
136            if testsys.cpu[0].workload[0].simpoint == 0:
137                fatal('Unable to find simpoint')
138            inst += int(testsys.cpu[0].workload[0].simpoint)
139
140        checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst))
141        if not exists(checkpoint_dir):
142            fatal("Unable to find checkpoint directory %s", checkpoint_dir)
143
144    elif options.restore_simpoint_checkpoint:
145        # Restore from SimPoint checkpoints
146        # Assumes that the checkpoint dir names are formatted as follows:
147        dirs = listdir(cptdir)
148        expr = re.compile('cpt\.simpoint_(\d+)_inst_(\d+)' +
149                    '_weight_([\d\.e\-]+)_interval_(\d+)_warmup_(\d+)')
150        cpts = []
151        for dir in dirs:
152            match = expr.match(dir)
153            if match:
154                cpts.append(dir)
155        cpts.sort()
156
157        cpt_num = options.checkpoint_restore
158        if cpt_num > len(cpts):
159            fatal('Checkpoint %d not found', cpt_num)
160        checkpoint_dir = joinpath(cptdir, cpts[cpt_num - 1])
161        match = expr.match(cpts[cpt_num - 1])
162        if match:
163            index = int(match.group(1))
164            start_inst = int(match.group(2))
165            weight_inst = float(match.group(3))
166            interval_length = int(match.group(4))
167            warmup_length = int(match.group(5))
168        print "Resuming from", checkpoint_dir
169        simpoint_start_insts = []
170        simpoint_start_insts.append(warmup_length)
171        simpoint_start_insts.append(warmup_length + interval_length)
172        testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
173        if testsys.switch_cpus != None:
174            testsys.switch_cpus[0].simpoint_start_insts = simpoint_start_insts
175
176        print "Resuming from SimPoint",
177        print "#%d, start_inst:%d, weight:%f, interval:%d, warmup:%d" % \
178            (index, start_inst, weight_inst, interval_length, warmup_length)
179
180    else:
181        dirs = listdir(cptdir)
182        expr = re.compile('cpt\.([0-9]+)')
183        cpts = []
184        for dir in dirs:
185            match = expr.match(dir)
186            if match:
187                cpts.append(match.group(1))
188
189        cpts.sort(lambda a,b: cmp(long(a), long(b)))
190
191        cpt_num = options.checkpoint_restore
192        if cpt_num > len(cpts):
193            fatal('Checkpoint %d not found', cpt_num)
194
195        cpt_starttick = int(cpts[cpt_num - 1])
196        checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])
197
198    return cpt_starttick, checkpoint_dir
199
200def scriptCheckpoints(options, maxtick, cptdir):
201    if options.at_instruction or options.simpoint:
202        checkpoint_inst = int(options.take_checkpoints)
203
204        # maintain correct offset if we restored from some instruction
205        if options.checkpoint_restore != None:
206            checkpoint_inst += options.checkpoint_restore
207
208        print "Creating checkpoint at inst:%d" % (checkpoint_inst)
209        exit_event = m5.simulate()
210        exit_cause = exit_event.getCause()
211        print "exit cause = %s" % exit_cause
212
213        # skip checkpoint instructions should they exist
214        while exit_cause == "checkpoint":
215            exit_event = m5.simulate()
216            exit_cause = exit_event.getCause()
217
218        if exit_cause == "a thread reached the max instruction count":
219            m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \
220                    (options.bench, checkpoint_inst)))
221            print "Checkpoint written."
222
223    else:
224        when, period = options.take_checkpoints.split(",", 1)
225        when = int(when)
226        period = int(period)
227        num_checkpoints = 0
228
229        exit_event = m5.simulate(when - m5.curTick())
230        exit_cause = exit_event.getCause()
231        while exit_cause == "checkpoint":
232            exit_event = m5.simulate(when - m5.curTick())
233            exit_cause = exit_event.getCause()
234
235        if exit_cause == "simulate() limit reached":
236            m5.checkpoint(joinpath(cptdir, "cpt.%d"))
237            num_checkpoints += 1
238
239        sim_ticks = when
240        max_checkpoints = options.max_checkpoints
241
242        while num_checkpoints < max_checkpoints and \
243                exit_cause == "simulate() limit reached":
244            if (sim_ticks + period) > maxtick:
245                exit_event = m5.simulate(maxtick - sim_ticks)
246                exit_cause = exit_event.getCause()
247                break
248            else:
249                exit_event = m5.simulate(period)
250                exit_cause = exit_event.getCause()
251                sim_ticks += period
252                while exit_event.getCause() == "checkpoint":
253                    exit_event = m5.simulate(sim_ticks - m5.curTick())
254                if exit_event.getCause() == "simulate() limit reached":
255                    m5.checkpoint(joinpath(cptdir, "cpt.%d"))
256                    num_checkpoints += 1
257
258    return exit_event
259
260def benchCheckpoints(options, maxtick, cptdir):
261    exit_event = m5.simulate(maxtick - m5.curTick())
262    exit_cause = exit_event.getCause()
263
264    num_checkpoints = 0
265    max_checkpoints = options.max_checkpoints
266
267    while exit_cause == "checkpoint":
268        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
269        num_checkpoints += 1
270        if num_checkpoints == max_checkpoints:
271            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
272            break
273
274        exit_event = m5.simulate(maxtick - m5.curTick())
275        exit_cause = exit_event.getCause()
276
277    return exit_event
278
279# Set up environment for taking SimPoint checkpoints
280# Expecting SimPoint files generated by SimPoint 3.2
281def parseSimpointAnalysisFile(options, testsys):
282    import re
283
284    simpoint_filename, weight_filename, interval_length, warmup_length = \
285        options.take_simpoint_checkpoints.split(",", 3)
286    print "simpoint analysis file:", simpoint_filename
287    print "simpoint weight file:", weight_filename
288    print "interval length:", interval_length
289    print "warmup length:", warmup_length
290
291    interval_length = int(interval_length)
292    warmup_length = int(warmup_length)
293
294    # Simpoint analysis output starts interval counts with 0.
295    simpoints = []
296    simpoint_start_insts = []
297
298    # Read in SimPoint analysis files
299    simpoint_file = open(simpoint_filename)
300    weight_file = open(weight_filename)
301    while True:
302        line = simpoint_file.readline()
303        if not line:
304            break
305        m = re.match("(\d+)\s+(\d+)", line)
306        if m:
307            interval = int(m.group(1))
308        else:
309            fatal('unrecognized line in simpoint file!')
310
311        line = weight_file.readline()
312        if not line:
313            fatal('not enough lines in simpoint weight file!')
314        m = re.match("([0-9\.e\-]+)\s+(\d+)", line)
315        if m:
316            weight = float(m.group(1))
317        else:
318            fatal('unrecognized line in simpoint weight file!')
319
320        if (interval * interval_length - warmup_length > 0):
321            starting_inst_count = \
322                interval * interval_length - warmup_length
323            actual_warmup_length = warmup_length
324        else:
325            # Not enough room for proper warmup
326            # Just starting from the beginning
327            starting_inst_count = 0
328            actual_warmup_length = interval * interval_length
329
330        simpoints.append((interval, weight, starting_inst_count,
331            actual_warmup_length))
332
333    # Sort SimPoints by starting inst count
334    simpoints.sort(key=lambda obj: obj[2])
335    for s in simpoints:
336        interval, weight, starting_inst_count, actual_warmup_length = s
337        print str(interval), str(weight), starting_inst_count, \
338            actual_warmup_length
339        simpoint_start_insts.append(starting_inst_count)
340
341    print "Total # of simpoints:", len(simpoints)
342    testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
343
344    return (simpoints, interval_length)
345
346def takeSimpointCheckpoints(simpoints, interval_length, cptdir):
347    num_checkpoints = 0
348    index = 0
349    last_chkpnt_inst_count = -1
350    for simpoint in simpoints:
351        interval, weight, starting_inst_count, actual_warmup_length = simpoint
352        if starting_inst_count == last_chkpnt_inst_count:
353            # checkpoint starting point same as last time
354            # (when warmup period longer than starting point)
355            exit_cause = "simpoint starting point found"
356            code = 0
357        else:
358            exit_event = m5.simulate()
359
360            # skip checkpoint instructions should they exist
361            while exit_event.getCause() == "checkpoint":
362                print "Found 'checkpoint' exit event...ignoring..."
363                exit_event = m5.simulate()
364
365            exit_cause = exit_event.getCause()
366            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