tests.py revision 11542:ecd058e3dcbe
12330SN/A#!/usr/bin/env python
22330SN/A#
32330SN/A# Copyright (c) 2016 ARM Limited
42330SN/A# All rights reserved
52330SN/A#
62330SN/A# The license below extends only to copyright in the software and shall
72330SN/A# not be construed as granting a license to any other intellectual
82330SN/A# property including but not limited to intellectual property relating
92330SN/A# to a hardware implementation of the functionality of the software
102330SN/A# licensed hereunder.  You may use the software subject to the license
112330SN/A# terms below provided that you ensure that this notice is replicated
122330SN/A# unmodified and in its entirety in all distributions of the software,
132330SN/A# modified or unmodified, in source code or in binary form.
142330SN/A#
152330SN/A# Redistribution and use in source and binary forms, with or without
162330SN/A# modification, are permitted provided that the following conditions are
172330SN/A# met: redistributions of source code must retain the above copyright
182330SN/A# notice, this list of conditions and the following disclaimer;
192330SN/A# redistributions in binary form must reproduce the above copyright
202330SN/A# notice, this list of conditions and the following disclaimer in the
212330SN/A# documentation and/or other materials provided with the distribution;
222330SN/A# neither the name of the copyright holders nor the names of its
232330SN/A# contributors may be used to endorse or promote products derived from
242330SN/A# this software without specific prior written permission.
252330SN/A#
262330SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
272689Sktlim@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
282689Sktlim@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
292330SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
302292SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
312292SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
322292SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
332292SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
342980Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
352362SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
362680Sktlim@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
372292SN/A#
382678Sktlim@umich.edu# Authors: Andreas Sandberg
392683Sktlim@umich.edu
402683Sktlim@umich.edufrom abc import ABCMeta, abstractmethod
412678Sktlim@umich.eduimport os
422678Sktlim@umich.edufrom collections import namedtuple
432292SN/Afrom units import *
442292SN/Afrom results import TestResult
452292SN/Aimport shutil
462292SN/A
473548Sgblack@eecs.umich.edu_test_base = os.path.join(os.path.dirname(__file__), "..")
483548Sgblack@eecs.umich.edu
493548Sgblack@eecs.umich.eduClassicConfig = namedtuple("ClassicConfig", (
503548Sgblack@eecs.umich.edu    "category",
512330SN/A    "mode",
522292SN/A    "workload",
532292SN/A    "isa",
543402Sktlim@umich.edu    "os",
552862Sktlim@umich.edu    "config",
563486Sktlim@umich.edu))
573402Sktlim@umich.edu
582862Sktlim@umich.edu# There are currently two "classes" of test
592330SN/A# configurations. Architecture-specific ones and generic ones
602330SN/A# (typically SE mode tests). In both cases, the configuration name
612330SN/A# matches a file in tests/configs/ that will be picked up by the test
622330SN/A# runner (run.py).
632330SN/A#
642330SN/A# Architecture specific configurations are listed in the arch_configs
652292SN/A# dictionary. This is indexed by a (cpu architecture, gpu
662683Sktlim@umich.edu# architecture) tuple. GPU architecture is optional and may be None.
672683Sktlim@umich.edu#
682292SN/A# Generic configurations are listed in the generic_configs tuple.
693402Sktlim@umich.edu#
702292SN/A# When discovering available test cases, this script look uses the
713402Sktlim@umich.edu# test list as a list of /candidate/ configurations. A configuration
723402Sktlim@umich.edu# is only used if a test has a reference output for that
732292SN/A# configuration. In addition to the base configurations from
742683Sktlim@umich.edu# arch_configs and generic_configs, a Ruby configuration may be
753486Sktlim@umich.edu# appended to the base name (this is probed /in addition/ to the
763486Sktlim@umich.edu# original name. See get_tests() for details.
772862Sktlim@umich.edu#
782862Sktlim@umich.eduarch_configs = {
792862Sktlim@umich.edu    ("alpha", None) : (
802862Sktlim@umich.edu        'tsunami-simple-atomic',
812683Sktlim@umich.edu        'tsunami-simple-timing',
822683Sktlim@umich.edu        'tsunami-simple-atomic-dual',
832683Sktlim@umich.edu        'tsunami-simple-timing-dual',
842683Sktlim@umich.edu        'twosys-tsunami-simple-atomic',
852683Sktlim@umich.edu        'tsunami-o3', 'tsunami-o3-dual',
862683Sktlim@umich.edu        'tsunami-minor', 'tsunami-minor-dual',
872683Sktlim@umich.edu        'tsunami-switcheroo-full',
882683Sktlim@umich.edu    ),
892683Sktlim@umich.edu
902683Sktlim@umich.edu    ("arm", None) : (
912683Sktlim@umich.edu        'simple-atomic-dummychecker',
922683Sktlim@umich.edu        'o3-timing-checker',
932683Sktlim@umich.edu        'realview-simple-atomic',
943686Sktlim@umich.edu        'realview-simple-atomic-dual',
953675Sktlim@umich.edu        'realview-simple-atomic-checkpoint',
963686Sktlim@umich.edu        'realview-simple-timing',
973675Sktlim@umich.edu        'realview-simple-timing-dual',
983686Sktlim@umich.edu        'realview-o3',
993675Sktlim@umich.edu        'realview-o3-checker',
1002683Sktlim@umich.edu        'realview-o3-dual',
1012683Sktlim@umich.edu        'realview-minor',
1022683Sktlim@umich.edu        'realview-minor-dual',
1032683Sktlim@umich.edu        'realview-switcheroo-atomic',
1042683Sktlim@umich.edu        'realview-switcheroo-timing',
1052683Sktlim@umich.edu        'realview-switcheroo-o3',
1062683Sktlim@umich.edu        'realview-switcheroo-full',
1072683Sktlim@umich.edu        'realview64-simple-atomic',
1083548Sgblack@eecs.umich.edu        'realview64-simple-atomic-checkpoint',
1092683Sktlim@umich.edu        'realview64-simple-atomic-dual',
1102690Sktlim@umich.edu        'realview64-simple-timing',
1112690Sktlim@umich.edu        'realview64-simple-timing-dual',
1122683Sktlim@umich.edu        'realview64-o3',
1132683Sktlim@umich.edu        'realview64-o3-checker',
1142690Sktlim@umich.edu        'realview64-o3-dual',
1152690Sktlim@umich.edu        'realview64-minor',
1162683Sktlim@umich.edu        'realview64-minor-dual',
1172683Sktlim@umich.edu        'realview64-switcheroo-atomic',
1182683Sktlim@umich.edu        'realview64-switcheroo-timing',
1192683Sktlim@umich.edu        'realview64-switcheroo-o3',
1203402Sktlim@umich.edu        'realview64-switcheroo-full',
1212683Sktlim@umich.edu    ),
1222683Sktlim@umich.edu
1232683Sktlim@umich.edu    ("sparc", None) : (
1242683Sktlim@umich.edu        't1000-simple-atomic',
1252683Sktlim@umich.edu        't1000-simple-x86',
1262678Sktlim@umich.edu    ),
1272292SN/A
1282683Sktlim@umich.edu    ("timing", None) : (
1292683Sktlim@umich.edu        'pc-simple-atomic',
1302292SN/A        'pc-simple-timing',
1312683Sktlim@umich.edu        'pc-o3-timing',
1322683Sktlim@umich.edu        'pc-switcheroo-full',
1332683Sktlim@umich.edu    ),
1342683Sktlim@umich.edu
1352683Sktlim@umich.edu    ("x86", "hsail") : (
1362683Sktlim@umich.edu        'gpu',
1372683Sktlim@umich.edu    ),
1382683Sktlim@umich.edu}
1392683Sktlim@umich.edu
1402683Sktlim@umich.edugeneric_configs = (
1412683Sktlim@umich.edu    'simple-atomic',
1422683Sktlim@umich.edu    'simple-atomic-mp',
1432683Sktlim@umich.edu    'simple-timing',
1442683Sktlim@umich.edu    'simple-timing-mp',
1452683Sktlim@umich.edu
1462683Sktlim@umich.edu    'minor-timing',
1472683Sktlim@umich.edu    'minor-timing-mp',
1482683Sktlim@umich.edu
1492683Sktlim@umich.edu    'o3-timing',
1503673Srdreslin@umich.edu    'o3-timing-mt',
1513675Sktlim@umich.edu    'o3-timing-mp',
1523675Sktlim@umich.edu
1533675Sktlim@umich.edu    'rubytest',
1543486Sktlim@umich.edu    'memcheck',
1552683Sktlim@umich.edu    'memtest',
1562683Sktlim@umich.edu    'memtest-filter',
1572683Sktlim@umich.edu    'tgen-simple-mem',
1582683Sktlim@umich.edu    'tgen-dram-ctrl',
1592683Sktlim@umich.edu
1602683Sktlim@umich.edu    'learning-gem5-p1-simple',
1612683Sktlim@umich.edu    'learning-gem5-p1-two-level',
1622683Sktlim@umich.edu)
1632683Sktlim@umich.edu
1642683Sktlim@umich.eduall_categories = ("quick", "long")
1652683Sktlim@umich.eduall_modes = ("fs", "se")
1662683Sktlim@umich.edu
1672683Sktlim@umich.educlass Test(object):
1682683Sktlim@umich.edu    """Test case base class.
1692683Sktlim@umich.edu
1702683Sktlim@umich.edu    Test cases consists of one or more test units that are run in two
1712683Sktlim@umich.edu    phases. A run phase (units produced by run_units() and a verify
1722683Sktlim@umich.edu    phase (units from verify_units()). The verify phase is skipped if
1733402Sktlim@umich.edu    the run phase fails.
1743402Sktlim@umich.edu
1753402Sktlim@umich.edu    """
1762683Sktlim@umich.edu
1772683Sktlim@umich.edu    __metaclass__ = ABCMeta
1782292SN/A
1792292SN/A    def __init__(self, name):
1802292SN/A        self.test_name = name
1812292SN/A
1822292SN/A    @abstractmethod
1832690Sktlim@umich.edu    def ref_files(self):
1842683Sktlim@umich.edu        """Get a list of reference files used by this test case"""
1852683Sktlim@umich.edu        pass
1862292SN/A
1872683Sktlim@umich.edu    @abstractmethod
1882683Sktlim@umich.edu    def run_units(self):
1892292SN/A        """Units (typically RunGem5 instances) that describe the run phase of
1902292SN/A        this test.
1912683Sktlim@umich.edu
1922292SN/A        """
1932292SN/A        pass
1942292SN/A
1952292SN/A    @abstractmethod
1962292SN/A    def verify_units(self):
1973548Sgblack@eecs.umich.edu        """Verify the output from the run phase (see run_units())."""
1982683Sktlim@umich.edu        pass
1992683Sktlim@umich.edu
2002683Sktlim@umich.edu    @abstractmethod
2012683Sktlim@umich.edu    def update_ref(self):
2022683Sktlim@umich.edu        """Update reference files with files from a test run"""
2032683Sktlim@umich.edu        pass
2042683Sktlim@umich.edu
2052683Sktlim@umich.edu    def run(self):
2062292SN/A        """Run this test case and return a list of results"""
2072678Sktlim@umich.edu
2082678Sktlim@umich.edu        run_results = [ u.run() for u in self.run_units() ]
2092292SN/A        run_ok = all([not r.skipped() and r for r in run_results ])
2102292SN/A
2112292SN/A        verify_results = [
2122292SN/A            u.run() if run_ok else u.skip()
2132292SN/A            for u in self.verify_units()
2142292SN/A        ]
2152330SN/A
2162330SN/A        return TestResult(self.test_name,
2172330SN/A                          run_results=run_results,
2182683Sktlim@umich.edu                          verify_results=verify_results)
2192683Sktlim@umich.edu
2202683Sktlim@umich.edu    def __str__(self):
2212683Sktlim@umich.edu        return self.test_name
2222292SN/A
2233276Sgblack@eecs.umich.educlass ClassicTest(Test):
2243276Sgblack@eecs.umich.edu    # The diff ignore list contains all files that shouldn't be diffed
2253276Sgblack@eecs.umich.edu    # using DiffOutFile. These files typically use special-purpose
2263276Sgblack@eecs.umich.edu    # diff tools (e.g., DiffStatFile).
2273276Sgblack@eecs.umich.edu    diff_ignore_files = (
2283276Sgblack@eecs.umich.edu        # Stat files use a special stat differ
2293276Sgblack@eecs.umich.edu        "stats.txt",
2303276Sgblack@eecs.umich.edu    )
2313276Sgblack@eecs.umich.edu
2323276Sgblack@eecs.umich.edu    # These files should never be included in the list of
2332690Sktlim@umich.edu    # reference files. This list should include temporary files
2342292SN/A    # and other files that we don't care about.
2352292SN/A    ref_ignore_files = (
2362292SN/A    )
2372292SN/A
2382292SN/A    def __init__(self, gem5, output_dir, config_tuple,
2392292SN/A                 timeout=None,
2402292SN/A                 skip=False, skip_diff_out=False, skip_diff_stat=False):
2412292SN/A
2422292SN/A        super(ClassicTest, self).__init__("/".join(config_tuple))
2432292SN/A
2442292SN/A        ct = config_tuple
2452292SN/A
2462292SN/A        self.gem5 = os.path.abspath(gem5)
2472292SN/A        self.script = os.path.join(_test_base, "run.py")
2482292SN/A        self.config_tuple = ct
2492292SN/A        self.timeout = timeout
2502292SN/A
2512292SN/A        self.output_dir = output_dir
2522292SN/A        self.ref_dir = os.path.join(_test_base,
2532292SN/A                                    ct.category, ct.mode, ct.workload,
2542292SN/A                                    "ref", ct.isa, ct.os, ct.config)
2552292SN/A        self.skip_run = skip
2562292SN/A        self.skip_diff_out = skip or skip_diff_out
2572292SN/A        self.skip_diff_stat = skip or skip_diff_stat
2582292SN/A
259    def ref_files(self):
260        ref_dir = os.path.abspath(self.ref_dir)
261        for root, dirs, files in os.walk(ref_dir, topdown=False):
262            for f in files:
263                fpath = os.path.join(root[len(ref_dir) + 1:], f)
264                if fpath not in ClassicTest.ref_ignore_files:
265                    yield fpath
266
267    def run_units(self):
268        args = [
269            self.script,
270            "/".join(self.config_tuple),
271        ]
272
273        return [
274            RunGem5(self.gem5, args,
275                    ref_dir=self.ref_dir, test_dir=self.output_dir,
276                    skip=self.skip_run),
277        ]
278
279    def verify_units(self):
280        return [
281            DiffStatFile(ref_dir=self.ref_dir, test_dir=self.output_dir,
282                         skip=self.skip_diff_stat)
283        ] + [
284            DiffOutFile(f,
285                        ref_dir=self.ref_dir, test_dir=self.output_dir,
286                        skip=self.skip_diff_out)
287            for f in self.ref_files()
288            if f not in ClassicTest.diff_ignore_files
289        ]
290
291    def update_ref(self):
292        for fname in self.ref_files():
293            shutil.copy(
294                os.path.join(self.output_dir, fname),
295                os.path.join(self.ref_dir, fname))
296
297def parse_test_filter(test_filter):
298    wildcards = ("", "*")
299
300    _filter = list(test_filter.split("/"))
301    if len(_filter) > 3:
302        raise RuntimeError("Illegal test filter string")
303    _filter += [ "", ] * (3 - len(_filter))
304
305    isa, cat, mode = _filter
306
307    if isa in wildcards:
308        raise RuntimeError("No ISA specified")
309
310    cat = all_categories if cat in wildcards else (cat, )
311    mode = all_modes if mode in wildcards else (mode, )
312
313    return isa, cat, mode
314
315def get_tests(isa,
316              categories=all_categories, modes=all_modes,
317              ruby_protocol=None, gpu_isa=None):
318
319    # Generate a list of candidate configs
320    configs = list(arch_configs.get((isa, gpu_isa), []))
321
322    if (isa, gpu_isa) == ("x86", "hsail"):
323        if ruby_protocol == "GPU_RfO":
324            configs += ['gpu-randomtest']
325    else:
326        configs += generic_configs
327
328    if ruby_protocol == 'MI_example':
329        configs += [ "%s-ruby" % (c, ) for c in configs ]
330    elif ruby_protocol is not None:
331        # Override generic ISA configs when using Ruby (excluding
332        # MI_example which is included in all ISAs by default). This
333        # reduces the number of generic tests we re-run for when
334        # compiling Ruby targets.
335        configs = [ "%s-ruby-%s" % (c, ruby_protocol) for c in configs ]
336
337    # /(quick|long)/(fs|se)/workload/ref/arch/guest/config/
338    for conf_script in configs:
339        for cat in categories:
340            for mode in modes:
341                mode_dir = os.path.join(_test_base, cat, mode)
342                if not os.path.exists(mode_dir):
343                    continue
344
345                for workload in os.listdir(mode_dir):
346                    isa_dir = os.path.join(mode_dir, workload, "ref", isa)
347                    if not os.path.isdir(isa_dir):
348                        continue
349
350                    for _os in os.listdir(isa_dir):
351                        test_dir = os.path.join(isa_dir, _os, conf_script)
352                        if not os.path.exists(test_dir) or \
353                           os.path.exists(os.path.join(test_dir, "skip")):
354                            continue
355
356                        yield ClassicConfig(cat, mode, workload, isa, _os,
357                                            conf_script)
358