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