| # Copyright (c) 2020 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. |
| # |
| # Copyright (c) 2017 Mark D. Hill and David A. Wood |
| # All rights reserved. |
| # |
| # 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. |
| |
| import os |
| import copy |
| import subprocess |
| import sys |
| |
| from testlib.test_util import TestFunction |
| from testlib.suite import TestSuite |
| from testlib.helper import log_call |
| from testlib.configuration import constants, config |
| from .fixture import TempdirFixture, Gem5Fixture, VariableFixture |
| |
| from . import verifier |
| |
| def gem5_verify_config(name, |
| config, |
| config_args, |
| verifiers, |
| gem5_args=tuple(), |
| fixtures=[], |
| valid_isas=constants.supported_isas, |
| valid_variants=constants.supported_variants, |
| length=constants.supported_lengths[0], |
| valid_hosts=constants.supported_hosts, |
| protocol=None): |
| ''' |
| Helper class to generate common gem5 tests using verifiers. |
| |
| The generated TestSuite will run gem5 with the provided config and |
| config_args. After that it will run any provided verifiers to verify |
| details about the gem5 run. |
| |
| .. seealso:: For the verifiers see :mod:`testlib.gem5.verifier` |
| |
| :param name: Name of the test. |
| :param config: The config to give gem5. |
| :param config_args: A list of arguments to pass to the given config. |
| |
| :param verifiers: An iterable with Verifier instances which will be placed |
| into a suite that will be ran after a gem5 run. |
| |
| :param gem5_args: An iterable with arguments to give to gem5. (Arguments |
| that would normally go before the config path.) |
| |
| :param valid_isas: An iterable with the isas that this test can be ran |
| for. If None given, will run for all supported_isas. |
| |
| :param valid_variants: An iterable with the variant levels that |
| this test can be ran for. (E.g. opt, debug) |
| ''' |
| fixtures = list(fixtures) |
| testsuites = [] |
| |
| for host in valid_hosts: |
| for opt in valid_variants: |
| for isa in valid_isas: |
| |
| # Create a tempdir fixture to be shared throughout the test. |
| tempdir = TempdirFixture() |
| gem5_returncode = VariableFixture( |
| name=constants.gem5_returncode_fixture_name) |
| |
| # Common name of this generated testcase. |
| _name = '{given_name}-{isa}-{host}-{opt}'.format( |
| given_name=name, |
| isa=isa, |
| host=host, |
| opt=opt) |
| if protocol: |
| _name += '-'+protocol |
| |
| # Create the running of gem5 subtest. NOTE: We specifically |
| # create this test before our verifiers so this is listed |
| # first. |
| tests = [] |
| gem5_execution = TestFunction( |
| _create_test_run_gem5(config, config_args, gem5_args), |
| name=_name) |
| tests.append(gem5_execution) |
| |
| # Create copies of the verifier subtests for this isa and |
| # variant. |
| for verifier in verifiers: |
| tests.append(verifier.instantiate_test(_name)) |
| |
| # Add the isa and variant to tags list. |
| tags = [isa, opt, length, host] |
| |
| # Create the gem5 target for the specific architecture and |
| # variant. |
| _fixtures = copy.copy(fixtures) |
| _fixtures.append(Gem5Fixture(isa, opt, protocol)) |
| _fixtures.append(tempdir) |
| _fixtures.append(gem5_returncode) |
| |
| # Finally construct the self contained TestSuite out of our |
| # tests. |
| testsuites.append(TestSuite( |
| name=_name, |
| fixtures=_fixtures, |
| tags=tags, |
| tests=tests)) |
| return testsuites |
| |
| def _create_test_run_gem5(config, config_args, gem5_args): |
| def test_run_gem5(params): |
| ''' |
| Simple \'test\' which runs gem5 and saves the result into a tempdir. |
| |
| NOTE: Requires fixtures: tempdir, gem5 |
| ''' |
| fixtures = params.fixtures |
| |
| if gem5_args is None: |
| _gem5_args = tuple() |
| elif isinstance(gem5_args, str): |
| # If just a single str, place it in an iterable |
| _gem5_args = (gem5_args,) |
| else: |
| _gem5_args = gem5_args |
| |
| # FIXME/TODO: I don't like the idea of having to modify this test run |
| # or always collect results even if not using a verifier. There should |
| # be some configuration in here that only gathers certain results for |
| # certain verifiers. |
| # |
| # I.E. Only the returncode verifier will use the gem5_returncode |
| # fixture, but we always require it even if that verifier isn't being |
| # ran. |
| tempdir = fixtures[constants.tempdir_fixture_name].path |
| gem5 = fixtures[constants.gem5_binary_fixture_name].path |
| command = [ |
| gem5, |
| '-d', # Set redirect dir to tempdir. |
| tempdir, |
| '-re', # TODO: Change to const. Redirect stdout and stderr |
| '--silent-redirect', |
| ] |
| command.extend(_gem5_args) |
| command.append(config) |
| # Config_args should set up the program args. |
| command.extend(config_args) |
| log_call(params.log, command, time=params.time, |
| stdout=sys.stdout, stderr=sys.stderr) |
| |
| return test_run_gem5 |