def __init__(self): requires( isa_required=ISA.X86, coherence_protocol_required=CoherenceProtocol.MESI_TWO_LEVEL, ) warn("The X86DemoBoard is solely for demonstration purposes. " "This board is not known to be be representative of any " "real-world system. Use with caution.") memory = SingleChannelDDR3_1600(size="2GB") processor = SimpleProcessor(cpu_type=CPUTypes.TIMING, num_cores=4) cache_hierarchy = MESITwoLevelCacheHierarchy( l1d_size="32kB", l1d_assoc=8, l1i_size="32kB", l1i_assoc=8, l2_size="1MB", l2_assoc=16, num_l2_banks=1, ) super().__init__( clk_freq="3GHz", processor=processor, memory=memory, cache_hierarchy=cache_hierarchy, )
def run(self, max_ticks: int = m5.MaxTick) -> None: """ This function will start or continue the simulator run and handle exit events accordingly. :param max_ticks: The maximum number of ticks to execute per simulation run. If this max_ticks value is met, a MAX_TICK exit event is received, if another simulation exit event is met the tick count is reset. This is the **maximum number of ticks per simululation run**. """ # We instantiate the board if it has not already been instantiated. self._instantiate() # This while loop will continue until an a generator yields True. while True: self._last_exit_event = m5.simulate(max_ticks) # Translate the exit event cause to the exit event enum. exit_enum = ExitEvent.translate_exit_status( self.get_last_exit_event_cause()) # Check to see the run is corresponding to the expected execution # order (assuming this check is demanded by the user). if self._expected_execution_order: expected_enum = self._expected_execution_order[ self._exit_event_count] if exit_enum.value != expected_enum.value: raise Exception( f"Expected a '{expected_enum.value}' exit event but a " f"'{exit_enum.value}' exit event was encountered.") # Record the current tick and exit event enum. self._tick_stopwatch.append((exit_enum, self.get_current_tick())) try: # If the user has specified their own generator for this exit # event, use it. exit_on_completion = next(self._on_exit_event[exit_enum]) except StopIteration: # If the user's generator has ended, throw a warning and use # the default generator for this exit event. warn("User-specified generator for the exit event " f"'{exit_enum.value}' has ended. Using the default " "generator.") exit_on_completion = next( self._default_on_exit_dict[exit_enum]) except KeyError: # If the user has not specified their own generator for this # exit event, use the default. exit_on_completion = next( self._default_on_exit_dict[exit_enum]) self._exit_event_count += 1 # If the generator returned True we will return from the Simulator # run loop. if exit_on_completion: return
def fromSeconds(value): import _m5.core if not isinstance(value, float): raise TypeError("can't convert '%s' to type tick" % type(value)) # once someone needs to convert to seconds, the global frequency # had better be fixed if not _m5.core.clockFrequencyFixed(): raise AttributeError( "In order to do conversions, the global frequency must be fixed") if value == 0: return 0 # convert the value from time to ticks value *= _m5.core.getClockFrequency() int_value = int( decimal.Decimal(value).to_integral_value( decimal.ROUND_HALF_UP)) err = (value - int_value) / value if err > frequency_tolerance: warn("rounding error > tolerance\n %f rounded to %d", value, int_value) return int_value
def incorporate_processor(self, board: AbstractBoard) -> None: if self._cpu_type == CPUTypes.KVM: board.kvm_vm = self.kvm_vm # Set the memory mode. if self._cpu_type == CPUTypes.TIMING or self._cpu_type == CPUTypes.O3: board.set_mem_mode(MemMode.TIMING) elif self._cpu_type == CPUTypes.KVM: board.set_mem_mode(MemMode.ATOMIC_NONCACHING) elif self._cpu_type == CPUTypes.ATOMIC: if board.get_cache_hierarchy().is_ruby(): warn( "Using an atomic core with Ruby will result in " "'atomic_noncaching' memory mode. This will skip caching " "completely." ) else: board.set_mem_mode(MemMode.ATOMIC) else: raise NotImplementedError if self._cpu_type == CPUTypes.KVM: # To get the KVM CPUs to run on different host CPUs # Specify a different event queue for each CPU for i, core in enumerate(self.cores): for obj in core.get_simobject().descendants(): obj.eventq_index = 0 core.get_simobject().eventq_index = i + 1
def create_network(options, ruby): # Allow legacy users to use garnet through garnet2.0 option # until next gem5 release. if options.network == "garnet2.0": warn("Usage of option 'garnet2.0' will be depracated. " \ "Please use 'garnet' for using the latest garnet " \ "version. Current version: 3.0") options.network = "garnet" # Set the network classes based on the command line options if options.network == "garnet": NetworkClass = GarnetNetwork IntLinkClass = GarnetIntLink ExtLinkClass = GarnetExtLink RouterClass = GarnetRouter InterfaceClass = GarnetNetworkInterface else: NetworkClass = SimpleNetwork IntLinkClass = SimpleIntLink ExtLinkClass = SimpleExtLink RouterClass = Switch InterfaceClass = None # Instantiate the network object # so that the controllers can connect to it. network = NetworkClass(ruby_system=ruby, topology=options.topology, routers=[], ext_links=[], int_links=[], netifs=[]) return (network, IntLinkClass, ExtLinkClass, RouterClass, InterfaceClass)
def fromSeconds(value): if not isinstance(value, float): raise TypeError, "can't convert '%s' to type tick" % type(value) # once someone needs to convert to seconds, the global frequency # had better be fixed if not tps_fixed: raise AttributeError, \ "In order to do conversions, the global frequency must be fixed" if value == 0: return 0 # convert the value from time to ticks value *= tps int_value = int(round(value)) err = (value - int_value) / value if "GEM5SIMTYPE" in environ: if environ["GEM5SIMTYPE"] == "GarnetStandalone": # Hide warn message for GarnetStandalone return int_value if err > frequency_tolerance: warn("rounding error > tolerance\n %f rounded to %d", value, int_value) return int_value
def _do_dot(network, outdir, dotFilename): callgraph = pydot.Dot(graph_type='graph', rankdir='LR') _dot_create(network, callgraph) dot_filename = os.path.join(outdir, dotFilename) callgraph.write(dot_filename) try: # dot crashes if the figure is extremely wide. # So avoid terminating simulation unnecessarily callgraph.write_svg(dot_filename + ".svg", prog='neato') callgraph.write_pdf(dot_filename + ".pdf", prog='neato') except: warn("failed to generate dot output from %s", dot_filename)
def do_dot(root, outdir, dotFilename): if not pydot: return callgraph = pydot.Dot(graph_type='digraph') dot_create_nodes(root, callgraph) dot_create_edges(root, callgraph) dot_filename = os.path.join(outdir, dotFilename) callgraph.write(dot_filename) try: # dot crashes if the figure is extremely wide. # So avoid terminating simulation unnecessarily callgraph.write_pdf(dot_filename + ".pdf") except: warn("failed to generate pdf output from %s", dot_filename)
def incorporate_processor(self, board: AbstractBoard) -> None: if self._cpu_type == CPUTypes.KVM: board.kvm_vm = self.kvm_vm # Set the memory mode. if self._cpu_type == CPUTypes.TIMING or self._cpu_type == CPUTypes.O3: board.set_mem_mode(MemMode.TIMING) elif self._cpu_type == CPUTypes.KVM: board.set_mem_mode(MemMode.ATOMIC_NONCACHING) elif self._cpu_type == CPUTypes.ATOMIC: if is_ruby(get_runtime_coherence_protocol()): warn("Using an atomic core with Ruby will result in " "'atomic_noncaching' memory mode. This will skip caching " "completely.") else: board.set_mem_mode(MemMode.ATOMIC) else: raise NotImplementedError
def do_dot(root, outdir, dotFilename): if not pydot: return # * use ranksep > 1.0 for for vertical separation between nodes # especially useful if you need to annotate edges using e.g. visio # which accepts svg format # * no need for hoizontal separation as nothing moves horizonally callgraph = pydot.Dot(graph_type='digraph', ranksep='1.3') dot_create_nodes(root, callgraph) dot_create_edges(root, callgraph) dot_filename = os.path.join(outdir, dotFilename) callgraph.write(dot_filename) try: # dot crashes if the figure is extremely wide. # So avoid terminating simulation unnecessarily callgraph.write_svg(dot_filename + ".svg") callgraph.write_pdf(dot_filename + ".pdf") except: warn("failed to generate dot output from %s", dot_filename)
def do_dvfs_dot(root, outdir, dotFilename): if not pydot: warn("No dot file generated. " + "Please install pydot to generate the dot file and pdf.") return # There is a chance that we are unable to resolve the clock or # voltage domains. If so, we fail silently. try: dvfsgraph = pydot.Dot(graph_type='digraph', ranksep='1.3') dot_create_dvfs_nodes(root, dvfsgraph) dot_create_edges(root, dvfsgraph) dot_filename = os.path.join(outdir, dotFilename) dvfsgraph.write(dot_filename) except: warn("Failed to generate dot graph for DVFS domains") return try: # dot crashes if the figure is extremely wide. # So avoid terminating simulation unnecessarily dvfsgraph.write_svg(dot_filename + ".svg") dvfsgraph.write_pdf(dot_filename + ".pdf") except: warn("failed to generate dot output from %s", dot_filename)
def fromSeconds(value): if not isinstance(value, float): raise TypeError, "can't convert '%s' to type tick" % type(value) # once someone needs to convert to seconds, the global frequency # had better be fixed if not tps_fixed: raise AttributeError, \ "In order to do conversions, the global frequency must be fixed" if value == 0: return 0 # convert the value from time to ticks value *= tps int_value = int(round(value)) err = (value - int_value) / value if err > frequency_tolerance: warn("rounding error > tolerance\n %f rounded to %d", value, int_value) return int_value
def do_dvfs_dot(root, outdir, dotFilename): if not pydot: return # There is a chance that we are unable to resolve the clock or # voltage domains. If so, we fail silently. try: dvfsgraph = pydot.Dot(graph_type='digraph', ranksep='1.3') dot_create_dvfs_nodes(root, dvfsgraph) dot_create_edges(root, dvfsgraph) dot_filename = os.path.join(outdir, dotFilename) dvfsgraph.write(dot_filename) except: warn("Failed to generate dot graph for DVFS domains") return try: # dot crashes if the figure is extremely wide. # So avoid terminating simulation unnecessarily dvfsgraph.write_svg(dot_filename + ".svg") dvfsgraph.write_pdf(dot_filename + ".pdf") except: warn("failed to generate dot output from %s", dot_filename)
options.ethernet_linkspeed, options.ethernet_linkdelay, options.etherdump); elif len(bm) == 1: root = Root(full_system=True, system=test_sys) else: print("Error I don't know how to create more than 2 systems.") sys.exit(1) if options.timesync: root.time_sync_enable = True if options.frame_capture: VncServer.frame_capture = True if buildEnv['TARGET_ISA'] == "arm" and not options.bare_metal \ and not options.dtb_filename: if options.machine_type not in ["VExpress_GEM5", "VExpress_GEM5_V1"]: warn("Can only correctly generate a dtb for VExpress_GEM5_V1 " \ "platforms, unless custom hardware models have been equipped "\ "with generation functionality.") # Generate a Device Tree for sysname in ('system', 'testsys', 'drivesys'): if hasattr(root, sysname): sys = getattr(root, sysname) sys.generateDtb(m5.options.outdir, '%s.dtb' % sysname) Simulation.setWorkCountOptions(test_sys, options) Simulation.run(options, root, test_sys, FutureClass)
root.sim_quantum = int(1e9) # 1 ms if args.timesync: root.time_sync_enable = True if args.frame_capture: VncServer.frame_capture = True if buildEnv['TARGET_ISA'] == "arm" and not args.bare_metal \ and not args.dtb_filename: if args.machine_type not in [ "VExpress_GEM5", "VExpress_GEM5_V1", "VExpress_GEM5_V2", "VExpress_GEM5_Foundation" ]: warn("Can only correctly generate a dtb for VExpress_GEM5_* " \ "platforms, unless custom hardware models have been equipped "\ "with generation functionality.") # Generate a Device Tree for sysname in ('system', 'testsys', 'drivesys'): if hasattr(root, sysname): sys = getattr(root, sysname) sys.workload.dtb_filename = \ os.path.join(m5.options.outdir, '%s.dtb' % sysname) sys.generateDtb(sys.workload.dtb_filename) if args.wait_gdb: test_sys.workload.wait_for_remote_gdb = True Simulation.setWorkCountOptions(test_sys, args) Simulation.run(args, root, test_sys, FutureClass)
type=str, required=True, help="Sumulation size the benchmark program.", choices=size_choices, ) args = parser.parse_args() # We expect the user to input the full path of the disk-image. if args.image[0] != "/": # We need to get the absolute path to this file. We assume that the file is # present on the current working directory. args.image = os.path.abspath(args.image) if not os.path.exists(args.image): warn("Disk image not found!") print("Instructions on building the disk image can be found at: ") print( "https://gem5art.readthedocs.io/en/latest/tutorials/spec-tutorial.html" ) fatal("The disk-image is not found at {}".format(args.image)) # Setting up all the fixed system parameters here # Caches: MESI Two Level Cache Hierarchy from gem5.components.cachehierarchies.ruby.\ mesi_two_level_cache_hierarchy import( MESITwoLevelCacheHierarchy, ) cache_hierarchy = MESITwoLevelCacheHierarchy(
def __init__( self, board: AbstractBoard, full_system: bool = True, on_exit_event: Optional[Dict[Union[str, ExitEvent], Generator[Optional[bool], None, None]]] = None, expected_execution_order: Optional[List[ExitEvent]] = None, ) -> None: """ :param board: The board to be simulated. :param full_system: Whether to run in full-system simulation or not. If False, the simulation will run in Syscall-Execution mode. True by default. :param on_exit_event: An optional map to specify the generator to execute on each exit event. The generator may yield a boolean which, if True, will have the Simulator exit the run loop. :param expected_execution_order: May be specified to check the exit events come in a specified order. If the order specified is not encountered (e.g., 'Workbegin', 'Workend', then 'Exit'), an Exception is thrown. If this parameter is not specified, any ordering of exit events is valid. `on_exit_event` usage notes --------------------------- The `on_exit_event` parameter specifies a Python generator for each exit event. `next(<generator>)` is run each time an exit event. The generator may yield a boolean. If this value of this boolean is True the Simulator run loop will exit, otherwise the Simulator run loop will continue execution. If the generator has finished (i.e. a `StopIteration` exception is thrown when `next(<generator>)` is executed), then the default behavior for that exit event is run. As an example, a user may specify their own exit event setup like so: ``` def unique_exit_event(): processor.switch() yield False m5.stats.dump() yield False yield True simulator = Simulator( board=board on_exit_event = { ExitEvent.Exit : unique_exit_event(), }, ) ``` This will execute `processor.switch()` the first time an exit event is encountered, will dump gem5 statistics the second time an exit event is encountered, and will terminate the Simulator run loop the third time. Each exit event has a default behavior if none is specified by the user. These are as follows: * ExitEvent.EXIT: default_exit_list * ExitEvent.CHECKPOINT: default_exit_list * ExitEvent.FAIL : default_exit_list * ExitEvent.SWITCHCPU: default_switch_list * ExitEvent.WORKBEGIN: default_workbegin_list * ExitEvent.WORKEND: default_workend_list * ExitEvent.USER_INTERRUPT: default_exit_generator * ExitEvent.MAX_TICK: default_exit_generator() These generators can be found in the `exit_event_generator.py` module. """ warn("The simulate package is still in a beta state. The gem5 " "project does not guarantee the APIs within this package will " "remain consistent across upcoming releases.") # We specify a dictionary here outlining the default behavior for each # exit event. Each exit event is mapped to a generator. self._default_on_exit_dict = { ExitEvent.EXIT: default_exit_generator(), # TODO: Something else should be done here for CHECKPOINT ExitEvent.CHECKPOINT: default_exit_generator(), ExitEvent.FAIL: default_exit_generator(), ExitEvent.SWITCHCPU: default_switch_generator(processor=board.get_processor()), ExitEvent.WORKBEGIN: default_workbegin_generator(), ExitEvent.WORKEND: default_workend_generator(), ExitEvent.USER_INTERRUPT: default_exit_generator(), ExitEvent.MAX_TICK: default_exit_generator(), } if on_exit_event: self._on_exit_event = on_exit_event else: self._on_exit_event = self._default_on_exit_dict self._instantiated = False self._board = board self._full_system = full_system self._expected_execution_order = expected_execution_order self._tick_stopwatch = [] self._last_exit_event = None self._exit_event_count = 0
parser.add_argument( "--ticks", type = int, help = "Optionally put the maximum number of ticks to execute during the "\ "ROI. It accepts an integer value." ) args = parser.parse_args() # The simulation may fail in the case of `mg` with class C as it uses 3.3 GB # of memory (more information is availabe at https://arxiv.org/abs/2010.13216). # We warn the user here. if args.benchmark == "mg" and args.size == "C": warn("mg.C uses 3.3 GB of memory. Currently we are simulating 3 GB\ of main memory in the system.") # The simulation will fail in the case of `ft` with class C. We warn the user # here. elif args.benchmark == "ft" and args.size == "C": warn("There is not enough memory for ft.C. Currently we are\ simulating 3 GB of main memory in the system.") # Checking for the maximum number of instructions, if provided by the user. # Setting up all the fixed system parameters here # Caches: MESI Two Level Cache Hierarchy from gem5.components.cachehierarchies.ruby.\ mesi_two_level_cache_hierarchy import( MESITwoLevelCacheHierarchy,
def build_test_system(np): cmdline = cmd_line_template() if buildEnv['TARGET_ISA'] == "alpha": test_sys = makeLinuxAlphaSystem(test_mem_mode, bm[0], options.ruby, cmdline=cmdline) elif buildEnv['TARGET_ISA'] == "mips": test_sys = makeLinuxMipsSystem(test_mem_mode, bm[0], cmdline=cmdline) elif buildEnv['TARGET_ISA'] == "sparc": test_sys = makeSparcSystem(test_mem_mode, bm[0], cmdline=cmdline) elif buildEnv['TARGET_ISA'] == "x86": test_sys = makeLinuxX86System(test_mem_mode, options.num_cpus, bm[0], options.ruby, cmdline=cmdline) elif buildEnv['TARGET_ISA'] == "arm": test_sys = makeArmSystem( test_mem_mode, options.machine_type, options.membus_width, options, options.num_cpus, bm[0], options.dtb_filename, bare_metal=options.bare_metal, cmdline=cmdline, ignore_dtb=options.generate_dtb, external_memory=options.external_memory_system, ruby=options.ruby, security=options.enable_security_extensions) if options.enable_context_switch_stats_dump: test_sys.enable_context_switch_stats_dump = True else: fatal("Incapable of building %s full system!", buildEnv['TARGET_ISA']) # Set the cache line size for the entire system test_sys.cache_line_size = options.cacheline_size # Create a top-level voltage domain test_sys.voltage_domain = VoltageDomain(voltage=options.sys_voltage) # Create a source clock for the system and set the clock period test_sys.clk_domain = SrcClockDomain( clock=options.sys_clock, voltage_domain=test_sys.voltage_domain) # Create a CPU voltage domain test_sys.cpu_voltage_domain = VoltageDomain() # Create a source clock for the CPUs and set the clock period test_sys.cpu_clk_domain = SrcClockDomain( clock=options.cpu_clock, voltage_domain=test_sys.cpu_voltage_domain) if options.kernel is not None: test_sys.kernel = binary(options.kernel) if options.script is not None: test_sys.readfile = options.script if options.lpae: test_sys.have_lpae = True if options.virtualisation: test_sys.have_virtualization = True test_sys.init_param = options.init_param # For now, assign all the CPUs to the same clock domain test_sys.cpu = [ TestCPUClass(clk_domain=test_sys.cpu_clk_domain, cpu_id=i) for i in xrange(np) ] if is_kvm_cpu(TestCPUClass) or is_kvm_cpu(FutureClass): test_sys.kvm_vm = KvmVM() if options.ruby: bootmem = getattr(test_sys, 'bootmem', None) Ruby.create_system(options, True, test_sys, test_sys.iobus, test_sys._dma_ports, bootmem) # Create a seperate clock domain for Ruby test_sys.ruby.clk_domain = SrcClockDomain( clock=options.ruby_clock, voltage_domain=test_sys.voltage_domain) # Connect the ruby io port to the PIO bus, # assuming that there is just one such port. test_sys.iobus.master = test_sys.ruby._io_port.slave for (i, cpu) in enumerate(test_sys.cpu): # # Tie the cpu ports to the correct ruby system ports # cpu.clk_domain = test_sys.cpu_clk_domain cpu.createThreads() cpu.createInterruptController() cpu.icache_port = test_sys.ruby._cpu_ports[i].slave cpu.dcache_port = test_sys.ruby._cpu_ports[i].slave if buildEnv['TARGET_ISA'] in ("x86", "arm"): cpu.itb.walker.port = test_sys.ruby._cpu_ports[i].slave cpu.dtb.walker.port = test_sys.ruby._cpu_ports[i].slave if buildEnv['TARGET_ISA'] in "x86": cpu.interrupts[0].pio = test_sys.ruby._cpu_ports[i].master cpu.interrupts[0].int_master = test_sys.ruby._cpu_ports[ i].slave cpu.interrupts[0].int_slave = test_sys.ruby._cpu_ports[ i].master else: if options.caches or options.l2cache: # By default the IOCache runs at the system clock test_sys.iocache = IOCache(addr_ranges=test_sys.mem_ranges) test_sys.iocache.cpu_side = test_sys.iobus.master test_sys.iocache.mem_side = test_sys.membus.slave elif not options.external_memory_system: test_sys.iobridge = Bridge(delay='50ns', ranges=test_sys.mem_ranges) test_sys.iobridge.slave = test_sys.iobus.master test_sys.iobridge.master = test_sys.membus.slave # Sanity check if options.fastmem: if TestCPUClass != AtomicSimpleCPU: fatal("Fastmem can only be used with atomic CPU!") if (options.caches or options.l2cache): fatal("You cannot use fastmem in combination with caches!") if options.simpoint_profile: if not options.fastmem: # Atomic CPU checked with fastmem option already fatal( "SimPoint generation should be done with atomic cpu and fastmem" ) if np > 1: fatal( "SimPoint generation not supported with more than one CPUs" ) for i in xrange(np): if options.fastmem: test_sys.cpu[i].fastmem = True if options.simpoint_profile: test_sys.cpu[i].addSimPointProbe(options.simpoint_interval) if options.checker: test_sys.cpu[i].addCheckerCpu() test_sys.cpu[i].createThreads() # If elastic tracing is enabled when not restoring from checkpoint and # when not fast forwarding using the atomic cpu, then check that the # TestCPUClass is DerivO3CPU or inherits from DerivO3CPU. If the check # passes then attach the elastic trace probe. # If restoring from checkpoint or fast forwarding, the code that does this for # FutureCPUClass is in the Simulation module. If the check passes then the # elastic trace probe is attached to the switch CPUs. if options.elastic_trace_en and options.checkpoint_restore == None and \ not options.fast_forward: CpuConfig.config_etrace(TestCPUClass, test_sys.cpu, options) if buildEnv['TARGET_ISA'] != "arm" and options.workload_automation_vio: warn("Ignoring --workload-automation-vio. It is unsupported on " "non-ARM systems.") elif options.workload_automation_vio: from m5.objects import PciVirtIO, VirtIO9PDiod viopci = PciVirtIO( pci_bus=0, pci_dev=test_sys.realview._num_pci_dev, pci_func=0, InterruptPin=1, InterruptLine=test_sys.realview._num_pci_int_line) test_sys.realview._num_pci_dev = test_sys.realview._num_pci_dev + 1 test_sys.realview._num_pci_int_line = test_sys.realview._num_pci_int_line + 1 viopci.vio = VirtIO9PDiod() viopci.vio.root = options.workload_automation_vio viopci.vio.socketPath = "/home/yqureshi/shares/local/scrap/temp" test_sys.realview.viopci = viopci test_sys.realview.viopci.dma = test_sys.iobus.slave test_sys.realview.viopci.pio = test_sys.iobus.master CacheConfig.config_cache(options, test_sys) MemConfig.config_mem(options, test_sys) return test_sys