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