X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=configs%2Fcommon%2FSimulation.py;h=cecf030adcb521aa6445ef0106b1bf2d32970194;hb=82c6734f6b0a614d01cb7c64a6bc53a20ca906a1;hp=3261594bd0704d7c535449cce620204ae245e250;hpb=0273533adb65cc4a29fdf01a0972a7c2529ffa98;p=gem5.git diff --git a/configs/common/Simulation.py b/configs/common/Simulation.py index 3261594bd..cecf030ad 100644 --- a/configs/common/Simulation.py +++ b/configs/common/Simulation.py @@ -1,4 +1,17 @@ +# 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,39 +39,219 @@ # # 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: - class TmpClass(TimingSimpleCPU): pass - elif options.detailed: - if not options.caches: - print "O3 CPU must be used with caches" - sys.exit(1) - class TmpClass(DerivO3CPU): pass - else: - class TmpClass(AtomicSimpleCPU): pass - 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 != None or options.fast_forward: + if options.checkpoint_restore != None: + if options.restore_with_cpu != options.cpu_type: CPUClass = TmpClass - class TmpClass(AtomicSimpleCPU): pass - 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 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: + dirs = listdir(cptdir) + expr = re.compile('cpt\.([0-9]*)') + cpts = [] + for dir in dirs: + match = expr.match(dir) + if match: + cpts.append(match.group(1)) + + cpts.sort(lambda a,b: cmp(long(a), long(b))) + + cpt_num = options.checkpoint_restore + if cpt_num > len(cpts): + fatal('Checkpoint %d not found', cpt_num) + + maxtick = maxtick - int(cpts[cpt_num - 1]) + checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) + + return maxtick, checkpoint_dir + +def scriptCheckpoints(options, maxtick, cptdir): + if options.at_instruction or options.simpoint: + checkpoint_inst = int(options.take_checkpoints) + + # maintain correct offset if we restored from some instruction + if options.checkpoint_restore != None: + checkpoint_inst += options.checkpoint_restore + + print "Creating checkpoint at inst:%d" % (checkpoint_inst) + exit_event = m5.simulate() + exit_cause = exit_event.getCause() + print "exit cause = %s" % exit_cause + + # skip checkpoint instructions should they exist + while exit_cause == "checkpoint": + exit_event = m5.simulate() + exit_cause = exit_event.getCause() + + if exit_cause == "a thread reached the max instruction count": + m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ + (options.bench, checkpoint_inst))) + print "Checkpoint written." + + else: + when, period = options.take_checkpoints.split(",", 1) + when = int(when) + period = int(period) + num_checkpoints = 0 + + 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_cause == "simulate() limit reached": + m5.checkpoint(joinpath(cptdir, "cpt.%d")) + num_checkpoints += 1 + + sim_ticks = when + max_checkpoints = options.max_checkpoints + + while num_checkpoints < max_checkpoints and \ + 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(joinpath(cptdir, "cpt.%d")) + num_checkpoints += 1 + + return exit_event + +def benchCheckpoints(options, maxtick, cptdir): + exit_event = m5.simulate(maxtick - m5.curTick()) + exit_cause = exit_event.getCause() + + num_checkpoints = 0 + max_checkpoints = options.max_checkpoints + + 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() + + return exit_event + +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() + + 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: @@ -78,47 +271,94 @@ def run(options, root, testsys, cpu_class): cptdir = getcwd() if options.fast_forward and options.checkpoint_restore != None: - m5.panic("Error: Can't specify both --fast-forward and --checkpoint-restore") + 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.standard_switch and not cpu_class: - m5.panic("Error: Must specify CPU to switch to for --standard-switch (almost always detailed (-d))") + if options.repeat_switch and options.take_checkpoints: + fatal("Can't specify both --repeat-switch and --take-checkpoints") np = options.num_cpus - max_checkpoints = options.max_checkpoints 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(defer_registration=True, cpu_id=(np+i)) + 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 - if not m5.build_env['FULL_SYSTEM']: - switch_cpus[i].workload = testsys.cpu[i].workload - switch_cpus[i].clock = testsys.cpu[0].clock + switch_cpus[i].workload = testsys.cpu[i].workload + switch_cpus[i].clock = testsys.cpu[i].clock # simulation period - if options.max_inst: - switch_cpus[i].max_insts_any_thread = options.max_inst + 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(defer_registration=True, cpu_id=(np+i)) + switch_cpus = [TimingSimpleCPU(switched_out=True, cpu_id=(i)) for i in xrange(np)] - switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) + 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 - 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 + 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: @@ -128,8 +368,8 @@ def run(options, root, testsys, cpu_class): 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 == None: - m5.panic('simpoint not found') + 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 @@ -141,19 +381,18 @@ def run(options, root, testsys, cpu_class): switch_cpus[i].max_insts_any_thread = options.warmup_insts # simulation period - if options.max_inst: - switch_cpus_1[i].max_insts_any_thread = options.max_inst + if options.maxinsts: + switch_cpus_1[i].max_insts_any_thread = options.maxinsts - 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) + # 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)] + 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 \ @@ -162,8 +401,8 @@ def run(options, root, testsys, cpu_class): # Set an instruction break point if options.simpoint: for i in xrange(np): - if testsys.cpu[i].workload[0].simpoint == None: - m5.panic('no simpoint for testsys.cpu[%d].workload[0]' % i) + 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 @@ -175,65 +414,10 @@ def run(options, root, testsys, cpu_class): for i in xrange(np): testsys.cpu[i].max_insts_any_thread = offset - m5.instantiate(root) - + checkpoint_dir = None if options.checkpoint_restore != None: - from os.path import isdir, exists - from os import listdir - import re - - if not isdir(cptdir): - m5.panic("checkpoint dir %s does not exist!" % cptdir) - - if options.at_instruction: - checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % \ - (options.bench, options.checkpoint_restore)) - if not exists(checkpoint_dir): - m5.panic("Unable to find checkpoint directory %s" % \ - checkpoint_dir) - - print "Restoring checkpoint ..." - m5.restoreCheckpoint(root, checkpoint_dir) - print "Done." - elif options.simpoint: - # assume workload 0 has the simpoint - if testsys.cpu[0].workload[0].simpoint == None: - m5.panic('Unable to find simpoint') - - options.checkpoint_restore += \ - int(testsys.cpu[0].workload[0].simpoint) - - checkpoint_dir = joinpath(cptdir, "cpt.%s.%d" % \ - (options.bench, options.checkpoint_restore)) - if not exists(checkpoint_dir): - m5.panic("Unable to find checkpoint directory %s.%s" % \ - (options.bench, options.checkpoint_restore)) - - print "Restoring checkpoint ..." - m5.restoreCheckpoint(root,checkpoint_dir) - print "Done." - else: - dirs = listdir(cptdir) - expr = re.compile('cpt\.([0-9]*)') - cpts = [] - for dir in dirs: - match = expr.match(dir) - if match: - cpts.append(match.group(1)) - - 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) - - ## Adjust max tick based on our starting tick - maxtick = maxtick - int(cpts[cpt_num - 1]) - - ## Restore the checkpoint - m5.restoreCheckpoint(root, - joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1])) + maxtick, checkpoint_dir = findCptDir(options, maxtick, cptdir, testsys) + m5.instantiate(checkpoint_dir) if options.standard_switch or cpu_class: if options.standard_switch: @@ -247,17 +431,9 @@ def run(options, root, testsys, cpu_class): else: print "Switch at curTick count:%s" % str(10000) exit_event = m5.simulate(10000) - print "Switched CPUS @ cycle = %s" % (m5.curTick()) + print "Switched CPUS @ tick %s" % (m5.curTick()) - # 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. - - m5.changeToTiming(testsys) - m5.switchCpus(switch_cpu_list) - m5.resume(testsys) + m5.switchCpus(testsys, switch_cpu_list) if options.standard_switch: print "Switch at instruction count:%d" % \ @@ -267,96 +443,44 @@ def run(options, root, testsys, cpu_class): if options.warmup_insts: exit_event = m5.simulate() else: - exit_event = m5.simulate(options.warmup) - print "Switching CPUS @ cycle = %s" % (m5.curTick()) + 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.drain(testsys) - m5.switchCpus(switch_cpu_list1) - m5.resume(testsys) - - num_checkpoints = 0 - exit_cause = '' - - # 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 != None : - if options.at_instruction or options.simpoint: - checkpoint_inst = int(options.take_checkpoints) - - # maintain correct offset if we restored from some instruction - if options.checkpoint_restore != None: - checkpoint_inst += options.checkpoint_restore - - print "Creating checkpoint at inst:%d" % (checkpoint_inst) - exit_event = m5.simulate() - print "exit cause = %s" % (exit_event.getCause()) - - # skip checkpoint instructions should they exist - while exit_event.getCause() == "checkpoint": - exit_event = m5.simulate() - - if exit_event.getCause() == \ - "a thread reached the max instruction count": - m5.checkpoint(root, joinpath(cptdir, "cpt.%s.%d" % \ - (options.bench, checkpoint_inst))) - print "Checkpoint written." - num_checkpoints += 1 - - if exit_event.getCause() == "user interrupt received": - exit_cause = exit_event.getCause(); + 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: - when, period = options.take_checkpoints.split(",", 1) - when = int(when) - period = int(period) - - exit_event = m5.simulate(when) - while exit_event.getCause() == "checkpoint": - exit_event = m5.simulate(when - m5.curTick()) + cptdir = getcwd() - if exit_event.getCause() == "simulate() limit reached": - m5.checkpoint(root, joinpath(cptdir, "cpt.%d")) - num_checkpoints += 1 - - sim_ticks = when - exit_cause = "maximum %d checkpoints dropped" % max_checkpoints - while num_checkpoints < max_checkpoints and \ - exit_event.getCause() == "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) - 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")) - num_checkpoints += 1 - - if exit_event.getCause() != "simulate() limit reached": - exit_cause = exit_event.getCause(); - - else: # no checkpoints being taken via this script + 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 ****" - exit_event = m5.simulate(maxtick) - 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 - - exit_event = m5.simulate(maxtick - m5.curTick()) - exit_cause = exit_event.getCause() + # 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) - if exit_cause == '': - exit_cause = exit_event.getCause() - print 'Exiting @ cycle %i because %s' % (m5.curTick(), exit_cause) + 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())