Simulation.py revision 10608:427f988fe6e5
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
46import CpuConfig
47import 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            # simulation period
466            if options.maxinsts:
467                switch_cpus[i].max_insts_any_thread = options.maxinsts
468            # Add checker cpu if selected
469            if options.checker:
470                switch_cpus[i].addCheckerCpu()
471
472        testsys.switch_cpus = switch_cpus
473        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
474
475    if options.repeat_switch:
476        switch_class = getCPUClass(options.cpu_type)[0]
477        if switch_class.require_caches() and \
478                not options.caches:
479            print "%s: Must be used with caches" % str(switch_class)
480            sys.exit(1)
481        if not switch_class.support_take_over():
482            print "%s: CPU switching not supported" % str(switch_class)
483            sys.exit(1)
484
485        repeat_switch_cpus = [switch_class(switched_out=True, \
486                                               cpu_id=(i)) for i in xrange(np)]
487
488        for i in xrange(np):
489            repeat_switch_cpus[i].system = testsys
490            repeat_switch_cpus[i].workload = testsys.cpu[i].workload
491            repeat_switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
492
493            if options.maxinsts:
494                repeat_switch_cpus[i].max_insts_any_thread = options.maxinsts
495
496            if options.checker:
497                repeat_switch_cpus[i].addCheckerCpu()
498
499        testsys.repeat_switch_cpus = repeat_switch_cpus
500
501        if cpu_class:
502            repeat_switch_cpu_list = [(switch_cpus[i], repeat_switch_cpus[i])
503                                      for i in xrange(np)]
504        else:
505            repeat_switch_cpu_list = [(testsys.cpu[i], repeat_switch_cpus[i])
506                                      for i in xrange(np)]
507
508    if options.standard_switch:
509        switch_cpus = [TimingSimpleCPU(switched_out=True, cpu_id=(i))
510                       for i in xrange(np)]
511        switch_cpus_1 = [DerivO3CPU(switched_out=True, cpu_id=(i))
512                        for i in xrange(np)]
513
514        for i in xrange(np):
515            switch_cpus[i].system =  testsys
516            switch_cpus_1[i].system =  testsys
517            switch_cpus[i].workload = testsys.cpu[i].workload
518            switch_cpus_1[i].workload = testsys.cpu[i].workload
519            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
520            switch_cpus_1[i].clk_domain = testsys.cpu[i].clk_domain
521
522            # if restoring, make atomic cpu simulate only a few instructions
523            if options.checkpoint_restore != None:
524                testsys.cpu[i].max_insts_any_thread = 1
525            # Fast forward to specified location if we are not restoring
526            elif options.fast_forward:
527                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
528            # Fast forward to a simpoint (warning: time consuming)
529            elif options.simpoint:
530                if testsys.cpu[i].workload[0].simpoint == 0:
531                    fatal('simpoint not found')
532                testsys.cpu[i].max_insts_any_thread = \
533                    testsys.cpu[i].workload[0].simpoint
534            # No distance specified, just switch
535            else:
536                testsys.cpu[i].max_insts_any_thread = 1
537
538            # warmup period
539            if options.warmup_insts:
540                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
541
542            # simulation period
543            if options.maxinsts:
544                switch_cpus_1[i].max_insts_any_thread = options.maxinsts
545
546            # attach the checker cpu if selected
547            if options.checker:
548                switch_cpus[i].addCheckerCpu()
549                switch_cpus_1[i].addCheckerCpu()
550
551        testsys.switch_cpus = switch_cpus
552        testsys.switch_cpus_1 = switch_cpus_1
553        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
554        switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)]
555
556    # set the checkpoint in the cpu before m5.instantiate is called
557    if options.take_checkpoints != None and \
558           (options.simpoint or options.at_instruction):
559        offset = int(options.take_checkpoints)
560        # Set an instruction break point
561        if options.simpoint:
562            for i in xrange(np):
563                if testsys.cpu[i].workload[0].simpoint == 0:
564                    fatal('no simpoint for testsys.cpu[%d].workload[0]', i)
565                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
566                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
567                # used for output below
568                options.take_checkpoints = checkpoint_inst
569        else:
570            options.take_checkpoints = offset
571            # Set all test cpus with the right number of instructions
572            # for the upcoming simulation
573            for i in xrange(np):
574                testsys.cpu[i].max_insts_any_thread = offset
575
576    if options.take_simpoint_checkpoints != None:
577        simpoints, interval_length = parseSimpointAnalysisFile(options, testsys)
578
579    checkpoint_dir = None
580    if options.checkpoint_restore:
581        cpt_starttick, checkpoint_dir = findCptDir(options, cptdir, testsys)
582    m5.instantiate(checkpoint_dir)
583
584    # Handle the max tick settings now that tick frequency was resolved
585    # during system instantiation
586    # NOTE: the maxtick variable here is in absolute ticks, so it must
587    # include any simulated ticks before a checkpoint
588    explicit_maxticks = 0
589    maxtick_from_abs = m5.MaxTick
590    maxtick_from_rel = m5.MaxTick
591    maxtick_from_maxtime = m5.MaxTick
592    if options.abs_max_tick:
593        maxtick_from_abs = options.abs_max_tick
594        explicit_maxticks += 1
595    if options.rel_max_tick:
596        maxtick_from_rel = options.rel_max_tick
597        if options.checkpoint_restore:
598            # NOTE: this may need to be updated if checkpoints ever store
599            # the ticks per simulated second
600            maxtick_from_rel += cpt_starttick
601            if options.at_instruction or options.simpoint:
602                warn("Relative max tick specified with --at-instruction or" \
603                     " --simpoint\n      These options don't specify the " \
604                     "checkpoint start tick, so assuming\n      you mean " \
605                     "absolute max tick")
606        explicit_maxticks += 1
607    if options.maxtime:
608        maxtick_from_maxtime = m5.ticks.fromSeconds(options.maxtime)
609        explicit_maxticks += 1
610    if explicit_maxticks > 1:
611        warn("Specified multiple of --abs-max-tick, --rel-max-tick, --maxtime."\
612             " Using least")
613    maxtick = min([maxtick_from_abs, maxtick_from_rel, maxtick_from_maxtime])
614
615    if options.checkpoint_restore != None and maxtick < cpt_starttick:
616        fatal("Bad maxtick (%d) specified: " \
617              "Checkpoint starts starts from tick: %d", maxtick, cpt_starttick)
618
619    if options.standard_switch or cpu_class:
620        if options.standard_switch:
621            print "Switch at instruction count:%s" % \
622                    str(testsys.cpu[0].max_insts_any_thread)
623            exit_event = m5.simulate()
624        elif cpu_class and options.fast_forward:
625            print "Switch at instruction count:%s" % \
626                    str(testsys.cpu[0].max_insts_any_thread)
627            exit_event = m5.simulate()
628        else:
629            print "Switch at curTick count:%s" % str(10000)
630            exit_event = m5.simulate(10000)
631        print "Switched CPUS @ tick %s" % (m5.curTick())
632
633        m5.switchCpus(testsys, switch_cpu_list)
634
635        if options.standard_switch:
636            print "Switch at instruction count:%d" % \
637                    (testsys.switch_cpus[0].max_insts_any_thread)
638
639            #warmup instruction count may have already been set
640            if options.warmup_insts:
641                exit_event = m5.simulate()
642            else:
643                exit_event = m5.simulate(options.standard_switch)
644            print "Switching CPUS @ tick %s" % (m5.curTick())
645            print "Simulation ends instruction count:%d" % \
646                    (testsys.switch_cpus_1[0].max_insts_any_thread)
647            m5.switchCpus(testsys, switch_cpu_list1)
648
649    # If we're taking and restoring checkpoints, use checkpoint_dir
650    # option only for finding the checkpoints to restore from.  This
651    # lets us test checkpointing by restoring from one set of
652    # checkpoints, generating a second set, and then comparing them.
653    if (options.take_checkpoints or options.take_simpoint_checkpoints) \
654        and options.checkpoint_restore:
655
656        if m5.options.outdir:
657            cptdir = m5.options.outdir
658        else:
659            cptdir = getcwd()
660
661    if options.take_checkpoints != None :
662        # Checkpoints being taken via the command line at <when> and at
663        # subsequent periods of <period>.  Checkpoint instructions
664        # received from the benchmark running are ignored and skipped in
665        # favor of command line checkpoint instructions.
666        exit_event = scriptCheckpoints(options, maxtick, cptdir)
667
668    # Take SimPoint checkpoints
669    elif options.take_simpoint_checkpoints != None:
670        takeSimpointCheckpoints(simpoints, interval_length, cptdir)
671
672    # Restore from SimPoint checkpoints
673    elif options.restore_simpoint_checkpoint != None:
674        restoreSimpointCheckpoint()
675
676    else:
677        if options.fast_forward:
678            m5.stats.reset()
679        print "**** REAL SIMULATION ****"
680
681        # If checkpoints are being taken, then the checkpoint instruction
682        # will occur in the benchmark code it self.
683        if options.repeat_switch and maxtick > options.repeat_switch:
684            exit_event = repeatSwitch(testsys, repeat_switch_cpu_list,
685                                      maxtick, options.repeat_switch)
686        else:
687            exit_event = benchCheckpoints(options, maxtick, cptdir)
688
689    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause())
690    if options.checkpoint_at_end:
691        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
692
693    if not m5.options.interactive:
694        sys.exit(exit_event.getCode())
695