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