Simulation.py revision 9140:cfd2a8364ea1
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 * 37from O3_ARM_v7a import * 38 39addToPath('../common') 40 41def getCPUClass(cpu_type): 42 """Returns the required cpu class and the mode of operation. 43 """ 44 45 if cpu_type == "timing": 46 return TimingSimpleCPU, 'timing' 47 elif cpu_type == "detailed": 48 return DerivO3CPU, 'timing' 49 elif cpu_type == "arm_detailed": 50 return O3_ARM_v7a_3, 'timing' 51 elif cpu_type == "inorder": 52 return InOrderCPU, 'timing' 53 else: 54 return AtomicSimpleCPU, 'atomic' 55 56def setCPUClass(options): 57 """Returns two cpu classes and the initial mode of operation. 58 59 Restoring from a checkpoint or fast forwarding through a benchmark 60 can be done using one type of cpu, and then the actual 61 simulation can be carried out using another type. This function 62 returns these two types of cpus and the initial mode of operation 63 depending on the options provided. 64 """ 65 66 if options.cpu_type == "detailed" or \ 67 options.cpu_type == "arm_detailed" or \ 68 options.cpu_type == "inorder" : 69 if not options.caches and not options.ruby: 70 fatal("O3/Inorder CPU must be used with caches") 71 72 TmpClass, test_mem_mode = getCPUClass(options.cpu_type) 73 CPUClass = None 74 75 if options.checkpoint_restore != None: 76 if options.restore_with_cpu != options.cpu_type: 77 CPUClass = TmpClass 78 TmpClass, test_mem_mode = getCPUClass(options.restore_with_cpu) 79 elif options.fast_forward: 80 CPUClass = TmpClass 81 TmpClass = AtomicSimpleCPU 82 test_mem_mode = 'atomic' 83 84 return (TmpClass, test_mem_mode, CPUClass) 85 86def setWorkCountOptions(system, options): 87 if options.work_item_id != None: 88 system.work_item_id = options.work_item_id 89 if options.work_begin_cpu_id_exit != None: 90 system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit 91 if options.work_end_exit_count != None: 92 system.work_end_exit_count = options.work_end_exit_count 93 if options.work_end_checkpoint_count != None: 94 system.work_end_ckpt_count = options.work_end_checkpoint_count 95 if options.work_begin_exit_count != None: 96 system.work_begin_exit_count = options.work_begin_exit_count 97 if options.work_begin_checkpoint_count != None: 98 system.work_begin_ckpt_count = options.work_begin_checkpoint_count 99 if options.work_cpus_checkpoint_count != None: 100 system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count 101 102def findCptDir(options, maxtick, cptdir, testsys): 103 """Figures out the directory from which the checkpointed state is read. 104 105 There are two different ways in which the directories holding checkpoints 106 can be named -- 107 1. cpt.<benchmark name>.<instruction count when the checkpoint was taken> 108 2. cpt.<some number, usually the tick value when the checkpoint was taken> 109 110 This function parses through the options to figure out which one of the 111 above should be used for selecting the checkpoint, and then figures out 112 the appropriate directory. 113 114 It also sets the value of the maximum tick value till which the simulation 115 will run. 116 """ 117 118 from os.path import isdir, exists 119 from os import listdir 120 import re 121 122 if not isdir(cptdir): 123 fatal("checkpoint dir %s does not exist!", cptdir) 124 125 if options.at_instruction or options.simpoint: 126 inst = options.checkpoint_restore 127 if options.simpoint: 128 # assume workload 0 has the simpoint 129 if testsys.cpu[0].workload[0].simpoint == 0: 130 fatal('Unable to find simpoint') 131 inst += int(testsys.cpu[0].workload[0].simpoint) 132 133 checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst)) 134 if not exists(checkpoint_dir): 135 fatal("Unable to find checkpoint directory %s", checkpoint_dir) 136 else: 137 dirs = listdir(cptdir) 138 expr = re.compile('cpt\.([0-9]*)') 139 cpts = [] 140 for dir in dirs: 141 match = expr.match(dir) 142 if match: 143 cpts.append(match.group(1)) 144 145 cpts.sort(lambda a,b: cmp(long(a), long(b))) 146 147 cpt_num = options.checkpoint_restore 148 if cpt_num > len(cpts): 149 fatal('Checkpoint %d not found', cpt_num) 150 151 maxtick = maxtick - int(cpts[cpt_num - 1]) 152 checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) 153 154 return maxtick, checkpoint_dir 155 156def scriptCheckpoints(options): 157 if options.at_instruction or options.simpoint: 158 checkpoint_inst = int(options.take_checkpoints) 159 160 # maintain correct offset if we restored from some instruction 161 if options.checkpoint_restore != None: 162 checkpoint_inst += options.checkpoint_restore 163 164 print "Creating checkpoint at inst:%d" % (checkpoint_inst) 165 exit_event = m5.simulate() 166 exit_cause = exit_event.getCause() 167 print "exit cause = %s" % exit_cause 168 169 # skip checkpoint instructions should they exist 170 while exit_cause == "checkpoint": 171 exit_event = m5.simulate() 172 exit_cause = exit_event.getCause() 173 174 if exit_cause == "a thread reached the max instruction count": 175 m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ 176 (options.bench, checkpoint_inst))) 177 print "Checkpoint written." 178 179 else: 180 when, period = options.take_checkpoints.split(",", 1) 181 when = int(when) 182 period = int(period) 183 184 exit_event = m5.simulate(when) 185 exit_cause = exit_event.getCause() 186 while exit_cause == "checkpoint": 187 exit_event = m5.simulate(when - m5.curTick()) 188 exit_cause = exit_event.getCause() 189 190 if exit_cause == "simulate() limit reached": 191 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 192 num_checkpoints += 1 193 194 sim_ticks = when 195 num_checkpoints = 0 196 max_checkpoints = options.max_checkpoints 197 198 while num_checkpoints < max_checkpoints and \ 199 exit_cause == "simulate() limit reached": 200 if (sim_ticks + period) > maxtick: 201 exit_event = m5.simulate(maxtick - sim_ticks) 202 exit_cause = exit_event.getCause() 203 break 204 else: 205 exit_event = m5.simulate(period) 206 exit_cause = exit_event.getCause() 207 sim_ticks += period 208 while exit_event.getCause() == "checkpoint": 209 exit_event = m5.simulate(sim_ticks - m5.curTick()) 210 if exit_event.getCause() == "simulate() limit reached": 211 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 212 num_checkpoints += 1 213 214 return exit_cause 215 216def benchCheckpoints(options, maxtick, cptdir): 217 if options.fast_forward: 218 m5.stats.reset() 219 220 print "**** REAL SIMULATION ****" 221 exit_event = m5.simulate(maxtick) 222 exit_cause = exit_event.getCause() 223 224 num_checkpoints = 0 225 max_checkpoints = options.max_checkpoints 226 227 while exit_cause == "checkpoint": 228 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 229 num_checkpoints += 1 230 if num_checkpoints == max_checkpoints: 231 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 232 break 233 234 exit_event = m5.simulate(maxtick - m5.curTick()) 235 exit_cause = exit_event.getCause() 236 237 return exit_cause 238 239def run(options, root, testsys, cpu_class): 240 if options.maxtick: 241 maxtick = options.maxtick 242 elif options.maxtime: 243 simtime = m5.ticks.seconds(simtime) 244 print "simulating for: ", simtime 245 maxtick = simtime 246 else: 247 maxtick = m5.MaxTick 248 249 if options.checkpoint_dir: 250 cptdir = options.checkpoint_dir 251 elif m5.options.outdir: 252 cptdir = m5.options.outdir 253 else: 254 cptdir = getcwd() 255 256 if options.fast_forward and options.checkpoint_restore != None: 257 fatal("Can't specify both --fast-forward and --checkpoint-restore") 258 259 if options.standard_switch and not options.caches: 260 fatal("Must specify --caches when using --standard-switch") 261 262 np = options.num_cpus 263 switch_cpus = None 264 265 if options.prog_interval: 266 for i in xrange(np): 267 testsys.cpu[i].progress_interval = options.prog_interval 268 269 if options.maxinsts: 270 for i in xrange(np): 271 testsys.cpu[i].max_insts_any_thread = options.maxinsts 272 273 if cpu_class: 274 switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i)) 275 for i in xrange(np)] 276 277 for i in xrange(np): 278 if options.fast_forward: 279 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 280 switch_cpus[i].system = testsys 281 switch_cpus[i].workload = testsys.cpu[i].workload 282 switch_cpus[i].clock = testsys.cpu[i].clock 283 # simulation period 284 if options.maxinsts: 285 switch_cpus[i].max_insts_any_thread = options.maxinsts 286 # Add checker cpu if selected 287 if options.checker: 288 switch_cpus[i].addCheckerCpu() 289 290 testsys.switch_cpus = switch_cpus 291 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 292 293 if options.standard_switch: 294 if not options.caches: 295 # O3 CPU must have a cache to work. 296 print "O3 CPU must be used with caches" 297 sys.exit(1) 298 299 switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) 300 for i in xrange(np)] 301 switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) 302 for i in xrange(np)] 303 304 for i in xrange(np): 305 switch_cpus[i].system = testsys 306 switch_cpus_1[i].system = testsys 307 switch_cpus[i].workload = testsys.cpu[i].workload 308 switch_cpus_1[i].workload = testsys.cpu[i].workload 309 switch_cpus[i].clock = testsys.cpu[i].clock 310 switch_cpus_1[i].clock = testsys.cpu[i].clock 311 312 # if restoring, make atomic cpu simulate only a few instructions 313 if options.checkpoint_restore != None: 314 testsys.cpu[i].max_insts_any_thread = 1 315 # Fast forward to specified location if we are not restoring 316 elif options.fast_forward: 317 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 318 # Fast forward to a simpoint (warning: time consuming) 319 elif options.simpoint: 320 if testsys.cpu[i].workload[0].simpoint == 0: 321 fatal('simpoint not found') 322 testsys.cpu[i].max_insts_any_thread = \ 323 testsys.cpu[i].workload[0].simpoint 324 # No distance specified, just switch 325 else: 326 testsys.cpu[i].max_insts_any_thread = 1 327 328 # warmup period 329 if options.warmup_insts: 330 switch_cpus[i].max_insts_any_thread = options.warmup_insts 331 332 # simulation period 333 if options.maxinsts: 334 switch_cpus_1[i].max_insts_any_thread = options.maxinsts 335 336 # attach the checker cpu if selected 337 if options.checker: 338 switch_cpus[i].addCheckerCpu() 339 switch_cpus_1[i].addCheckerCpu() 340 341 testsys.switch_cpus = switch_cpus 342 testsys.switch_cpus_1 = switch_cpus_1 343 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 344 switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] 345 346 # set the checkpoint in the cpu before m5.instantiate is called 347 if options.take_checkpoints != None and \ 348 (options.simpoint or options.at_instruction): 349 offset = int(options.take_checkpoints) 350 # Set an instruction break point 351 if options.simpoint: 352 for i in xrange(np): 353 if testsys.cpu[i].workload[0].simpoint == 0: 354 fatal('no simpoint for testsys.cpu[%d].workload[0]', i) 355 checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset 356 testsys.cpu[i].max_insts_any_thread = checkpoint_inst 357 # used for output below 358 options.take_checkpoints = checkpoint_inst 359 else: 360 options.take_checkpoints = offset 361 # Set all test cpus with the right number of instructions 362 # for the upcoming simulation 363 for i in xrange(np): 364 testsys.cpu[i].max_insts_any_thread = offset 365 366 checkpoint_dir = None 367 if options.checkpoint_restore != None: 368 maxtick, checkpoint_dir = findCptDir(options, maxtick, cptdir, testsys) 369 m5.instantiate(checkpoint_dir) 370 371 if options.standard_switch or cpu_class: 372 if options.standard_switch: 373 print "Switch at instruction count:%s" % \ 374 str(testsys.cpu[0].max_insts_any_thread) 375 exit_event = m5.simulate() 376 elif cpu_class and options.fast_forward: 377 print "Switch at instruction count:%s" % \ 378 str(testsys.cpu[0].max_insts_any_thread) 379 exit_event = m5.simulate() 380 else: 381 print "Switch at curTick count:%s" % str(10000) 382 exit_event = m5.simulate(10000) 383 print "Switched CPUS @ tick %s" % (m5.curTick()) 384 385 # when you change to Timing (or Atomic), you halt the system 386 # given as argument. When you are finished with the system 387 # changes (including switchCpus), you must resume the system 388 # manually. You DON'T need to resume after just switching 389 # CPUs if you haven't changed anything on the system level. 390 391 m5.changeToTiming(testsys) 392 m5.switchCpus(switch_cpu_list) 393 m5.resume(testsys) 394 395 if options.standard_switch: 396 print "Switch at instruction count:%d" % \ 397 (testsys.switch_cpus[0].max_insts_any_thread) 398 399 #warmup instruction count may have already been set 400 if options.warmup_insts: 401 exit_event = m5.simulate() 402 else: 403 exit_event = m5.simulate(options.warmup) 404 print "Switching CPUS @ tick %s" % (m5.curTick()) 405 print "Simulation ends instruction count:%d" % \ 406 (testsys.switch_cpus_1[0].max_insts_any_thread) 407 m5.drain(testsys) 408 m5.switchCpus(switch_cpu_list1) 409 m5.resume(testsys) 410 411 # If we're taking and restoring checkpoints, use checkpoint_dir 412 # option only for finding the checkpoints to restore from. This 413 # lets us test checkpointing by restoring from one set of 414 # checkpoints, generating a second set, and then comparing them. 415 if options.take_checkpoints and options.checkpoint_restore: 416 if m5.options.outdir: 417 cptdir = m5.options.outdir 418 else: 419 cptdir = getcwd() 420 421 if options.take_checkpoints != None : 422 # Checkpoints being taken via the command line at <when> and at 423 # subsequent periods of <period>. Checkpoint instructions 424 # received from the benchmark running are ignored and skipped in 425 # favor of command line checkpoint instructions. 426 exit_cause = scriptCheckpoints(options) 427 else: 428 # If checkpoints are being taken, then the checkpoint instruction 429 # will occur in the benchmark code it self. 430 exit_cause = benchCheckpoints(options, maxtick, cptdir) 431 432 print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause) 433 if options.checkpoint_at_end: 434 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 435