Simulation.py revision 11320
112855Sgabeblack@google.com# Copyright (c) 2012-2013 ARM Limited
212855Sgabeblack@google.com# All rights reserved
312855Sgabeblack@google.com#
412855Sgabeblack@google.com# The license below extends only to copyright in the software and shall
512855Sgabeblack@google.com# not be construed as granting a license to any other intellectual
612855Sgabeblack@google.com# property including but not limited to intellectual property relating
712855Sgabeblack@google.com# to a hardware implementation of the functionality of the software
812855Sgabeblack@google.com# licensed hereunder.  You may use the software subject to the license
912855Sgabeblack@google.com# terms below provided that you ensure that this notice is replicated
1012855Sgabeblack@google.com# unmodified and in its entirety in all distributions of the software,
1112855Sgabeblack@google.com# modified or unmodified, in source code or in binary form.
1212855Sgabeblack@google.com#
1312855Sgabeblack@google.com# Copyright (c) 2006-2008 The Regents of The University of Michigan
1412855Sgabeblack@google.com# Copyright (c) 2010 Advanced Micro Devices, Inc.
1512855Sgabeblack@google.com# All rights reserved.
1612855Sgabeblack@google.com#
1712855Sgabeblack@google.com# Redistribution and use in source and binary forms, with or without
1812855Sgabeblack@google.com# modification, are permitted provided that the following conditions are
1912855Sgabeblack@google.com# met: redistributions of source code must retain the above copyright
2012855Sgabeblack@google.com# notice, this list of conditions and the following disclaimer;
2112855Sgabeblack@google.com# redistributions in binary form must reproduce the above copyright
2212855Sgabeblack@google.com# notice, this list of conditions and the following disclaimer in the
2312855Sgabeblack@google.com# documentation and/or other materials provided with the distribution;
2412855Sgabeblack@google.com# neither the name of the copyright holders nor the names of its
2512855Sgabeblack@google.com# contributors may be used to endorse or promote products derived from
2612855Sgabeblack@google.com# this software without specific prior written permission.
2712855Sgabeblack@google.com#
2812855Sgabeblack@google.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2912855Sgabeblack@google.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3012855Sgabeblack@google.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3112855Sgabeblack@google.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3212855Sgabeblack@google.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3312855Sgabeblack@google.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3412855Sgabeblack@google.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3512855Sgabeblack@google.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3612855Sgabeblack@google.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3712855Sgabeblack@google.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3812855Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3912855Sgabeblack@google.com#
4012855Sgabeblack@google.com# Authors: Lisa Hsu
4112855Sgabeblack@google.com
4212855Sgabeblack@google.comimport sys
4312855Sgabeblack@google.comfrom os import getcwd
4412855Sgabeblack@google.comfrom os.path import join as joinpath
4512855Sgabeblack@google.com
4612855Sgabeblack@google.comimport CpuConfig
4712855Sgabeblack@google.comimport MemConfig
4812855Sgabeblack@google.com
4912855Sgabeblack@google.comimport m5
5012855Sgabeblack@google.comfrom m5.defines import buildEnv
5112855Sgabeblack@google.comfrom m5.objects import *
5212855Sgabeblack@google.comfrom m5.util import *
5312855Sgabeblack@google.com
5412855Sgabeblack@google.comaddToPath('../common')
5512855Sgabeblack@google.com
5612855Sgabeblack@google.comdef getCPUClass(cpu_type):
5712855Sgabeblack@google.com    """Returns the required cpu class and the mode of operation."""
5812855Sgabeblack@google.com    cls = CpuConfig.get(cpu_type)
5912855Sgabeblack@google.com    return cls, cls.memory_mode()
6012855Sgabeblack@google.com
6112855Sgabeblack@google.comdef setCPUClass(options):
6212855Sgabeblack@google.com    """Returns two cpu classes and the initial mode of operation.
6312855Sgabeblack@google.com
6412855Sgabeblack@google.com       Restoring from a checkpoint or fast forwarding through a benchmark
6512855Sgabeblack@google.com       can be done using one type of cpu, and then the actual
6612855Sgabeblack@google.com       simulation can be carried out using another type. This function
6712855Sgabeblack@google.com       returns these two types of cpus and the initial mode of operation
6812855Sgabeblack@google.com       depending on the options provided.
6912855Sgabeblack@google.com    """
7012855Sgabeblack@google.com
7112855Sgabeblack@google.com    TmpClass, test_mem_mode = getCPUClass(options.cpu_type)
7212855Sgabeblack@google.com    CPUClass = None
7312855Sgabeblack@google.com    if TmpClass.require_caches() and \
7412855Sgabeblack@google.com            not options.caches and not options.ruby:
7512855Sgabeblack@google.com        fatal("%s must be used with caches" % options.cpu_type)
7612855Sgabeblack@google.com
7712855Sgabeblack@google.com    if options.checkpoint_restore != None:
7812855Sgabeblack@google.com        if options.restore_with_cpu != options.cpu_type:
7912855Sgabeblack@google.com            CPUClass = TmpClass
8012855Sgabeblack@google.com            TmpClass, test_mem_mode = getCPUClass(options.restore_with_cpu)
8112855Sgabeblack@google.com    elif options.fast_forward:
8212855Sgabeblack@google.com        CPUClass = TmpClass
8312855Sgabeblack@google.com        TmpClass = AtomicSimpleCPU
8412855Sgabeblack@google.com        test_mem_mode = 'atomic'
8512855Sgabeblack@google.com
8612855Sgabeblack@google.com    return (TmpClass, test_mem_mode, CPUClass)
8712855Sgabeblack@google.com
8812855Sgabeblack@google.comdef setMemClass(options):
8912855Sgabeblack@google.com    """Returns a memory controller class."""
9012855Sgabeblack@google.com
9112855Sgabeblack@google.com    return MemConfig.get(options.mem_type)
9212855Sgabeblack@google.com
9312855Sgabeblack@google.comdef setWorkCountOptions(system, options):
9412855Sgabeblack@google.com    if options.work_item_id != None:
9512855Sgabeblack@google.com        system.work_item_id = options.work_item_id
9612855Sgabeblack@google.com    if options.num_work_ids != None:
9712855Sgabeblack@google.com        system.num_work_ids = options.num_work_ids
9812855Sgabeblack@google.com    if options.work_begin_cpu_id_exit != None:
9912855Sgabeblack@google.com        system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit
10012855Sgabeblack@google.com    if options.work_end_exit_count != None:
10112855Sgabeblack@google.com        system.work_end_exit_count = options.work_end_exit_count
10212855Sgabeblack@google.com    if options.work_end_checkpoint_count != None:
10312855Sgabeblack@google.com        system.work_end_ckpt_count = options.work_end_checkpoint_count
10412855Sgabeblack@google.com    if options.work_begin_exit_count != None:
10512855Sgabeblack@google.com        system.work_begin_exit_count = options.work_begin_exit_count
10612855Sgabeblack@google.com    if options.work_begin_checkpoint_count != None:
10712855Sgabeblack@google.com        system.work_begin_ckpt_count = options.work_begin_checkpoint_count
10812855Sgabeblack@google.com    if options.work_cpus_checkpoint_count != None:
10912855Sgabeblack@google.com        system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count
11012855Sgabeblack@google.com
11112855Sgabeblack@google.comdef findCptDir(options, cptdir, testsys):
11212855Sgabeblack@google.com    """Figures out the directory from which the checkpointed state is read.
11312855Sgabeblack@google.com
11412855Sgabeblack@google.com    There are two different ways in which the directories holding checkpoints
11512855Sgabeblack@google.com    can be named --
11612855Sgabeblack@google.com    1. cpt.<benchmark name>.<instruction count when the checkpoint was taken>
11712855Sgabeblack@google.com    2. cpt.<some number, usually the tick value when the checkpoint was taken>
11812855Sgabeblack@google.com
11912855Sgabeblack@google.com    This function parses through the options to figure out which one of the
12012855Sgabeblack@google.com    above should be used for selecting the checkpoint, and then figures out
12112855Sgabeblack@google.com    the appropriate directory.
12212855Sgabeblack@google.com    """
12312855Sgabeblack@google.com
12412855Sgabeblack@google.com    from os.path import isdir, exists
12512855Sgabeblack@google.com    from os import listdir
12612855Sgabeblack@google.com    import re
12712855Sgabeblack@google.com
12812855Sgabeblack@google.com    if not isdir(cptdir):
12912855Sgabeblack@google.com        fatal("checkpoint dir %s does not exist!", cptdir)
13012855Sgabeblack@google.com
13112855Sgabeblack@google.com    cpt_starttick = 0
13212855Sgabeblack@google.com    if options.at_instruction or options.simpoint:
13312855Sgabeblack@google.com        inst = options.checkpoint_restore
13412855Sgabeblack@google.com        if options.simpoint:
13512855Sgabeblack@google.com            # assume workload 0 has the simpoint
13612855Sgabeblack@google.com            if testsys.cpu[0].workload[0].simpoint == 0:
13712855Sgabeblack@google.com                fatal('Unable to find simpoint')
13812855Sgabeblack@google.com            inst += int(testsys.cpu[0].workload[0].simpoint)
13912855Sgabeblack@google.com
14012855Sgabeblack@google.com        checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst))
14112855Sgabeblack@google.com        if not exists(checkpoint_dir):
14212855Sgabeblack@google.com            fatal("Unable to find checkpoint directory %s", checkpoint_dir)
14312855Sgabeblack@google.com
14412855Sgabeblack@google.com    elif options.restore_simpoint_checkpoint:
14512855Sgabeblack@google.com        # Restore from SimPoint checkpoints
14612855Sgabeblack@google.com        # Assumes that the checkpoint dir names are formatted as follows:
14712855Sgabeblack@google.com        dirs = listdir(cptdir)
14812855Sgabeblack@google.com        expr = re.compile('cpt\.simpoint_(\d+)_inst_(\d+)' +
14912855Sgabeblack@google.com                    '_weight_([\d\.e\-]+)_interval_(\d+)_warmup_(\d+)')
15012855Sgabeblack@google.com        cpts = []
15112855Sgabeblack@google.com        for dir in dirs:
15212855Sgabeblack@google.com            match = expr.match(dir)
15312855Sgabeblack@google.com            if match:
15412855Sgabeblack@google.com                cpts.append(dir)
15512855Sgabeblack@google.com        cpts.sort()
15612855Sgabeblack@google.com
15712855Sgabeblack@google.com        cpt_num = options.checkpoint_restore
158        if cpt_num > len(cpts):
159            fatal('Checkpoint %d not found', cpt_num)
160        checkpoint_dir = joinpath(cptdir, cpts[cpt_num - 1])
161        match = expr.match(cpts[cpt_num - 1])
162        if match:
163            index = int(match.group(1))
164            start_inst = int(match.group(2))
165            weight_inst = float(match.group(3))
166            interval_length = int(match.group(4))
167            warmup_length = int(match.group(5))
168        print "Resuming from", checkpoint_dir
169        simpoint_start_insts = []
170        simpoint_start_insts.append(warmup_length)
171        simpoint_start_insts.append(warmup_length + interval_length)
172        testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
173        if testsys.switch_cpus != None:
174            testsys.switch_cpus[0].simpoint_start_insts = simpoint_start_insts
175
176        print "Resuming from SimPoint",
177        print "#%d, start_inst:%d, weight:%f, interval:%d, warmup:%d" % \
178            (index, start_inst, weight_inst, interval_length, warmup_length)
179
180    else:
181        dirs = listdir(cptdir)
182        expr = re.compile('cpt\.([0-9]+)')
183        cpts = []
184        for dir in dirs:
185            match = expr.match(dir)
186            if match:
187                cpts.append(match.group(1))
188
189        cpts.sort(lambda a,b: cmp(long(a), long(b)))
190
191        cpt_num = options.checkpoint_restore
192        if cpt_num > len(cpts):
193            fatal('Checkpoint %d not found', cpt_num)
194
195        cpt_starttick = int(cpts[cpt_num - 1])
196        checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])
197
198    return cpt_starttick, checkpoint_dir
199
200def scriptCheckpoints(options, maxtick, cptdir):
201    if options.at_instruction or options.simpoint:
202        checkpoint_inst = int(options.take_checkpoints)
203
204        # maintain correct offset if we restored from some instruction
205        if options.checkpoint_restore != None:
206            checkpoint_inst += options.checkpoint_restore
207
208        print "Creating checkpoint at inst:%d" % (checkpoint_inst)
209        exit_event = m5.simulate()
210        exit_cause = exit_event.getCause()
211        print "exit cause = %s" % exit_cause
212
213        # skip checkpoint instructions should they exist
214        while exit_cause == "checkpoint":
215            exit_event = m5.simulate()
216            exit_cause = exit_event.getCause()
217
218        if exit_cause == "a thread reached the max instruction count":
219            m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \
220                    (options.bench, checkpoint_inst)))
221            print "Checkpoint written."
222
223    else:
224        when, period = options.take_checkpoints.split(",", 1)
225        when = int(when)
226        period = int(period)
227        num_checkpoints = 0
228
229        exit_event = m5.simulate(when - m5.curTick())
230        exit_cause = exit_event.getCause()
231        while exit_cause == "checkpoint":
232            exit_event = m5.simulate(when - m5.curTick())
233            exit_cause = exit_event.getCause()
234
235        if exit_cause == "simulate() limit reached":
236            m5.checkpoint(joinpath(cptdir, "cpt.%d"))
237            num_checkpoints += 1
238
239        sim_ticks = when
240        max_checkpoints = options.max_checkpoints
241
242        while num_checkpoints < max_checkpoints and \
243                exit_cause == "simulate() limit reached":
244            if (sim_ticks + period) > maxtick:
245                exit_event = m5.simulate(maxtick - sim_ticks)
246                exit_cause = exit_event.getCause()
247                break
248            else:
249                exit_event = m5.simulate(period)
250                exit_cause = exit_event.getCause()
251                sim_ticks += period
252                while exit_event.getCause() == "checkpoint":
253                    exit_event = m5.simulate(sim_ticks - m5.curTick())
254                if exit_event.getCause() == "simulate() limit reached":
255                    m5.checkpoint(joinpath(cptdir, "cpt.%d"))
256                    num_checkpoints += 1
257
258    return exit_event
259
260def benchCheckpoints(options, maxtick, cptdir):
261    exit_event = m5.simulate(maxtick - m5.curTick())
262    exit_cause = exit_event.getCause()
263
264    num_checkpoints = 0
265    max_checkpoints = options.max_checkpoints
266
267    while exit_cause == "checkpoint":
268        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
269        num_checkpoints += 1
270        if num_checkpoints == max_checkpoints:
271            exit_cause = "maximum %d checkpoints dropped" % max_checkpoints
272            break
273
274        exit_event = m5.simulate(maxtick - m5.curTick())
275        exit_cause = exit_event.getCause()
276
277    return exit_event
278
279# Set up environment for taking SimPoint checkpoints
280# Expecting SimPoint files generated by SimPoint 3.2
281def parseSimpointAnalysisFile(options, testsys):
282    import re
283
284    simpoint_filename, weight_filename, interval_length, warmup_length = \
285        options.take_simpoint_checkpoints.split(",", 3)
286    print "simpoint analysis file:", simpoint_filename
287    print "simpoint weight file:", weight_filename
288    print "interval length:", interval_length
289    print "warmup length:", warmup_length
290
291    interval_length = int(interval_length)
292    warmup_length = int(warmup_length)
293
294    # Simpoint analysis output starts interval counts with 0.
295    simpoints = []
296    simpoint_start_insts = []
297
298    # Read in SimPoint analysis files
299    simpoint_file = open(simpoint_filename)
300    weight_file = open(weight_filename)
301    while True:
302        line = simpoint_file.readline()
303        if not line:
304            break
305        m = re.match("(\d+)\s+(\d+)", line)
306        if m:
307            interval = int(m.group(1))
308        else:
309            fatal('unrecognized line in simpoint file!')
310
311        line = weight_file.readline()
312        if not line:
313            fatal('not enough lines in simpoint weight file!')
314        m = re.match("([0-9\.e\-]+)\s+(\d+)", line)
315        if m:
316            weight = float(m.group(1))
317        else:
318            fatal('unrecognized line in simpoint weight file!')
319
320        if (interval * interval_length - warmup_length > 0):
321            starting_inst_count = \
322                interval * interval_length - warmup_length
323            actual_warmup_length = warmup_length
324        else:
325            # Not enough room for proper warmup
326            # Just starting from the beginning
327            starting_inst_count = 0
328            actual_warmup_length = interval * interval_length
329
330        simpoints.append((interval, weight, starting_inst_count,
331            actual_warmup_length))
332
333    # Sort SimPoints by starting inst count
334    simpoints.sort(key=lambda obj: obj[2])
335    for s in simpoints:
336        interval, weight, starting_inst_count, actual_warmup_length = s
337        print str(interval), str(weight), starting_inst_count, \
338            actual_warmup_length
339        simpoint_start_insts.append(starting_inst_count)
340
341    print "Total # of simpoints:", len(simpoints)
342    testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
343
344    return (simpoints, interval_length)
345
346def takeSimpointCheckpoints(simpoints, interval_length, cptdir):
347    num_checkpoints = 0
348    index = 0
349    last_chkpnt_inst_count = -1
350    for simpoint in simpoints:
351        interval, weight, starting_inst_count, actual_warmup_length = simpoint
352        if starting_inst_count == last_chkpnt_inst_count:
353            # checkpoint starting point same as last time
354            # (when warmup period longer than starting point)
355            exit_cause = "simpoint starting point found"
356            code = 0
357        else:
358            exit_event = m5.simulate()
359
360            # skip checkpoint instructions should they exist
361            while exit_event.getCause() == "checkpoint":
362                print "Found 'checkpoint' exit event...ignoring..."
363                exit_event = m5.simulate()
364
365            exit_cause = exit_event.getCause()
366            code = exit_event.getCode()
367
368        if exit_cause == "simpoint starting point found":
369            m5.checkpoint(joinpath(cptdir,
370                "cpt.simpoint_%02d_inst_%d_weight_%f_interval_%d_warmup_%d"
371                % (index, starting_inst_count, weight, interval_length,
372                actual_warmup_length)))
373            print "Checkpoint #%d written. start inst:%d weight:%f" % \
374                (num_checkpoints, starting_inst_count, weight)
375            num_checkpoints += 1
376            last_chkpnt_inst_count = starting_inst_count
377        else:
378            break
379        index += 1
380
381    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
382    print "%d checkpoints taken" % num_checkpoints
383    sys.exit(code)
384
385def restoreSimpointCheckpoint():
386    exit_event = m5.simulate()
387    exit_cause = exit_event.getCause()
388
389    if exit_cause == "simpoint starting point found":
390        print "Warmed up! Dumping and resetting stats!"
391        m5.stats.dump()
392        m5.stats.reset()
393
394        exit_event = m5.simulate()
395        exit_cause = exit_event.getCause()
396
397        if exit_cause == "simpoint starting point found":
398            print "Done running SimPoint!"
399            sys.exit(exit_event.getCode())
400
401    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
402    sys.exit(exit_event.getCode())
403
404def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq):
405    print "starting switch loop"
406    while True:
407        exit_event = m5.simulate(switch_freq)
408        exit_cause = exit_event.getCause()
409
410        if exit_cause != "simulate() limit reached":
411            return exit_event
412
413        m5.switchCpus(testsys, repeat_switch_cpu_list)
414
415        tmp_cpu_list = []
416        for old_cpu, new_cpu in repeat_switch_cpu_list:
417            tmp_cpu_list.append((new_cpu, old_cpu))
418        repeat_switch_cpu_list = tmp_cpu_list
419
420        if (maxtick - m5.curTick()) <= switch_freq:
421            exit_event = m5.simulate(maxtick - m5.curTick())
422            return exit_event
423
424def run(options, root, testsys, cpu_class):
425    if options.checkpoint_dir:
426        cptdir = options.checkpoint_dir
427    elif m5.options.outdir:
428        cptdir = m5.options.outdir
429    else:
430        cptdir = getcwd()
431
432    if options.fast_forward and options.checkpoint_restore != None:
433        fatal("Can't specify both --fast-forward and --checkpoint-restore")
434
435    if options.standard_switch and not options.caches:
436        fatal("Must specify --caches when using --standard-switch")
437
438    if options.standard_switch and options.repeat_switch:
439        fatal("Can't specify both --standard-switch and --repeat-switch")
440
441    if options.repeat_switch and options.take_checkpoints:
442        fatal("Can't specify both --repeat-switch and --take-checkpoints")
443
444    np = options.num_cpus
445    switch_cpus = None
446
447    if options.prog_interval:
448        for i in xrange(np):
449            testsys.cpu[i].progress_interval = options.prog_interval
450
451    if options.maxinsts:
452        for i in xrange(np):
453            testsys.cpu[i].max_insts_any_thread = options.maxinsts
454
455    if cpu_class:
456        switch_cpus = [cpu_class(switched_out=True, cpu_id=(i))
457                       for i in xrange(np)]
458
459        for i in xrange(np):
460            if options.fast_forward:
461                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
462            switch_cpus[i].system = testsys
463            switch_cpus[i].workload = testsys.cpu[i].workload
464            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
465            switch_cpus[i].progress_interval = \
466                testsys.cpu[i].progress_interval
467            # simulation period
468            if options.maxinsts:
469                switch_cpus[i].max_insts_any_thread = options.maxinsts
470            # Add checker cpu if selected
471            if options.checker:
472                switch_cpus[i].addCheckerCpu()
473
474        # If elastic tracing is enabled attach the elastic trace probe
475        # to the switch CPUs
476        if options.elastic_trace_en:
477            CpuConfig.config_etrace(cpu_class, switch_cpus, options)
478
479        testsys.switch_cpus = switch_cpus
480        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
481
482    if options.repeat_switch:
483        switch_class = getCPUClass(options.cpu_type)[0]
484        if switch_class.require_caches() and \
485                not options.caches:
486            print "%s: Must be used with caches" % str(switch_class)
487            sys.exit(1)
488        if not switch_class.support_take_over():
489            print "%s: CPU switching not supported" % str(switch_class)
490            sys.exit(1)
491
492        repeat_switch_cpus = [switch_class(switched_out=True, \
493                                               cpu_id=(i)) for i in xrange(np)]
494
495        for i in xrange(np):
496            repeat_switch_cpus[i].system = testsys
497            repeat_switch_cpus[i].workload = testsys.cpu[i].workload
498            repeat_switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
499
500            if options.maxinsts:
501                repeat_switch_cpus[i].max_insts_any_thread = options.maxinsts
502
503            if options.checker:
504                repeat_switch_cpus[i].addCheckerCpu()
505
506        testsys.repeat_switch_cpus = repeat_switch_cpus
507
508        if cpu_class:
509            repeat_switch_cpu_list = [(switch_cpus[i], repeat_switch_cpus[i])
510                                      for i in xrange(np)]
511        else:
512            repeat_switch_cpu_list = [(testsys.cpu[i], repeat_switch_cpus[i])
513                                      for i in xrange(np)]
514
515    if options.standard_switch:
516        switch_cpus = [TimingSimpleCPU(switched_out=True, cpu_id=(i))
517                       for i in xrange(np)]
518        switch_cpus_1 = [DerivO3CPU(switched_out=True, cpu_id=(i))
519                        for i in xrange(np)]
520
521        for i in xrange(np):
522            switch_cpus[i].system =  testsys
523            switch_cpus_1[i].system =  testsys
524            switch_cpus[i].workload = testsys.cpu[i].workload
525            switch_cpus_1[i].workload = testsys.cpu[i].workload
526            switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain
527            switch_cpus_1[i].clk_domain = testsys.cpu[i].clk_domain
528
529            # if restoring, make atomic cpu simulate only a few instructions
530            if options.checkpoint_restore != None:
531                testsys.cpu[i].max_insts_any_thread = 1
532            # Fast forward to specified location if we are not restoring
533            elif options.fast_forward:
534                testsys.cpu[i].max_insts_any_thread = int(options.fast_forward)
535            # Fast forward to a simpoint (warning: time consuming)
536            elif options.simpoint:
537                if testsys.cpu[i].workload[0].simpoint == 0:
538                    fatal('simpoint not found')
539                testsys.cpu[i].max_insts_any_thread = \
540                    testsys.cpu[i].workload[0].simpoint
541            # No distance specified, just switch
542            else:
543                testsys.cpu[i].max_insts_any_thread = 1
544
545            # warmup period
546            if options.warmup_insts:
547                switch_cpus[i].max_insts_any_thread =  options.warmup_insts
548
549            # simulation period
550            if options.maxinsts:
551                switch_cpus_1[i].max_insts_any_thread = options.maxinsts
552
553            # attach the checker cpu if selected
554            if options.checker:
555                switch_cpus[i].addCheckerCpu()
556                switch_cpus_1[i].addCheckerCpu()
557
558        testsys.switch_cpus = switch_cpus
559        testsys.switch_cpus_1 = switch_cpus_1
560        switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)]
561        switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)]
562
563    # set the checkpoint in the cpu before m5.instantiate is called
564    if options.take_checkpoints != None and \
565           (options.simpoint or options.at_instruction):
566        offset = int(options.take_checkpoints)
567        # Set an instruction break point
568        if options.simpoint:
569            for i in xrange(np):
570                if testsys.cpu[i].workload[0].simpoint == 0:
571                    fatal('no simpoint for testsys.cpu[%d].workload[0]', i)
572                checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset
573                testsys.cpu[i].max_insts_any_thread = checkpoint_inst
574                # used for output below
575                options.take_checkpoints = checkpoint_inst
576        else:
577            options.take_checkpoints = offset
578            # Set all test cpus with the right number of instructions
579            # for the upcoming simulation
580            for i in xrange(np):
581                testsys.cpu[i].max_insts_any_thread = offset
582
583    if options.take_simpoint_checkpoints != None:
584        simpoints, interval_length = parseSimpointAnalysisFile(options, testsys)
585
586    checkpoint_dir = None
587    if options.checkpoint_restore:
588        cpt_starttick, checkpoint_dir = findCptDir(options, cptdir, testsys)
589    m5.instantiate(checkpoint_dir)
590
591    # Initialization is complete.  If we're not in control of simulation
592    # (that is, if we're a slave simulator acting as a component in another
593    #  'master' simulator) then we're done here.  The other simulator will
594    # call simulate() directly. --initialize-only is used to indicate this.
595    if options.initialize_only:
596        return
597
598    # Handle the max tick settings now that tick frequency was resolved
599    # during system instantiation
600    # NOTE: the maxtick variable here is in absolute ticks, so it must
601    # include any simulated ticks before a checkpoint
602    explicit_maxticks = 0
603    maxtick_from_abs = m5.MaxTick
604    maxtick_from_rel = m5.MaxTick
605    maxtick_from_maxtime = m5.MaxTick
606    if options.abs_max_tick:
607        maxtick_from_abs = options.abs_max_tick
608        explicit_maxticks += 1
609    if options.rel_max_tick:
610        maxtick_from_rel = options.rel_max_tick
611        if options.checkpoint_restore:
612            # NOTE: this may need to be updated if checkpoints ever store
613            # the ticks per simulated second
614            maxtick_from_rel += cpt_starttick
615            if options.at_instruction or options.simpoint:
616                warn("Relative max tick specified with --at-instruction or" \
617                     " --simpoint\n      These options don't specify the " \
618                     "checkpoint start tick, so assuming\n      you mean " \
619                     "absolute max tick")
620        explicit_maxticks += 1
621    if options.maxtime:
622        maxtick_from_maxtime = m5.ticks.fromSeconds(options.maxtime)
623        explicit_maxticks += 1
624    if explicit_maxticks > 1:
625        warn("Specified multiple of --abs-max-tick, --rel-max-tick, --maxtime."\
626             " Using least")
627    maxtick = min([maxtick_from_abs, maxtick_from_rel, maxtick_from_maxtime])
628
629    if options.checkpoint_restore != None and maxtick < cpt_starttick:
630        fatal("Bad maxtick (%d) specified: " \
631              "Checkpoint starts starts from tick: %d", maxtick, cpt_starttick)
632
633    if options.standard_switch or cpu_class:
634        if options.standard_switch:
635            print "Switch at instruction count:%s" % \
636                    str(testsys.cpu[0].max_insts_any_thread)
637            exit_event = m5.simulate()
638        elif cpu_class and options.fast_forward:
639            print "Switch at instruction count:%s" % \
640                    str(testsys.cpu[0].max_insts_any_thread)
641            exit_event = m5.simulate()
642        else:
643            print "Switch at curTick count:%s" % str(10000)
644            exit_event = m5.simulate(10000)
645        print "Switched CPUS @ tick %s" % (m5.curTick())
646
647        m5.switchCpus(testsys, switch_cpu_list)
648
649        if options.standard_switch:
650            print "Switch at instruction count:%d" % \
651                    (testsys.switch_cpus[0].max_insts_any_thread)
652
653            #warmup instruction count may have already been set
654            if options.warmup_insts:
655                exit_event = m5.simulate()
656            else:
657                exit_event = m5.simulate(options.standard_switch)
658            print "Switching CPUS @ tick %s" % (m5.curTick())
659            print "Simulation ends instruction count:%d" % \
660                    (testsys.switch_cpus_1[0].max_insts_any_thread)
661            m5.switchCpus(testsys, switch_cpu_list1)
662
663    # If we're taking and restoring checkpoints, use checkpoint_dir
664    # option only for finding the checkpoints to restore from.  This
665    # lets us test checkpointing by restoring from one set of
666    # checkpoints, generating a second set, and then comparing them.
667    if (options.take_checkpoints or options.take_simpoint_checkpoints) \
668        and options.checkpoint_restore:
669
670        if m5.options.outdir:
671            cptdir = m5.options.outdir
672        else:
673            cptdir = getcwd()
674
675    if options.take_checkpoints != None :
676        # Checkpoints being taken via the command line at <when> and at
677        # subsequent periods of <period>.  Checkpoint instructions
678        # received from the benchmark running are ignored and skipped in
679        # favor of command line checkpoint instructions.
680        exit_event = scriptCheckpoints(options, maxtick, cptdir)
681
682    # Take SimPoint checkpoints
683    elif options.take_simpoint_checkpoints != None:
684        takeSimpointCheckpoints(simpoints, interval_length, cptdir)
685
686    # Restore from SimPoint checkpoints
687    elif options.restore_simpoint_checkpoint != None:
688        restoreSimpointCheckpoint()
689
690    else:
691        if options.fast_forward:
692            m5.stats.reset()
693        print "**** REAL SIMULATION ****"
694
695        # If checkpoints are being taken, then the checkpoint instruction
696        # will occur in the benchmark code it self.
697        if options.repeat_switch and maxtick > options.repeat_switch:
698            exit_event = repeatSwitch(testsys, repeat_switch_cpu_list,
699                                      maxtick, options.repeat_switch)
700        else:
701            exit_event = benchCheckpoints(options, maxtick, cptdir)
702
703    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause())
704    if options.checkpoint_at_end:
705        m5.checkpoint(joinpath(cptdir, "cpt.%d"))
706
707    if not m5.options.interactive:
708        sys.exit(exit_event.getCode())
709