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