X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=configs%2Fcommon%2FSimulation.py;h=cecf030adcb521aa6445ef0106b1bf2d32970194;hb=82c6734f6b0a614d01cb7c64a6bc53a20ca906a1;hp=53c2956a24eb3420b8700d84c458ef48d4f9b9fa;hpb=6f9ad931cc1c63da925b6372513282d2aa8dc84c;p=gem5.git diff --git a/configs/common/Simulation.py b/configs/common/Simulation.py index 53c2956a2..cecf030ad 100644 --- a/configs/common/Simulation.py +++ b/configs/common/Simulation.py @@ -1,4 +1,17 @@ -# Copyright (c) 2006-2007 The Regents of The University of Michigan +# Copyright (c) 2012 ARM Limited +# All rights reserved +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Copyright (c) 2006-2008 The Regents of The University of Michigan +# Copyright (c) 2010 Advanced Micro Devices, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,111 +39,104 @@ # # Authors: Lisa Hsu +import sys from os import getcwd from os.path import join as joinpath + +import CpuConfig + import m5 +from m5.defines import buildEnv from m5.objects import * -m5.AddToPath('../common') -from Caches import L1Cache +from m5.util import * + +addToPath('../common') + +def getCPUClass(cpu_type): + """Returns the required cpu class and the mode of operation.""" + cls = CpuConfig.get(cpu_type) + return cls, cls.memory_mode() def setCPUClass(options): + """Returns two cpu classes and the initial mode of operation. - atomic = False - if options.timing: - TmpClass = TimingSimpleCPU - elif options.detailed: - if not options.caches: - print "O3 CPU must be used with caches" - sys.exit(1) - TmpClass = DerivO3CPU - else: - TmpClass = AtomicSimpleCPU - atomic = True + Restoring from a checkpoint or fast forwarding through a benchmark + can be done using one type of cpu, and then the actual + simulation can be carried out using another type. This function + returns these two types of cpus and the initial mode of operation + depending on the options provided. + """ + TmpClass, test_mem_mode = getCPUClass(options.cpu_type) CPUClass = None - test_mem_mode = 'atomic' + if TmpClass.require_caches() and \ + not options.caches and not options.ruby: + fatal("%s must be used with caches" % options.cpu_type) - if not atomic: - if options.checkpoint_restore: + if options.checkpoint_restore != None: + if options.restore_with_cpu != options.cpu_type: CPUClass = TmpClass - TmpClass = AtomicSimpleCPU - else: - test_mem_mode = 'timing' + TmpClass, test_mem_mode = getCPUClass(options.restore_with_cpu) + elif options.fast_forward: + CPUClass = TmpClass + TmpClass = AtomicSimpleCPU + test_mem_mode = 'atomic' return (TmpClass, test_mem_mode, CPUClass) - -def run(options, root, testsys, cpu_class): - if options.maxtick: - maxtick = options.maxtick - elif options.maxtime: - simtime = m5.ticks.seconds(simtime) - print "simulating for: ", simtime - maxtick = simtime +def setWorkCountOptions(system, options): + if options.work_item_id != None: + system.work_item_id = options.work_item_id + if options.work_begin_cpu_id_exit != None: + system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit + if options.work_end_exit_count != None: + system.work_end_exit_count = options.work_end_exit_count + if options.work_end_checkpoint_count != None: + system.work_end_ckpt_count = options.work_end_checkpoint_count + if options.work_begin_exit_count != None: + system.work_begin_exit_count = options.work_begin_exit_count + if options.work_begin_checkpoint_count != None: + system.work_begin_ckpt_count = options.work_begin_checkpoint_count + if options.work_cpus_checkpoint_count != None: + system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count + +def findCptDir(options, maxtick, cptdir, testsys): + """Figures out the directory from which the checkpointed state is read. + + There are two different ways in which the directories holding checkpoints + can be named -- + 1. cpt.. + 2. cpt. + + This function parses through the options to figure out which one of the + above should be used for selecting the checkpoint, and then figures out + the appropriate directory. + + It also sets the value of the maximum tick value till which the simulation + will run. + """ + + from os.path import isdir, exists + from os import listdir + import re + + if not isdir(cptdir): + fatal("checkpoint dir %s does not exist!", cptdir) + + if options.at_instruction or options.simpoint: + inst = options.checkpoint_restore + if options.simpoint: + # assume workload 0 has the simpoint + if testsys.cpu[0].workload[0].simpoint == 0: + fatal('Unable to find simpoint') + inst += int(testsys.cpu[0].workload[0].simpoint) + + checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst)) + if not exists(checkpoint_dir): + fatal("Unable to find checkpoint directory %s", checkpoint_dir) else: - maxtick = m5.MaxTick - - if options.checkpoint_dir: - cptdir = options.checkpoint_dir - else: - cptdir = getcwd() - - np = options.num_cpus - max_checkpoints = options.max_checkpoints - switch_cpus = None - - if cpu_class: - switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i)) - for i in xrange(np)] - - for i in xrange(np): - switch_cpus[i].system = testsys - if not m5.build_env['FULL_SYSTEM']: - switch_cpus[i].workload = testsys.cpu[i].workload - switch_cpus[i].clock = testsys.cpu[0].clock - - root.switch_cpus = switch_cpus - switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] - - if options.standard_switch: - switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) - for i in xrange(np)] - switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) - for i in xrange(np)] - - for i in xrange(np): - switch_cpus[i].system = testsys - switch_cpus_1[i].system = testsys - if not m5.build_env['FULL_SYSTEM']: - switch_cpus[i].workload = testsys.cpu[i].workload - switch_cpus_1[i].workload = testsys.cpu[i].workload - switch_cpus[i].clock = testsys.cpu[0].clock - switch_cpus_1[i].clock = testsys.cpu[0].clock - - if not options.caches: - # O3 CPU must have a cache to work. - switch_cpus_1[i].addPrivateSplitL1Caches(L1Cache(size = '32kB'), - L1Cache(size = '64kB')) - switch_cpus_1[i].connectMemPorts(testsys.membus) - - - testsys.switch_cpus = switch_cpus - testsys.switch_cpus_1 = switch_cpus_1 - switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] - switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] - - m5.instantiate(root) - - if options.checkpoint_restore: - from os.path import isdir - from os import listdir - import re - - if not isdir(cptdir): - m5.panic("checkpoint dir %s does not exist!" % cptdir) - dirs = listdir(cptdir) - expr = re.compile('cpt.([0-9]*)') + expr = re.compile('cpt\.([0-9]*)') cpts = [] for dir in dirs: match = expr.match(dir) @@ -140,90 +146,341 @@ def run(options, root, testsys, cpu_class): cpts.sort(lambda a,b: cmp(long(a), long(b))) cpt_num = options.checkpoint_restore - if cpt_num > len(cpts): - m5.panic('Checkpoint %d not found' % cpt_num) + fatal('Checkpoint %d not found', cpt_num) - ## Adjust max tick based on our starting tick maxtick = maxtick - int(cpts[cpt_num - 1]) + checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) - ## Restore the checkpoint - m5.restoreCheckpoint(root, - joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])) + return maxtick, checkpoint_dir - if options.standard_switch or cpu_class: - exit_event = m5.simulate(10000) +def scriptCheckpoints(options, maxtick, cptdir): + if options.at_instruction or options.simpoint: + checkpoint_inst = int(options.take_checkpoints) - ## when you change to Timing (or Atomic), you halt the system given - ## as argument. When you are finished with the system changes - ## (including switchCpus), you must resume the system manually. - ## You DON'T need to resume after just switching CPUs if you haven't - ## changed anything on the system level. + # maintain correct offset if we restored from some instruction + if options.checkpoint_restore != None: + checkpoint_inst += options.checkpoint_restore - m5.changeToTiming(testsys) - m5.switchCpus(switch_cpu_list) - m5.resume(testsys) + print "Creating checkpoint at inst:%d" % (checkpoint_inst) + exit_event = m5.simulate() + exit_cause = exit_event.getCause() + print "exit cause = %s" % exit_cause - if options.standard_switch: - exit_event = m5.simulate(options.warmup) - m5.drain(testsys) - m5.switchCpus(switch_cpu_list1) - m5.resume(testsys) + # skip checkpoint instructions should they exist + while exit_cause == "checkpoint": + exit_event = m5.simulate() + exit_cause = exit_event.getCause() - num_checkpoints = 0 - exit_cause = '' + if exit_cause == "a thread reached the max instruction count": + m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ + (options.bench, checkpoint_inst))) + print "Checkpoint written." - ## Checkpoints being taken via the command line at and at subsequent - ## periods of . Checkpoint instructions received from the benchmark running - ## are ignored and skipped in favor of command line checkpoint instructions. - if options.take_checkpoints: - [when, period] = options.take_checkpoints.split(",", 1) + else: + when, period = options.take_checkpoints.split(",", 1) when = int(when) period = int(period) + num_checkpoints = 0 - exit_event = m5.simulate(when) - while exit_event.getCause() == "checkpoint": + exit_event = m5.simulate(when - m5.curTick()) + exit_cause = exit_event.getCause() + while exit_cause == "checkpoint": exit_event = m5.simulate(when - m5.curTick()) + exit_cause = exit_event.getCause() - if exit_event.getCause() == "simulate() limit reached": - m5.checkpoint(root, joinpath(cptdir, "cpt.%d")) + if exit_cause == "simulate() limit reached": + m5.checkpoint(joinpath(cptdir, "cpt.%d")) num_checkpoints += 1 sim_ticks = when - exit_cause = "maximum %d checkpoints dropped" % max_checkpoints + max_checkpoints = options.max_checkpoints + while num_checkpoints < max_checkpoints and \ - exit_event.getCause() != "user interrupt received": + exit_cause == "simulate() limit reached": if (sim_ticks + period) > maxtick: exit_event = m5.simulate(maxtick - sim_ticks) exit_cause = exit_event.getCause() break else: exit_event = m5.simulate(period) + exit_cause = exit_event.getCause() sim_ticks += period while exit_event.getCause() == "checkpoint": exit_event = m5.simulate(sim_ticks - m5.curTick()) if exit_event.getCause() == "simulate() limit reached": - m5.checkpoint(root, joinpath(cptdir, "cpt.%d")) + m5.checkpoint(joinpath(cptdir, "cpt.%d")) num_checkpoints += 1 - if exit_event.getCause() == "user interrupt received": - exit_cause = exit_event.getCause(); + return exit_event +def benchCheckpoints(options, maxtick, cptdir): + exit_event = m5.simulate(maxtick - m5.curTick()) + exit_cause = exit_event.getCause() - else: #no checkpoints being taken via this script - exit_event = m5.simulate(maxtick) + num_checkpoints = 0 + max_checkpoints = options.max_checkpoints - while exit_event.getCause() == "checkpoint": - m5.checkpoint(root, joinpath(cptdir, "cpt.%d")) - num_checkpoints += 1 - if num_checkpoints == max_checkpoints: - exit_cause = "maximum %d checkpoints dropped" % max_checkpoints - break + while exit_cause == "checkpoint": + m5.checkpoint(joinpath(cptdir, "cpt.%d")) + num_checkpoints += 1 + if num_checkpoints == max_checkpoints: + exit_cause = "maximum %d checkpoints dropped" % max_checkpoints + break - exit_event = m5.simulate(maxtick - m5.curTick()) - exit_cause = exit_event.getCause() + exit_event = m5.simulate(maxtick - m5.curTick()) + exit_cause = exit_event.getCause() + + return exit_event - if exit_cause == '': +def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq): + print "starting switch loop" + while True: + exit_event = m5.simulate(switch_freq) exit_cause = exit_event.getCause() - print 'Exiting @ cycle %i because %s' % (m5.curTick(), exit_cause) + if exit_cause != "simulate() limit reached": + return exit_event + + m5.switchCpus(testsys, repeat_switch_cpu_list) + + tmp_cpu_list = [] + for old_cpu, new_cpu in repeat_switch_cpu_list: + tmp_cpu_list.append((new_cpu, old_cpu)) + repeat_switch_cpu_list = tmp_cpu_list + + if (maxtick - m5.curTick()) <= switch_freq: + exit_event = m5.simulate(maxtick - m5.curTick()) + return exit_event + +def run(options, root, testsys, cpu_class): + if options.maxtick: + maxtick = options.maxtick + elif options.maxtime: + simtime = m5.ticks.seconds(simtime) + print "simulating for: ", simtime + maxtick = simtime + else: + maxtick = m5.MaxTick + + if options.checkpoint_dir: + cptdir = options.checkpoint_dir + elif m5.options.outdir: + cptdir = m5.options.outdir + else: + cptdir = getcwd() + + if options.fast_forward and options.checkpoint_restore != None: + fatal("Can't specify both --fast-forward and --checkpoint-restore") + + if options.standard_switch and not options.caches: + fatal("Must specify --caches when using --standard-switch") + + if options.standard_switch and options.repeat_switch: + fatal("Can't specify both --standard-switch and --repeat-switch") + + if options.repeat_switch and options.take_checkpoints: + fatal("Can't specify both --repeat-switch and --take-checkpoints") + + np = options.num_cpus + switch_cpus = None + + if options.prog_interval: + for i in xrange(np): + testsys.cpu[i].progress_interval = options.prog_interval + + if options.maxinsts: + for i in xrange(np): + testsys.cpu[i].max_insts_any_thread = options.maxinsts + + if cpu_class: + switch_cpus = [cpu_class(switched_out=True, cpu_id=(i)) + for i in xrange(np)] + + for i in xrange(np): + if options.fast_forward: + testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) + switch_cpus[i].system = testsys + switch_cpus[i].workload = testsys.cpu[i].workload + switch_cpus[i].clock = testsys.cpu[i].clock + # simulation period + if options.maxinsts: + switch_cpus[i].max_insts_any_thread = options.maxinsts + # Add checker cpu if selected + if options.checker: + switch_cpus[i].addCheckerCpu() + + testsys.switch_cpus = switch_cpus + switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] + + if options.repeat_switch: + switch_class = getCPUClass(options.cpu_type)[0] + if switch_class.require_caches() and \ + not options.caches: + print "%s: Must be used with caches" % str(switch_class) + sys.exit(1) + if not switch_class.support_take_over(): + print "%s: CPU switching not supported" % str(switch_class) + sys.exit(1) + + repeat_switch_cpus = [switch_class(switched_out=True, \ + cpu_id=(i)) for i in xrange(np)] + + for i in xrange(np): + repeat_switch_cpus[i].system = testsys + repeat_switch_cpus[i].workload = testsys.cpu[i].workload + repeat_switch_cpus[i].clock = testsys.cpu[i].clock + + if options.maxinsts: + repeat_switch_cpus[i].max_insts_any_thread = options.maxinsts + + if options.checker: + repeat_switch_cpus[i].addCheckerCpu() + + testsys.repeat_switch_cpus = repeat_switch_cpus + + if cpu_class: + repeat_switch_cpu_list = [(switch_cpus[i], repeat_switch_cpus[i]) + for i in xrange(np)] + else: + repeat_switch_cpu_list = [(testsys.cpu[i], repeat_switch_cpus[i]) + for i in xrange(np)] + + if options.standard_switch: + switch_cpus = [TimingSimpleCPU(switched_out=True, cpu_id=(i)) + for i in xrange(np)] + switch_cpus_1 = [DerivO3CPU(switched_out=True, cpu_id=(i)) + for i in xrange(np)] + + for i in xrange(np): + switch_cpus[i].system = testsys + switch_cpus_1[i].system = testsys + switch_cpus[i].workload = testsys.cpu[i].workload + switch_cpus_1[i].workload = testsys.cpu[i].workload + switch_cpus[i].clock = testsys.cpu[i].clock + switch_cpus_1[i].clock = testsys.cpu[i].clock + + # if restoring, make atomic cpu simulate only a few instructions + if options.checkpoint_restore != None: + testsys.cpu[i].max_insts_any_thread = 1 + # Fast forward to specified location if we are not restoring + elif options.fast_forward: + testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) + # Fast forward to a simpoint (warning: time consuming) + elif options.simpoint: + if testsys.cpu[i].workload[0].simpoint == 0: + fatal('simpoint not found') + testsys.cpu[i].max_insts_any_thread = \ + testsys.cpu[i].workload[0].simpoint + # No distance specified, just switch + else: + testsys.cpu[i].max_insts_any_thread = 1 + + # warmup period + if options.warmup_insts: + switch_cpus[i].max_insts_any_thread = options.warmup_insts + + # simulation period + if options.maxinsts: + switch_cpus_1[i].max_insts_any_thread = options.maxinsts + + # attach the checker cpu if selected + if options.checker: + switch_cpus[i].addCheckerCpu() + switch_cpus_1[i].addCheckerCpu() + + testsys.switch_cpus = switch_cpus + testsys.switch_cpus_1 = switch_cpus_1 + switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] + switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] + + # set the checkpoint in the cpu before m5.instantiate is called + if options.take_checkpoints != None and \ + (options.simpoint or options.at_instruction): + offset = int(options.take_checkpoints) + # Set an instruction break point + if options.simpoint: + for i in xrange(np): + if testsys.cpu[i].workload[0].simpoint == 0: + fatal('no simpoint for testsys.cpu[%d].workload[0]', i) + checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset + testsys.cpu[i].max_insts_any_thread = checkpoint_inst + # used for output below + options.take_checkpoints = checkpoint_inst + else: + options.take_checkpoints = offset + # Set all test cpus with the right number of instructions + # for the upcoming simulation + for i in xrange(np): + testsys.cpu[i].max_insts_any_thread = offset + + checkpoint_dir = None + if options.checkpoint_restore != None: + maxtick, checkpoint_dir = findCptDir(options, maxtick, cptdir, testsys) + m5.instantiate(checkpoint_dir) + + if options.standard_switch or cpu_class: + if options.standard_switch: + print "Switch at instruction count:%s" % \ + str(testsys.cpu[0].max_insts_any_thread) + exit_event = m5.simulate() + elif cpu_class and options.fast_forward: + print "Switch at instruction count:%s" % \ + str(testsys.cpu[0].max_insts_any_thread) + exit_event = m5.simulate() + else: + print "Switch at curTick count:%s" % str(10000) + exit_event = m5.simulate(10000) + print "Switched CPUS @ tick %s" % (m5.curTick()) + + m5.switchCpus(testsys, switch_cpu_list) + + if options.standard_switch: + print "Switch at instruction count:%d" % \ + (testsys.switch_cpus[0].max_insts_any_thread) + + #warmup instruction count may have already been set + if options.warmup_insts: + exit_event = m5.simulate() + else: + exit_event = m5.simulate(options.standard_switch) + print "Switching CPUS @ tick %s" % (m5.curTick()) + print "Simulation ends instruction count:%d" % \ + (testsys.switch_cpus_1[0].max_insts_any_thread) + m5.switchCpus(testsys, switch_cpu_list1) + + # If we're taking and restoring checkpoints, use checkpoint_dir + # option only for finding the checkpoints to restore from. This + # lets us test checkpointing by restoring from one set of + # checkpoints, generating a second set, and then comparing them. + if options.take_checkpoints and options.checkpoint_restore: + if m5.options.outdir: + cptdir = m5.options.outdir + else: + cptdir = getcwd() + + if options.take_checkpoints != None : + # Checkpoints being taken via the command line at and at + # subsequent periods of . Checkpoint instructions + # received from the benchmark running are ignored and skipped in + # favor of command line checkpoint instructions. + exit_event = scriptCheckpoints(options, maxtick, cptdir) + else: + if options.fast_forward: + m5.stats.reset() + print "**** REAL SIMULATION ****" + + # If checkpoints are being taken, then the checkpoint instruction + # will occur in the benchmark code it self. + if options.repeat_switch and maxtick > options.repeat_switch: + exit_event = repeatSwitch(testsys, repeat_switch_cpu_list, + maxtick, options.repeat_switch) + else: + exit_event = benchCheckpoints(options, maxtick, cptdir) + + print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()) + if options.checkpoint_at_end: + m5.checkpoint(joinpath(cptdir, "cpt.%d")) + + if not m5.options.interactive: + sys.exit(exit_event.getCode())