Simulation.py revision 8311
1# Copyright (c) 2006-2008 The Regents of The University of Michigan 2# Copyright (c) 2010 Advanced Micro Devices, Inc. 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27# 28# Authors: Lisa Hsu 29 30from os import getcwd 31from os.path import join as joinpath 32 33import m5 34from m5.defines import buildEnv 35from m5.objects import * 36from m5.util import * 37 38addToPath('../common') 39 40def setCPUClass(options): 41 42 atomic = False 43 if options.timing: 44 class TmpClass(TimingSimpleCPU): pass 45 elif options.detailed: 46 if not options.caches: 47 print "O3 CPU must be used with caches" 48 sys.exit(1) 49 class TmpClass(DerivO3CPU): pass 50 elif options.inorder: 51 if not options.caches: 52 print "InOrder CPU must be used with caches" 53 sys.exit(1) 54 class TmpClass(InOrderCPU): pass 55 else: 56 class TmpClass(AtomicSimpleCPU): pass 57 atomic = True 58 59 CPUClass = None 60 test_mem_mode = 'atomic' 61 62 if not atomic: 63 if options.checkpoint_restore != None or options.fast_forward: 64 CPUClass = TmpClass 65 class TmpClass(AtomicSimpleCPU): pass 66 else: 67 test_mem_mode = 'timing' 68 69 return (TmpClass, test_mem_mode, CPUClass) 70 71 72def run(options, root, testsys, cpu_class): 73 if options.maxtick: 74 maxtick = options.maxtick 75 elif options.maxtime: 76 simtime = m5.ticks.seconds(simtime) 77 print "simulating for: ", simtime 78 maxtick = simtime 79 else: 80 maxtick = m5.MaxTick 81 82 if options.checkpoint_dir: 83 cptdir = options.checkpoint_dir 84 elif m5.options.outdir: 85 cptdir = m5.options.outdir 86 else: 87 cptdir = getcwd() 88 89 if options.fast_forward and options.checkpoint_restore != None: 90 fatal("Can't specify both --fast-forward and --checkpoint-restore") 91 92 if options.standard_switch and not options.caches: 93 fatal("Must specify --caches when using --standard-switch") 94 95 np = options.num_cpus 96 max_checkpoints = options.max_checkpoints 97 switch_cpus = None 98 99 if options.prog_intvl: 100 for i in xrange(np): 101 testsys.cpu[i].progress_interval = options.prog_interval 102 103 if options.maxinsts: 104 for i in xrange(np): 105 testsys.cpu[i].max_insts_any_thread = options.maxinsts 106 107 if cpu_class: 108 switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i)) 109 for i in xrange(np)] 110 111 for i in xrange(np): 112 if options.fast_forward: 113 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 114 switch_cpus[i].system = testsys 115 if not buildEnv['FULL_SYSTEM']: 116 switch_cpus[i].workload = testsys.cpu[i].workload 117 switch_cpus[i].clock = testsys.cpu[0].clock 118 # simulation period 119 if options.maxinsts: 120 switch_cpus[i].max_insts_any_thread = options.maxinsts 121 122 testsys.switch_cpus = switch_cpus 123 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 124 125 if options.standard_switch: 126 if not options.caches: 127 # O3 CPU must have a cache to work. 128 print "O3 CPU must be used with caches" 129 sys.exit(1) 130 131 switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) 132 for i in xrange(np)] 133 switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) 134 for i in xrange(np)] 135 136 for i in xrange(np): 137 switch_cpus[i].system = testsys 138 switch_cpus_1[i].system = testsys 139 if not buildEnv['FULL_SYSTEM']: 140 switch_cpus[i].workload = testsys.cpu[i].workload 141 switch_cpus_1[i].workload = testsys.cpu[i].workload 142 switch_cpus[i].clock = testsys.cpu[0].clock 143 switch_cpus_1[i].clock = testsys.cpu[0].clock 144 145 # if restoring, make atomic cpu simulate only a few instructions 146 if options.checkpoint_restore != None: 147 testsys.cpu[i].max_insts_any_thread = 1 148 # Fast forward to specified location if we are not restoring 149 elif options.fast_forward: 150 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 151 # Fast forward to a simpoint (warning: time consuming) 152 elif options.simpoint: 153 if testsys.cpu[i].workload[0].simpoint == 0: 154 fatal('simpoint not found') 155 testsys.cpu[i].max_insts_any_thread = \ 156 testsys.cpu[i].workload[0].simpoint 157 # No distance specified, just switch 158 else: 159 testsys.cpu[i].max_insts_any_thread = 1 160 161 # warmup period 162 if options.warmup_insts: 163 switch_cpus[i].max_insts_any_thread = options.warmup_insts 164 165 # simulation period 166 if options.maxinsts: 167 switch_cpus_1[i].max_insts_any_thread = options.maxinsts 168 169 testsys.switch_cpus = switch_cpus 170 testsys.switch_cpus_1 = switch_cpus_1 171 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 172 switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] 173 174 # set the checkpoint in the cpu before m5.instantiate is called 175 if options.take_checkpoints != None and \ 176 (options.simpoint or options.at_instruction): 177 offset = int(options.take_checkpoints) 178 # Set an instruction break point 179 if options.simpoint: 180 for i in xrange(np): 181 if testsys.cpu[i].workload[0].simpoint == 0: 182 fatal('no simpoint for testsys.cpu[%d].workload[0]', i) 183 checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset 184 testsys.cpu[i].max_insts_any_thread = checkpoint_inst 185 # used for output below 186 options.take_checkpoints = checkpoint_inst 187 else: 188 options.take_checkpoints = offset 189 # Set all test cpus with the right number of instructions 190 # for the upcoming simulation 191 for i in xrange(np): 192 testsys.cpu[i].max_insts_any_thread = offset 193 194 checkpoint_dir = None 195 if options.checkpoint_restore != None: 196 from os.path import isdir, exists 197 from os import listdir 198 import re 199 200 if not isdir(cptdir): 201 fatal("checkpoint dir %s does not exist!", cptdir) 202 203 if options.at_instruction or options.simpoint: 204 inst = options.checkpoint_restore 205 if options.simpoint: 206 # assume workload 0 has the simpoint 207 if testsys.cpu[0].workload[0].simpoint == 0: 208 fatal('Unable to find simpoint') 209 inst += int(testsys.cpu[0].workload[0].simpoint) 210 211 checkpoint_dir = joinpath(cptdir, 212 "cpt.%s.%s" % (options.bench, inst)) 213 if not exists(checkpoint_dir): 214 fatal("Unable to find checkpoint directory %s", checkpoint_dir) 215 else: 216 dirs = listdir(cptdir) 217 expr = re.compile('cpt\.([0-9]*)') 218 cpts = [] 219 for dir in dirs: 220 match = expr.match(dir) 221 if match: 222 cpts.append(match.group(1)) 223 224 cpts.sort(lambda a,b: cmp(long(a), long(b))) 225 226 cpt_num = options.checkpoint_restore 227 228 if cpt_num > len(cpts): 229 fatal('Checkpoint %d not found', cpt_num) 230 231 ## Adjust max tick based on our starting tick 232 maxtick = maxtick - int(cpts[cpt_num - 1]) 233 checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) 234 235 m5.instantiate(checkpoint_dir) 236 237 if options.standard_switch or cpu_class: 238 if options.standard_switch: 239 print "Switch at instruction count:%s" % \ 240 str(testsys.cpu[0].max_insts_any_thread) 241 exit_event = m5.simulate() 242 elif cpu_class and options.fast_forward: 243 print "Switch at instruction count:%s" % \ 244 str(testsys.cpu[0].max_insts_any_thread) 245 exit_event = m5.simulate() 246 else: 247 print "Switch at curTick count:%s" % str(10000) 248 exit_event = m5.simulate(10000) 249 print "Switched CPUS @ tick %s" % (m5.curTick()) 250 251 # when you change to Timing (or Atomic), you halt the system 252 # given as argument. When you are finished with the system 253 # changes (including switchCpus), you must resume the system 254 # manually. You DON'T need to resume after just switching 255 # CPUs if you haven't changed anything on the system level. 256 257 m5.changeToTiming(testsys) 258 m5.switchCpus(switch_cpu_list) 259 m5.resume(testsys) 260 261 if options.standard_switch: 262 print "Switch at instruction count:%d" % \ 263 (testsys.switch_cpus[0].max_insts_any_thread) 264 265 #warmup instruction count may have already been set 266 if options.warmup_insts: 267 exit_event = m5.simulate() 268 else: 269 exit_event = m5.simulate(options.warmup) 270 print "Switching CPUS @ tick %s" % (m5.curTick()) 271 print "Simulation ends instruction count:%d" % \ 272 (testsys.switch_cpus_1[0].max_insts_any_thread) 273 m5.drain(testsys) 274 m5.switchCpus(switch_cpu_list1) 275 m5.resume(testsys) 276 277 num_checkpoints = 0 278 exit_cause = '' 279 280 # If we're taking and restoring checkpoints, use checkpoint_dir 281 # option only for finding the checkpoints to restore from. This 282 # lets us test checkpointing by restoring from one set of 283 # checkpoints, generating a second set, and then comparing them. 284 if options.take_checkpoints and options.checkpoint_restore: 285 if m5.options.outdir: 286 cptdir = m5.options.outdir 287 else: 288 cptdir = getcwd() 289 290 # Checkpoints being taken via the command line at <when> and at 291 # subsequent periods of <period>. Checkpoint instructions 292 # received from the benchmark running are ignored and skipped in 293 # favor of command line checkpoint instructions. 294 if options.take_checkpoints != None : 295 if options.at_instruction or options.simpoint: 296 checkpoint_inst = int(options.take_checkpoints) 297 298 # maintain correct offset if we restored from some instruction 299 if options.checkpoint_restore != None: 300 checkpoint_inst += options.checkpoint_restore 301 302 print "Creating checkpoint at inst:%d" % (checkpoint_inst) 303 exit_event = m5.simulate() 304 print "exit cause = %s" % (exit_event.getCause()) 305 306 # skip checkpoint instructions should they exist 307 while exit_event.getCause() == "checkpoint": 308 exit_event = m5.simulate() 309 310 if exit_event.getCause() == \ 311 "a thread reached the max instruction count": 312 m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ 313 (options.bench, checkpoint_inst))) 314 print "Checkpoint written." 315 num_checkpoints += 1 316 317 if exit_event.getCause() == "user interrupt received": 318 exit_cause = exit_event.getCause(); 319 else: 320 when, period = options.take_checkpoints.split(",", 1) 321 when = int(when) 322 period = int(period) 323 324 exit_event = m5.simulate(when) 325 while exit_event.getCause() == "checkpoint": 326 exit_event = m5.simulate(when - m5.curTick()) 327 328 if exit_event.getCause() == "simulate() limit reached": 329 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 330 num_checkpoints += 1 331 332 sim_ticks = when 333 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 334 while num_checkpoints < max_checkpoints and \ 335 exit_event.getCause() == "simulate() limit reached": 336 if (sim_ticks + period) > maxtick: 337 exit_event = m5.simulate(maxtick - sim_ticks) 338 exit_cause = exit_event.getCause() 339 break 340 else: 341 exit_event = m5.simulate(period) 342 sim_ticks += period 343 while exit_event.getCause() == "checkpoint": 344 exit_event = m5.simulate(sim_ticks - m5.curTick()) 345 if exit_event.getCause() == "simulate() limit reached": 346 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 347 num_checkpoints += 1 348 349 if exit_event.getCause() != "simulate() limit reached": 350 exit_cause = exit_event.getCause(); 351 352 else: # no checkpoints being taken via this script 353 if options.fast_forward: 354 m5.stats.reset() 355 print "**** REAL SIMULATION ****" 356 exit_event = m5.simulate(maxtick) 357 358 while exit_event.getCause() == "checkpoint": 359 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 360 num_checkpoints += 1 361 if num_checkpoints == max_checkpoints: 362 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 363 break 364 365 exit_event = m5.simulate(maxtick - m5.curTick()) 366 exit_cause = exit_event.getCause() 367 368 if exit_cause == '': 369 exit_cause = exit_event.getCause() 370 print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause) 371 372 if options.checkpoint_at_end: 373 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 374 375