Simulation.py revision 9139:ee038fbbe5d2
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 run(options, root, testsys, cpu_class): 103 if options.maxtick: 104 maxtick = options.maxtick 105 elif options.maxtime: 106 simtime = m5.ticks.seconds(simtime) 107 print "simulating for: ", simtime 108 maxtick = simtime 109 else: 110 maxtick = m5.MaxTick 111 112 if options.checkpoint_dir: 113 cptdir = options.checkpoint_dir 114 elif m5.options.outdir: 115 cptdir = m5.options.outdir 116 else: 117 cptdir = getcwd() 118 119 if options.fast_forward and options.checkpoint_restore != None: 120 fatal("Can't specify both --fast-forward and --checkpoint-restore") 121 122 if options.standard_switch and not options.caches: 123 fatal("Must specify --caches when using --standard-switch") 124 125 np = options.num_cpus 126 max_checkpoints = options.max_checkpoints 127 switch_cpus = None 128 129 if options.prog_interval: 130 for i in xrange(np): 131 testsys.cpu[i].progress_interval = options.prog_interval 132 133 if options.maxinsts: 134 for i in xrange(np): 135 testsys.cpu[i].max_insts_any_thread = options.maxinsts 136 137 if cpu_class: 138 switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i)) 139 for i in xrange(np)] 140 141 for i in xrange(np): 142 if options.fast_forward: 143 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 144 switch_cpus[i].system = testsys 145 switch_cpus[i].workload = testsys.cpu[i].workload 146 switch_cpus[i].clock = testsys.cpu[i].clock 147 # simulation period 148 if options.maxinsts: 149 switch_cpus[i].max_insts_any_thread = options.maxinsts 150 # Add checker cpu if selected 151 if options.checker: 152 switch_cpus[i].addCheckerCpu() 153 154 testsys.switch_cpus = switch_cpus 155 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 156 157 if options.standard_switch: 158 if not options.caches: 159 # O3 CPU must have a cache to work. 160 print "O3 CPU must be used with caches" 161 sys.exit(1) 162 163 switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) 164 for i in xrange(np)] 165 switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) 166 for i in xrange(np)] 167 168 for i in xrange(np): 169 switch_cpus[i].system = testsys 170 switch_cpus_1[i].system = testsys 171 switch_cpus[i].workload = testsys.cpu[i].workload 172 switch_cpus_1[i].workload = testsys.cpu[i].workload 173 switch_cpus[i].clock = testsys.cpu[i].clock 174 switch_cpus_1[i].clock = testsys.cpu[i].clock 175 176 # if restoring, make atomic cpu simulate only a few instructions 177 if options.checkpoint_restore != None: 178 testsys.cpu[i].max_insts_any_thread = 1 179 # Fast forward to specified location if we are not restoring 180 elif options.fast_forward: 181 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 182 # Fast forward to a simpoint (warning: time consuming) 183 elif options.simpoint: 184 if testsys.cpu[i].workload[0].simpoint == 0: 185 fatal('simpoint not found') 186 testsys.cpu[i].max_insts_any_thread = \ 187 testsys.cpu[i].workload[0].simpoint 188 # No distance specified, just switch 189 else: 190 testsys.cpu[i].max_insts_any_thread = 1 191 192 # warmup period 193 if options.warmup_insts: 194 switch_cpus[i].max_insts_any_thread = options.warmup_insts 195 196 # simulation period 197 if options.maxinsts: 198 switch_cpus_1[i].max_insts_any_thread = options.maxinsts 199 200 # attach the checker cpu if selected 201 if options.checker: 202 switch_cpus[i].addCheckerCpu() 203 switch_cpus_1[i].addCheckerCpu() 204 205 testsys.switch_cpus = switch_cpus 206 testsys.switch_cpus_1 = switch_cpus_1 207 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 208 switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] 209 210 # set the checkpoint in the cpu before m5.instantiate is called 211 if options.take_checkpoints != None and \ 212 (options.simpoint or options.at_instruction): 213 offset = int(options.take_checkpoints) 214 # Set an instruction break point 215 if options.simpoint: 216 for i in xrange(np): 217 if testsys.cpu[i].workload[0].simpoint == 0: 218 fatal('no simpoint for testsys.cpu[%d].workload[0]', i) 219 checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset 220 testsys.cpu[i].max_insts_any_thread = checkpoint_inst 221 # used for output below 222 options.take_checkpoints = checkpoint_inst 223 else: 224 options.take_checkpoints = offset 225 # Set all test cpus with the right number of instructions 226 # for the upcoming simulation 227 for i in xrange(np): 228 testsys.cpu[i].max_insts_any_thread = offset 229 230 checkpoint_dir = None 231 if options.checkpoint_restore != None: 232 from os.path import isdir, exists 233 from os import listdir 234 import re 235 236 if not isdir(cptdir): 237 fatal("checkpoint dir %s does not exist!", cptdir) 238 239 if options.at_instruction or options.simpoint: 240 inst = options.checkpoint_restore 241 if options.simpoint: 242 # assume workload 0 has the simpoint 243 if testsys.cpu[0].workload[0].simpoint == 0: 244 fatal('Unable to find simpoint') 245 inst += int(testsys.cpu[0].workload[0].simpoint) 246 247 checkpoint_dir = joinpath(cptdir, 248 "cpt.%s.%s" % (options.bench, inst)) 249 if not exists(checkpoint_dir): 250 fatal("Unable to find checkpoint directory %s", checkpoint_dir) 251 else: 252 dirs = listdir(cptdir) 253 expr = re.compile('cpt\.([0-9]*)') 254 cpts = [] 255 for dir in dirs: 256 match = expr.match(dir) 257 if match: 258 cpts.append(match.group(1)) 259 260 cpts.sort(lambda a,b: cmp(long(a), long(b))) 261 262 cpt_num = options.checkpoint_restore 263 264 if cpt_num > len(cpts): 265 fatal('Checkpoint %d not found', cpt_num) 266 267 ## Adjust max tick based on our starting tick 268 maxtick = maxtick - int(cpts[cpt_num - 1]) 269 checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) 270 271 m5.instantiate(checkpoint_dir) 272 273 if options.standard_switch or cpu_class: 274 if options.standard_switch: 275 print "Switch at instruction count:%s" % \ 276 str(testsys.cpu[0].max_insts_any_thread) 277 exit_event = m5.simulate() 278 elif cpu_class and options.fast_forward: 279 print "Switch at instruction count:%s" % \ 280 str(testsys.cpu[0].max_insts_any_thread) 281 exit_event = m5.simulate() 282 else: 283 print "Switch at curTick count:%s" % str(10000) 284 exit_event = m5.simulate(10000) 285 print "Switched CPUS @ tick %s" % (m5.curTick()) 286 287 # when you change to Timing (or Atomic), you halt the system 288 # given as argument. When you are finished with the system 289 # changes (including switchCpus), you must resume the system 290 # manually. You DON'T need to resume after just switching 291 # CPUs if you haven't changed anything on the system level. 292 293 m5.changeToTiming(testsys) 294 m5.switchCpus(switch_cpu_list) 295 m5.resume(testsys) 296 297 if options.standard_switch: 298 print "Switch at instruction count:%d" % \ 299 (testsys.switch_cpus[0].max_insts_any_thread) 300 301 #warmup instruction count may have already been set 302 if options.warmup_insts: 303 exit_event = m5.simulate() 304 else: 305 exit_event = m5.simulate(options.warmup) 306 print "Switching CPUS @ tick %s" % (m5.curTick()) 307 print "Simulation ends instruction count:%d" % \ 308 (testsys.switch_cpus_1[0].max_insts_any_thread) 309 m5.drain(testsys) 310 m5.switchCpus(switch_cpu_list1) 311 m5.resume(testsys) 312 313 num_checkpoints = 0 314 exit_cause = '' 315 316 # If we're taking and restoring checkpoints, use checkpoint_dir 317 # option only for finding the checkpoints to restore from. This 318 # lets us test checkpointing by restoring from one set of 319 # checkpoints, generating a second set, and then comparing them. 320 if options.take_checkpoints and options.checkpoint_restore: 321 if m5.options.outdir: 322 cptdir = m5.options.outdir 323 else: 324 cptdir = getcwd() 325 326 # Checkpoints being taken via the command line at <when> and at 327 # subsequent periods of <period>. Checkpoint instructions 328 # received from the benchmark running are ignored and skipped in 329 # favor of command line checkpoint instructions. 330 if options.take_checkpoints != None : 331 if options.at_instruction or options.simpoint: 332 checkpoint_inst = int(options.take_checkpoints) 333 334 # maintain correct offset if we restored from some instruction 335 if options.checkpoint_restore != None: 336 checkpoint_inst += options.checkpoint_restore 337 338 print "Creating checkpoint at inst:%d" % (checkpoint_inst) 339 exit_event = m5.simulate() 340 print "exit cause = %s" % (exit_event.getCause()) 341 342 # skip checkpoint instructions should they exist 343 while exit_event.getCause() == "checkpoint": 344 exit_event = m5.simulate() 345 346 if exit_event.getCause() == \ 347 "a thread reached the max instruction count": 348 m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ 349 (options.bench, checkpoint_inst))) 350 print "Checkpoint written." 351 num_checkpoints += 1 352 353 if exit_event.getCause() == "user interrupt received": 354 exit_cause = exit_event.getCause(); 355 else: 356 when, period = options.take_checkpoints.split(",", 1) 357 when = int(when) 358 period = int(period) 359 360 exit_event = m5.simulate(when) 361 while exit_event.getCause() == "checkpoint": 362 exit_event = m5.simulate(when - m5.curTick()) 363 364 if exit_event.getCause() == "simulate() limit reached": 365 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 366 num_checkpoints += 1 367 368 sim_ticks = when 369 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 370 while num_checkpoints < max_checkpoints and \ 371 exit_event.getCause() == "simulate() limit reached": 372 if (sim_ticks + period) > maxtick: 373 exit_event = m5.simulate(maxtick - sim_ticks) 374 exit_cause = exit_event.getCause() 375 break 376 else: 377 exit_event = m5.simulate(period) 378 sim_ticks += period 379 while exit_event.getCause() == "checkpoint": 380 exit_event = m5.simulate(sim_ticks - m5.curTick()) 381 if exit_event.getCause() == "simulate() limit reached": 382 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 383 num_checkpoints += 1 384 385 if exit_event.getCause() != "simulate() limit reached": 386 exit_cause = exit_event.getCause(); 387 388 else: # no checkpoints being taken via this script 389 if options.fast_forward: 390 m5.stats.reset() 391 print "**** REAL SIMULATION ****" 392 exit_event = m5.simulate(maxtick) 393 394 while exit_event.getCause() == "checkpoint": 395 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 396 num_checkpoints += 1 397 if num_checkpoints == max_checkpoints: 398 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 399 break 400 401 exit_event = m5.simulate(maxtick - m5.curTick()) 402 exit_cause = exit_event.getCause() 403 404 if exit_cause == '': 405 exit_cause = exit_event.getCause() 406 print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause) 407 408 if options.checkpoint_at_end: 409 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 410 411