diff -r 283cedb3e98e -r d97a78954fd4 configs/common/Options.py --- a/configs/common/Options.py Sat Jul 17 02:21:48 2010 +0100 +++ b/configs/common/Options.py Sat Jul 17 02:21:48 2010 +0100 @@ -101,3 +101,15 @@ parser.add_option("--at-instruction", action="store_true", default=False, help="""Treate value of --checkpoint-restore or --take-checkpoint as a number of instructions.""") + +# SMARTS related options. +parser.add_option("--smarts-sample-interval", dest = "kSmarts", type = "int", + help = "Specify SMARTS sampling interval.") +parser.add_option("--smarts-num-samples", dest = "nSmarts", type = "int", + help = "Specify SMARTS number of samples.") +parser.add_option("--smarts-warm", dest = "wSmarts", default = 2000, + help = "Specify SMARTS number of instructions to warm.") +parser.add_option("--smarts-measure", dest = "mSmarts", default = 1000, + help = "Specify SMARTS number of instructions to measure.") +parser.add_option("--smarts-bmk-size", dest = "bSmarts", type = "int", + help = "Specify SMARTS size of benchmark in billion insts.") diff -r 283cedb3e98e -r d97a78954fd4 configs/common/Simulation.py --- a/configs/common/Simulation.py Sat Jul 17 02:21:48 2010 +0100 +++ b/configs/common/Simulation.py Sat Jul 17 02:21:48 2010 +0100 @@ -36,6 +36,8 @@ addToPath('../common') +from Smarts import runSmarts + def setCPUClass(options): atomic = False @@ -59,7 +61,8 @@ test_mem_mode = 'atomic' if not atomic: - if options.checkpoint_restore != None or options.fast_forward: + if options.checkpoint_restore != None or options.fast_forward or \ + options.kSmarts or options.nSmarts: CPUClass = TmpClass class TmpClass(AtomicSimpleCPU): pass else: @@ -121,6 +124,11 @@ testsys.switch_cpus = switch_cpus switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] + # If using smarts simulation, do this only. + if options.kSmarts or options.nSmarts: + runSmarts(options, root, testsys) + return + if options.standard_switch: switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) for i in xrange(np)] diff -r 283cedb3e98e -r d97a78954fd4 configs/common/Smarts.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configs/common/Smarts.py Sat Jul 17 02:21:48 2010 +0100 @@ -0,0 +1,204 @@ +# Copyright (c) 2010 The University of Edinburgh +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Timothy M. Jones + +import math +import m5 + +# A class to perform error estimation. +class ErrorEstimator(object): + cpiMean = 0 + cpiSumSq = 0 + numSamples = 0 + sampleStartTick = 0 + sampleStartInsts = 0 + + # Start detailed execution, so set variables for error-estimation. + def startDetailedExec(self, cpu): + self.sampleStartTick = m5.curTick() + self.sampleStartInsts = cpu.getInstsExecuted(0) + + # Finish detailed execution, so update the error-estimation stat. + def finishDetailedExec(self, cpu): + numSamples = self.numSamples + cycles = (m5.curTick() - self.sampleStartTick) / cpu.clock.getValue() + insts = cpu.getInstsExecuted(0) - self.sampleStartInsts + cpi = float(cycles) / float(insts) + + d = cpi - self.cpiMean + self.cpiMean += d / (numSamples + 1) + if numSamples > 0: + self.cpiSumSq += d * d * numSamples / (numSamples + 1) + self.numSamples += 1 + + # Finish the whole simulation and calculate error-estimation. + def finishSimulation(self): + cpiStdev = 0.0 + cpiCi = 0.0 + numSamples = self.numSamples + if numSamples > 1: + cpiStdev = math.sqrt(self.cpiSumSq / (numSamples - 1)) + if numSamples > 0: + # Z value for 99.7 is 3.0, for 95 is 1.96 + cpiCi = 100.0 * 3.0 * cpiStdev + cpiCi = cpiCi / self.cpiMean / math.sqrt(numSamples) + print 'CPI mean', self.cpiMean, 'stdev', cpiStdev, \ + 'confidence', cpiCi, 'samples', numSamples + + # Assuming 3.0% error. + sqrtNTuned = 3.0 * cpiStdev / self.cpiMean / (3.0 / 100.0) + nTuned = sqrtNTuned * sqrtNTuned + if nTuned < 50: + nTuned = 50 + if nTuned - numSamples > 30: + print 'N-tuned for 3.0% error', int(nTuned) + + +# Get instructions executed from a list of CPUs. +def getTotalInstsExecuted(cpuList): + insts = 0 + for cpu in cpuList: + insts += cpu.getInstsExecuted(0) + return insts + + +# Get the number of instructions to execute next. +def setInstsToExecute(runCpu, idleCpu, desiredInsts, options): + if options.maxinsts and desiredInsts > options.maxinsts: + executeInsts = options.maxinsts - idleCpu.getInstsExecuted(0) + else: + executeInsts = desiredInsts - idleCpu.getInstsExecuted(0) + runCpu.setMaxInsts(executeInsts) + + +# Run using SMARTS sampling methodology. +def runSmarts(options, root, system): + + # Check the options. + mSmarts = options.mSmarts + wSmarts = options.wSmarts + if not options.kSmarts and not options.nSmarts: + print "Error: script needs SMARTS options n or k" + sys.exit(1) + elif options.kSmarts and options.nSmarts: + print "Error: use SMARTS option n or k, not both" + sys.exit(1) + elif options.mSmarts <= 0: + print "Error: SMARTS measurement instructions must be greater than 0" + sys.exit(1) + elif options.nSmarts: + nSmarts = options.nSmarts + if not options.bSmarts: + print "Error: need to specify bmk size if using SMARTS option n" + sys.exit(1) + bmkSize = options.bSmarts * 1000000000.0 + kSmarts = int(math.floor(bmkSize / float(mSmarts) / float(nSmarts))) + else: + kSmarts = options.kSmarts + + if wSmarts + mSmarts > kSmarts * mSmarts: + print "Error: SMARTS k * m must not be larger than m + w" + sys.exit(1) + + # Keep handy references to cpus. + funcCpu = system.cpu[0] + detailCpu = system.switch_cpus[0] + + # Copy shared structures. + funcCpu.branchPred = detailCpu.branchPred + funcCpu.itb = detailCpu.itb + funcCpu.dtb = detailCpu.dtb + + # Switching processors. + detailCpu.workload = funcCpu.workload + switch_to_func_list = [ (detailCpu, funcCpu) ] + switch_to_detail_list = [ (funcCpu, detailCpu) ] + + # Set up mode changes. + modeChanges = { 'Forwarding':'Warming', 'Warming':'Running', + 'Running':'Forwarding' } + periodSmarts = kSmarts * mSmarts + funcCpu.max_insts_any_thread = 0 + funcCpu.max_insts_all_threads = periodSmarts + + # Instantiate everything. + m5.instantiate(root) + + # Run by continually switching processors until the program ends. + estimator = ErrorEstimator() + mode = 'Forwarding' + ended = False + while not ended: + exit_event = m5.simulate() + cause = exit_event.getCause() + + # Possibly stop after a number of instructions. + totalInsts = getTotalInstsExecuted([ funcCpu, detailCpu ]) + if options.maxinsts and totalInsts >= options.maxinsts: + ended = True + + # Check for normal exit. + elif cause != 'target called exit()': + + # Change the mode that we're in. + mode = modeChanges[mode] + + # Starting forwarding, backup stats and switch CPUs. + if mode == 'Forwarding': + m5.backupStats() + estimator.finishDetailedExec(detailCpu) + m5.changeToAtomic(system) + m5.switchCpus(switch_to_func_list, True) + m5.resume(system) + + # Calculate instructions to fast-forward. + endOfPeriod = ((totalInsts / periodSmarts) + 1) * periodSmarts + setInstsToExecute(funcCpu, detailCpu, endOfPeriod, options) + + # Starting warming, change CPUs. + elif mode == 'Warming': + funcCpu.icache.markAllReady() + funcCpu.dcache.markAllReady() + m5.changeToTiming(system) + m5.switchCpus(switch_to_detail_list, True) + m5.resume(system) + endOfWarm = totalInsts + wSmarts + setInstsToExecute(detailCpu, funcCpu, endOfWarm, options) + + # Starting running, restore stats and continue. + elif mode == 'Running': + m5.restoreStats() + estimator.startDetailedExec(detailCpu) + endOfRun = totalInsts + mSmarts + setInstsToExecute(detailCpu, funcCpu, endOfRun, options) + + # Target called exit, so finish. + else: + ended = True + + # Finish simulation. + estimator.finishSimulation()