Simulation.py revision 9816:971507cbbe65
1# Copyright (c) 2012-2013 ARM Limited 2# All rights reserved 3# 4# The license below extends only to copyright in the software and shall 5# not be construed as granting a license to any other intellectual 6# property including but not limited to intellectual property relating 7# to a hardware implementation of the functionality of the software 8# licensed hereunder. You may use the software subject to the license 9# terms below provided that you ensure that this notice is replicated 10# unmodified and in its entirety in all distributions of the software, 11# modified or unmodified, in source code or in binary form. 12# 13# Copyright (c) 2006-2008 The Regents of The University of Michigan 14# Copyright (c) 2010 Advanced Micro Devices, Inc. 15# All rights reserved. 16# 17# Redistribution and use in source and binary forms, with or without 18# modification, are permitted provided that the following conditions are 19# met: redistributions of source code must retain the above copyright 20# notice, this list of conditions and the following disclaimer; 21# redistributions in binary form must reproduce the above copyright 22# notice, this list of conditions and the following disclaimer in the 23# documentation and/or other materials provided with the distribution; 24# neither the name of the copyright holders nor the names of its 25# contributors may be used to endorse or promote products derived from 26# this software without specific prior written permission. 27# 28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39# 40# Authors: Lisa Hsu 41 42import sys 43from os import getcwd 44from os.path import join as joinpath 45 46import CpuConfig 47import MemConfig 48 49import m5 50from m5.defines import buildEnv 51from m5.objects import * 52from m5.util import * 53 54addToPath('../common') 55 56def getCPUClass(cpu_type): 57 """Returns the required cpu class and the mode of operation.""" 58 cls = CpuConfig.get(cpu_type) 59 return cls, cls.memory_mode() 60 61def setCPUClass(options): 62 """Returns two cpu classes and the initial mode of operation. 63 64 Restoring from a checkpoint or fast forwarding through a benchmark 65 can be done using one type of cpu, and then the actual 66 simulation can be carried out using another type. This function 67 returns these two types of cpus and the initial mode of operation 68 depending on the options provided. 69 """ 70 71 TmpClass, test_mem_mode = getCPUClass(options.cpu_type) 72 CPUClass = None 73 if TmpClass.require_caches() and \ 74 not options.caches and not options.ruby: 75 fatal("%s must be used with caches" % options.cpu_type) 76 77 if options.checkpoint_restore != None: 78 if options.restore_with_cpu != options.cpu_type: 79 CPUClass = TmpClass 80 TmpClass, test_mem_mode = getCPUClass(options.restore_with_cpu) 81 elif options.fast_forward: 82 CPUClass = TmpClass 83 TmpClass = AtomicSimpleCPU 84 test_mem_mode = 'atomic' 85 86 return (TmpClass, test_mem_mode, CPUClass) 87 88def setMemClass(options): 89 """Returns a memory controller class.""" 90 91 return MemConfig.get(options.mem_type) 92 93def setWorkCountOptions(system, options): 94 if options.work_item_id != None: 95 system.work_item_id = options.work_item_id 96 if options.work_begin_cpu_id_exit != None: 97 system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit 98 if options.work_end_exit_count != None: 99 system.work_end_exit_count = options.work_end_exit_count 100 if options.work_end_checkpoint_count != None: 101 system.work_end_ckpt_count = options.work_end_checkpoint_count 102 if options.work_begin_exit_count != None: 103 system.work_begin_exit_count = options.work_begin_exit_count 104 if options.work_begin_checkpoint_count != None: 105 system.work_begin_ckpt_count = options.work_begin_checkpoint_count 106 if options.work_cpus_checkpoint_count != None: 107 system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count 108 109def findCptDir(options, cptdir, testsys): 110 """Figures out the directory from which the checkpointed state is read. 111 112 There are two different ways in which the directories holding checkpoints 113 can be named -- 114 1. cpt.<benchmark name>.<instruction count when the checkpoint was taken> 115 2. cpt.<some number, usually the tick value when the checkpoint was taken> 116 117 This function parses through the options to figure out which one of the 118 above should be used for selecting the checkpoint, and then figures out 119 the appropriate directory. 120 """ 121 122 from os.path import isdir, exists 123 from os import listdir 124 import re 125 126 if not isdir(cptdir): 127 fatal("checkpoint dir %s does not exist!", cptdir) 128 129 if options.at_instruction or options.simpoint: 130 inst = options.checkpoint_restore 131 if options.simpoint: 132 # assume workload 0 has the simpoint 133 if testsys.cpu[0].workload[0].simpoint == 0: 134 fatal('Unable to find simpoint') 135 inst += int(testsys.cpu[0].workload[0].simpoint) 136 137 checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst)) 138 if not exists(checkpoint_dir): 139 fatal("Unable to find checkpoint directory %s", checkpoint_dir) 140 else: 141 dirs = listdir(cptdir) 142 expr = re.compile('cpt\.([0-9]*)') 143 cpts = [] 144 for dir in dirs: 145 match = expr.match(dir) 146 if match: 147 cpts.append(match.group(1)) 148 149 cpts.sort(lambda a,b: cmp(long(a), long(b))) 150 151 cpt_num = options.checkpoint_restore 152 if cpt_num > len(cpts): 153 fatal('Checkpoint %d not found', cpt_num) 154 155 cpt_starttick = int(cpts[cpt_num - 1]) 156 checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) 157 158 return cpt_starttick, checkpoint_dir 159 160def scriptCheckpoints(options, maxtick, cptdir): 161 if options.at_instruction or options.simpoint: 162 checkpoint_inst = int(options.take_checkpoints) 163 164 # maintain correct offset if we restored from some instruction 165 if options.checkpoint_restore != None: 166 checkpoint_inst += options.checkpoint_restore 167 168 print "Creating checkpoint at inst:%d" % (checkpoint_inst) 169 exit_event = m5.simulate() 170 exit_cause = exit_event.getCause() 171 print "exit cause = %s" % exit_cause 172 173 # skip checkpoint instructions should they exist 174 while exit_cause == "checkpoint": 175 exit_event = m5.simulate() 176 exit_cause = exit_event.getCause() 177 178 if exit_cause == "a thread reached the max instruction count": 179 m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ 180 (options.bench, checkpoint_inst))) 181 print "Checkpoint written." 182 183 else: 184 when, period = options.take_checkpoints.split(",", 1) 185 when = int(when) 186 period = int(period) 187 num_checkpoints = 0 188 189 exit_event = m5.simulate(when - m5.curTick()) 190 exit_cause = exit_event.getCause() 191 while exit_cause == "checkpoint": 192 exit_event = m5.simulate(when - m5.curTick()) 193 exit_cause = exit_event.getCause() 194 195 if exit_cause == "simulate() limit reached": 196 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 197 num_checkpoints += 1 198 199 sim_ticks = when 200 max_checkpoints = options.max_checkpoints 201 202 while num_checkpoints < max_checkpoints and \ 203 exit_cause == "simulate() limit reached": 204 if (sim_ticks + period) > maxtick: 205 exit_event = m5.simulate(maxtick - sim_ticks) 206 exit_cause = exit_event.getCause() 207 break 208 else: 209 exit_event = m5.simulate(period) 210 exit_cause = exit_event.getCause() 211 sim_ticks += period 212 while exit_event.getCause() == "checkpoint": 213 exit_event = m5.simulate(sim_ticks - m5.curTick()) 214 if exit_event.getCause() == "simulate() limit reached": 215 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 216 num_checkpoints += 1 217 218 return exit_event 219 220def benchCheckpoints(options, maxtick, cptdir): 221 exit_event = m5.simulate(maxtick - m5.curTick()) 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_event 238 239def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq): 240 print "starting switch loop" 241 while True: 242 exit_event = m5.simulate(switch_freq) 243 exit_cause = exit_event.getCause() 244 245 if exit_cause != "simulate() limit reached": 246 return exit_event 247 248 m5.switchCpus(testsys, repeat_switch_cpu_list) 249 250 tmp_cpu_list = [] 251 for old_cpu, new_cpu in repeat_switch_cpu_list: 252 tmp_cpu_list.append((new_cpu, old_cpu)) 253 repeat_switch_cpu_list = tmp_cpu_list 254 255 if (maxtick - m5.curTick()) <= switch_freq: 256 exit_event = m5.simulate(maxtick - m5.curTick()) 257 return exit_event 258 259def run(options, root, testsys, cpu_class): 260 if options.checkpoint_dir: 261 cptdir = options.checkpoint_dir 262 elif m5.options.outdir: 263 cptdir = m5.options.outdir 264 else: 265 cptdir = getcwd() 266 267 if options.fast_forward and options.checkpoint_restore != None: 268 fatal("Can't specify both --fast-forward and --checkpoint-restore") 269 270 if options.standard_switch and not options.caches: 271 fatal("Must specify --caches when using --standard-switch") 272 273 if options.standard_switch and options.repeat_switch: 274 fatal("Can't specify both --standard-switch and --repeat-switch") 275 276 if options.repeat_switch and options.take_checkpoints: 277 fatal("Can't specify both --repeat-switch and --take-checkpoints") 278 279 np = options.num_cpus 280 switch_cpus = None 281 282 if options.prog_interval: 283 for i in xrange(np): 284 testsys.cpu[i].progress_interval = options.prog_interval 285 286 if options.maxinsts: 287 for i in xrange(np): 288 testsys.cpu[i].max_insts_any_thread = options.maxinsts 289 290 if cpu_class: 291 switch_cpus = [cpu_class(switched_out=True, cpu_id=(i)) 292 for i in xrange(np)] 293 294 for i in xrange(np): 295 if options.fast_forward: 296 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 297 switch_cpus[i].system = testsys 298 switch_cpus[i].workload = testsys.cpu[i].workload 299 switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain 300 # simulation period 301 if options.maxinsts: 302 switch_cpus[i].max_insts_any_thread = options.maxinsts 303 # Add checker cpu if selected 304 if options.checker: 305 switch_cpus[i].addCheckerCpu() 306 307 testsys.switch_cpus = switch_cpus 308 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 309 310 if options.repeat_switch: 311 switch_class = getCPUClass(options.cpu_type)[0] 312 if switch_class.require_caches() and \ 313 not options.caches: 314 print "%s: Must be used with caches" % str(switch_class) 315 sys.exit(1) 316 if not switch_class.support_take_over(): 317 print "%s: CPU switching not supported" % str(switch_class) 318 sys.exit(1) 319 320 repeat_switch_cpus = [switch_class(switched_out=True, \ 321 cpu_id=(i)) for i in xrange(np)] 322 323 for i in xrange(np): 324 repeat_switch_cpus[i].system = testsys 325 repeat_switch_cpus[i].workload = testsys.cpu[i].workload 326 repeat_switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain 327 328 if options.maxinsts: 329 repeat_switch_cpus[i].max_insts_any_thread = options.maxinsts 330 331 if options.checker: 332 repeat_switch_cpus[i].addCheckerCpu() 333 334 testsys.repeat_switch_cpus = repeat_switch_cpus 335 336 if cpu_class: 337 repeat_switch_cpu_list = [(switch_cpus[i], repeat_switch_cpus[i]) 338 for i in xrange(np)] 339 else: 340 repeat_switch_cpu_list = [(testsys.cpu[i], repeat_switch_cpus[i]) 341 for i in xrange(np)] 342 343 if options.standard_switch: 344 switch_cpus = [TimingSimpleCPU(switched_out=True, cpu_id=(i)) 345 for i in xrange(np)] 346 switch_cpus_1 = [DerivO3CPU(switched_out=True, cpu_id=(i)) 347 for i in xrange(np)] 348 349 for i in xrange(np): 350 switch_cpus[i].system = testsys 351 switch_cpus_1[i].system = testsys 352 switch_cpus[i].workload = testsys.cpu[i].workload 353 switch_cpus_1[i].workload = testsys.cpu[i].workload 354 switch_cpus[i].clk_domain = testsys.cpu[i].clk_domain 355 switch_cpus_1[i].clk_domain = testsys.cpu[i].clk_domain 356 357 # if restoring, make atomic cpu simulate only a few instructions 358 if options.checkpoint_restore != None: 359 testsys.cpu[i].max_insts_any_thread = 1 360 # Fast forward to specified location if we are not restoring 361 elif options.fast_forward: 362 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 363 # Fast forward to a simpoint (warning: time consuming) 364 elif options.simpoint: 365 if testsys.cpu[i].workload[0].simpoint == 0: 366 fatal('simpoint not found') 367 testsys.cpu[i].max_insts_any_thread = \ 368 testsys.cpu[i].workload[0].simpoint 369 # No distance specified, just switch 370 else: 371 testsys.cpu[i].max_insts_any_thread = 1 372 373 # warmup period 374 if options.warmup_insts: 375 switch_cpus[i].max_insts_any_thread = options.warmup_insts 376 377 # simulation period 378 if options.maxinsts: 379 switch_cpus_1[i].max_insts_any_thread = options.maxinsts 380 381 # attach the checker cpu if selected 382 if options.checker: 383 switch_cpus[i].addCheckerCpu() 384 switch_cpus_1[i].addCheckerCpu() 385 386 testsys.switch_cpus = switch_cpus 387 testsys.switch_cpus_1 = switch_cpus_1 388 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 389 switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] 390 391 # set the checkpoint in the cpu before m5.instantiate is called 392 if options.take_checkpoints != None and \ 393 (options.simpoint or options.at_instruction): 394 offset = int(options.take_checkpoints) 395 # Set an instruction break point 396 if options.simpoint: 397 for i in xrange(np): 398 if testsys.cpu[i].workload[0].simpoint == 0: 399 fatal('no simpoint for testsys.cpu[%d].workload[0]', i) 400 checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset 401 testsys.cpu[i].max_insts_any_thread = checkpoint_inst 402 # used for output below 403 options.take_checkpoints = checkpoint_inst 404 else: 405 options.take_checkpoints = offset 406 # Set all test cpus with the right number of instructions 407 # for the upcoming simulation 408 for i in xrange(np): 409 testsys.cpu[i].max_insts_any_thread = offset 410 411 checkpoint_dir = None 412 if options.checkpoint_restore: 413 cpt_starttick, checkpoint_dir = findCptDir(options, cptdir, testsys) 414 m5.instantiate(checkpoint_dir) 415 416 # Handle the max tick settings now that tick frequency was resolved 417 # during system instantiation 418 # NOTE: the maxtick variable here is in absolute ticks, so it must 419 # include any simulated ticks before a checkpoint 420 explicit_maxticks = 0 421 maxtick_from_abs = m5.MaxTick 422 maxtick_from_rel = m5.MaxTick 423 maxtick_from_maxtime = m5.MaxTick 424 if options.abs_max_tick: 425 maxtick_from_abs = options.abs_max_tick 426 explicit_maxticks += 1 427 if options.rel_max_tick: 428 maxtick_from_rel = options.rel_max_tick 429 if options.checkpoint_restore: 430 # NOTE: this may need to be updated if checkpoints ever store 431 # the ticks per simulated second 432 maxtick_from_rel += cpt_starttick 433 explicit_maxticks += 1 434 if options.maxtime: 435 maxtick_from_maxtime = m5.ticks.fromSeconds(options.maxtime) 436 explicit_maxticks += 1 437 if explicit_maxticks > 1: 438 warn("Specified multiple of --abs-max-tick, --rel-max-tick, --maxtime."\ 439 " Using least") 440 maxtick = min([maxtick_from_abs, maxtick_from_rel, maxtick_from_maxtime]) 441 442 if options.checkpoint_restore != None and maxtick < cpt_starttick: 443 fatal("Bad maxtick (%d) specified: " \ 444 "Checkpoint starts starts from tick: %d", maxtick, cpt_starttick) 445 446 if options.standard_switch or cpu_class: 447 if options.standard_switch: 448 print "Switch at instruction count:%s" % \ 449 str(testsys.cpu[0].max_insts_any_thread) 450 exit_event = m5.simulate() 451 elif cpu_class and options.fast_forward: 452 print "Switch at instruction count:%s" % \ 453 str(testsys.cpu[0].max_insts_any_thread) 454 exit_event = m5.simulate() 455 else: 456 print "Switch at curTick count:%s" % str(10000) 457 exit_event = m5.simulate(10000) 458 print "Switched CPUS @ tick %s" % (m5.curTick()) 459 460 m5.switchCpus(testsys, switch_cpu_list) 461 462 if options.standard_switch: 463 print "Switch at instruction count:%d" % \ 464 (testsys.switch_cpus[0].max_insts_any_thread) 465 466 #warmup instruction count may have already been set 467 if options.warmup_insts: 468 exit_event = m5.simulate() 469 else: 470 exit_event = m5.simulate(options.standard_switch) 471 print "Switching CPUS @ tick %s" % (m5.curTick()) 472 print "Simulation ends instruction count:%d" % \ 473 (testsys.switch_cpus_1[0].max_insts_any_thread) 474 m5.switchCpus(testsys, switch_cpu_list1) 475 476 # If we're taking and restoring checkpoints, use checkpoint_dir 477 # option only for finding the checkpoints to restore from. This 478 # lets us test checkpointing by restoring from one set of 479 # checkpoints, generating a second set, and then comparing them. 480 if options.take_checkpoints and options.checkpoint_restore: 481 if m5.options.outdir: 482 cptdir = m5.options.outdir 483 else: 484 cptdir = getcwd() 485 486 if options.take_checkpoints != None : 487 # Checkpoints being taken via the command line at <when> and at 488 # subsequent periods of <period>. Checkpoint instructions 489 # received from the benchmark running are ignored and skipped in 490 # favor of command line checkpoint instructions. 491 exit_event = scriptCheckpoints(options, maxtick, cptdir) 492 else: 493 if options.fast_forward: 494 m5.stats.reset() 495 print "**** REAL SIMULATION ****" 496 497 # If checkpoints are being taken, then the checkpoint instruction 498 # will occur in the benchmark code it self. 499 if options.repeat_switch and maxtick > options.repeat_switch: 500 exit_event = repeatSwitch(testsys, repeat_switch_cpu_list, 501 maxtick, options.repeat_switch) 502 else: 503 exit_event = benchCheckpoints(options, maxtick, cptdir) 504 505 print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()) 506 if options.checkpoint_at_end: 507 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 508 509 if not m5.options.interactive: 510 sys.exit(exit_event.getCode()) 511