| # Copyright (c) 2012 ARM Limited | |
| # All rights reserved. | |
| # | |
| # The license below extends only to copyright in the software and shall | |
| # not be construed as granting a license to any other intellectual | |
| # property including but not limited to intellectual property relating | |
| # to a hardware implementation of the functionality of the software | |
| # licensed hereunder. You may use the software subject to the license | |
| # terms below provided that you ensure that this notice is replicated | |
| # unmodified and in its entirety in all distributions of the software, | |
| # modified or unmodified, in source code or in binary form. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions are | |
| # met: redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer; | |
| # redistributions in binary form must reproduce the above copyright | |
| # notice, this list of conditions and the following disclaimer in the | |
| # documentation and/or other materials provided with the distribution; | |
| # neither the name of the copyright holders nor the names of its | |
| # contributors may be used to endorse or promote products derived from | |
| # this software without specific prior written permission. | |
| # | |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| # | |
| # Authors: Andreas Sandberg | |
| import m5 | |
| from m5.objects import * | |
| m5.util.addToPath('../configs/common') | |
| from Caches import * | |
| class Sequential: | |
| """Sequential CPU switcher. | |
| The sequential CPU switches between all CPUs in a system in | |
| order. The CPUs in the system must have been prepared for | |
| switching, which in practice means that only one CPU is switched | |
| in. base_config.BaseFSSwitcheroo can be used to create such a | |
| system. | |
| """ | |
| def __init__(self, cpus): | |
| self.first_cpu = None | |
| for (cpuno, cpu) in enumerate(cpus): | |
| if not cpu.switched_out: | |
| if self.first_cpu != None: | |
| fatal("More than one CPU is switched in"); | |
| self.first_cpu = cpuno | |
| if self.first_cpu == None: | |
| fatal("The system contains no switched in CPUs") | |
| self.cur_cpu = self.first_cpu | |
| self.cpus = cpus | |
| def next(self): | |
| self.cur_cpu = (self.cur_cpu + 1) % len(self.cpus) | |
| return self.cpus[self.cur_cpu] | |
| def first(self): | |
| return self.cpus[self.first_cpu] | |
| def run_test(root, switcher=None, freq=1000, verbose=False): | |
| """Test runner for CPU switcheroo tests. | |
| The switcheroo test runner is used to switch CPUs in a system that | |
| has been prepared for CPU switching. Such systems should have | |
| multiple CPUs when they are instantiated, but only one should be | |
| switched in. Such configurations can be created using the | |
| base_config.BaseFSSwitcheroo class. | |
| A CPU switcher object is used to control switching. The default | |
| switcher sequentially switches between all CPUs in a system, | |
| starting with the CPU that is currently switched in. | |
| Unlike most other test runners, this one automatically configures | |
| the memory mode of the system based on the first CPU the switcher | |
| reports. | |
| Keyword Arguments: | |
| switcher -- CPU switcher implementation. See Sequential for | |
| an example implementation. | |
| period -- Switching frequency in Hz. | |
| verbose -- Enable output at each switch (suppressed by default). | |
| """ | |
| if switcher == None: | |
| switcher = Sequential(root.system.cpu) | |
| current_cpu = switcher.first() | |
| system = root.system | |
| system.mem_mode = type(current_cpu).memory_mode() | |
| # Suppress "Entering event queue" messages since we get tons of them. | |
| # Worse yet, they include the timestamp, which makes them highly | |
| # variable and unsuitable for comparing as test outputs. | |
| m5.internal.core.cvar.want_info = verbose | |
| # instantiate configuration | |
| m5.instantiate() | |
| # Determine the switching period, this has to be done after | |
| # instantiating the system since the time base must be fixed. | |
| period = m5.ticks.fromSeconds(1.0 / freq) | |
| while True: | |
| exit_event = m5.simulate(period) | |
| exit_cause = exit_event.getCause() | |
| if exit_cause == "simulate() limit reached": | |
| next_cpu = switcher.next() | |
| if verbose: | |
| print "Switching CPUs..." | |
| print "Next CPU: %s" % type(next_cpu) | |
| m5.drain(system) | |
| if current_cpu != next_cpu: | |
| m5.switchCpus(system, [ (current_cpu, next_cpu) ], | |
| do_drain=False, verbose=verbose) | |
| else: | |
| print "Source CPU and destination CPU are the same, skipping..." | |
| m5.resume(system) | |
| current_cpu = next_cpu | |
| elif exit_cause == "target called exit()" or \ | |
| exit_cause == "m5_exit instruction encountered": | |
| sys.exit(0) | |
| else: | |
| print "Test failed: Unknown exit cause: %s" % exit_cause | |
| sys.exit(1) |