regression.py revision 10235
110235Syasuko.eckert@amd.com#!/usr/bin/env python
210235Syasuko.eckert@amd.com
310235Syasuko.eckert@amd.com# Copyright (c) 2010-2013 Advanced Micro Devices, Inc.
410235Syasuko.eckert@amd.com# All rights reserved.
510235Syasuko.eckert@amd.com#
610235Syasuko.eckert@amd.com# Redistribution and use in source and binary forms, with or without
710235Syasuko.eckert@amd.com# modification, are permitted provided that the following conditions are
810235Syasuko.eckert@amd.com# met: redistributions of source code must retain the above copyright
910235Syasuko.eckert@amd.com# notice, this list of conditions and the following disclaimer;
1010235Syasuko.eckert@amd.com# redistributions in binary form must reproduce the above copyright
1110235Syasuko.eckert@amd.com# notice, this list of conditions and the following disclaimer in the
1210235Syasuko.eckert@amd.com# documentation and/or other materials provided with the distribution;
1310235Syasuko.eckert@amd.com# neither the name of the copyright holders nor the names of its
1410235Syasuko.eckert@amd.com# contributors may be used to endorse or promote products derived from
1510235Syasuko.eckert@amd.com# this software without specific prior written permission.
1610235Syasuko.eckert@amd.com#
1710235Syasuko.eckert@amd.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1810235Syasuko.eckert@amd.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1910235Syasuko.eckert@amd.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2010235Syasuko.eckert@amd.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2110235Syasuko.eckert@amd.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2210235Syasuko.eckert@amd.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2310235Syasuko.eckert@amd.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2410235Syasuko.eckert@amd.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2510235Syasuko.eckert@amd.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2610235Syasuko.eckert@amd.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2710235Syasuko.eckert@amd.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2810235Syasuko.eckert@amd.com
2910235Syasuko.eckert@amd.com"""
3010235Syasuko.eckert@amd.comSYNOPSIS
3110235Syasuko.eckert@amd.com
3210235Syasuko.eckert@amd.com    ./regression/regression.py ./regression/
3310235Syasuko.eckert@amd.com
3410235Syasuko.eckert@amd.comDESCRIPTION
3510235Syasuko.eckert@amd.com
3610235Syasuko.eckert@amd.com    Runs regression tester for McPAT.
3710235Syasuko.eckert@amd.com    This tester can compile and runs McPAT on the input contained in the
3810235Syasuko.eckert@amd.com    specified directory, and then compares the output to that of a prior run in
3910235Syasuko.eckert@amd.com    order to ensure that specific power and area calculations do not change.
4010235Syasuko.eckert@amd.com
4110235Syasuko.eckert@amd.comAUTHORS
4210235Syasuko.eckert@amd.com
4310235Syasuko.eckert@amd.com    Joel Hestness <hestness@cs.wisc.edu> (while interning at AMD)
4410235Syasuko.eckert@amd.com    Yasuko Eckert <yasuko.eckert@amd.com>
4510235Syasuko.eckert@amd.com"""
4610235Syasuko.eckert@amd.com
4710235Syasuko.eckert@amd.comimport os
4810235Syasuko.eckert@amd.comimport sys
4910235Syasuko.eckert@amd.comimport optparse
5010235Syasuko.eckert@amd.comimport re
5110235Syasuko.eckert@amd.com
5210235Syasuko.eckert@amd.com################################
5310235Syasuko.eckert@amd.com# Global Variables
5410235Syasuko.eckert@amd.com################################
5510235Syasuko.eckert@amd.com
5610235Syasuko.eckert@amd.comglobal mcpat_binary
5710235Syasuko.eckert@amd.commcpat_binary = "../../build/mcpat/mcpat"
5810235Syasuko.eckert@amd.comglobal optionsparser
5910235Syasuko.eckert@amd.com
6010235Syasuko.eckert@amd.com################################
6110235Syasuko.eckert@amd.com# Global Functions
6210235Syasuko.eckert@amd.com################################
6310235Syasuko.eckert@amd.com
6410235Syasuko.eckert@amd.comdef run_test(testdir):
6510235Syasuko.eckert@amd.com    test_passed = True
6610235Syasuko.eckert@amd.com    testfiles = os.listdir(testdir)
6710235Syasuko.eckert@amd.com    for testfile in testfiles:
6810235Syasuko.eckert@amd.com        # For each power_region file, run McPAT on it and check the
6910235Syasuko.eckert@amd.com        # output created against the regression
7010235Syasuko.eckert@amd.com        if re.match("power_region.*\.xml$", testfile):
7110235Syasuko.eckert@amd.com            # Get the region index of the test
7210235Syasuko.eckert@amd.com            fileparts = testfile.split(".")
7310235Syasuko.eckert@amd.com            region_index = fileparts[0][12:]
7410235Syasuko.eckert@amd.com            regression_test = os.path.join(testdir, testfile)
7510235Syasuko.eckert@amd.com            regression_output = os.path.join(
7610235Syasuko.eckert@amd.com                    testdir, "region%s.out" % region_index)
7710235Syasuko.eckert@amd.com            regression_correct = os.path.join(
7810235Syasuko.eckert@amd.com                    testdir, "region%s.out.ref" % region_index)
7910235Syasuko.eckert@amd.com            print "Running test: %s..." % regression_test
8010235Syasuko.eckert@amd.com            # Run McPAT on the input
8110235Syasuko.eckert@amd.com            os.system(
8210235Syasuko.eckert@amd.com                    "%s -infile %s -print_level 10 > %s" %
8310235Syasuko.eckert@amd.com                    (mcpat_binary, regression_test, regression_output) )
8410235Syasuko.eckert@amd.com            if os.path.exists(regression_correct):
8510235Syasuko.eckert@amd.com                diff = os.popen(
8610235Syasuko.eckert@amd.com                        "diff %s %s" % (regression_output, regression_correct),
8710235Syasuko.eckert@amd.com                        "r").read()
8810235Syasuko.eckert@amd.com                if diff != "":
8910235Syasuko.eckert@amd.com                    print "WARN: Differences found in %s" % regression_output
9010235Syasuko.eckert@amd.com                    if options.verbose:
9110235Syasuko.eckert@amd.com                        print diff
9210235Syasuko.eckert@amd.com                    test_passed = False
9310235Syasuko.eckert@amd.com            else:
9410235Syasuko.eckert@amd.com                print "WARN: Regression test not set up: %s..." % regression_test
9510235Syasuko.eckert@amd.com                print "WARN: Not able to verify test"
9610235Syasuko.eckert@amd.com                test_passed = False
9710235Syasuko.eckert@amd.com
9810235Syasuko.eckert@amd.com            if options.cleanup:
9910235Syasuko.eckert@amd.com                if options.verbose:
10010235Syasuko.eckert@amd.com                    print "WARN: Cleaning (deleting) regression output file: "\
10110235Syasuko.eckert@amd.com                            "%s" % regression_output
10210235Syasuko.eckert@amd.com                os.system("rm -f %s" % regression_output)
10310235Syasuko.eckert@amd.com
10410235Syasuko.eckert@amd.com    if test_passed:
10510235Syasuko.eckert@amd.com        print "PASSED: %s\n\n" % testdir
10610235Syasuko.eckert@amd.com    else:
10710235Syasuko.eckert@amd.com        print "FAILED: %s\n\n" % testdir
10810235Syasuko.eckert@amd.com
10910235Syasuko.eckert@amd.comdef has_power_region_files(testdir):
11010235Syasuko.eckert@amd.com    files = os.listdir(testdir)
11110235Syasuko.eckert@amd.com    for file in files:
11210235Syasuko.eckert@amd.com        if "power_region" in file and ".xml" in file:
11310235Syasuko.eckert@amd.com            return True
11410235Syasuko.eckert@amd.com
11510235Syasuko.eckert@amd.comdef is_valid_test_directory(testdir):
11610235Syasuko.eckert@amd.com    valid_regression = True
11710235Syasuko.eckert@amd.com    power_region_file_found = False
11810235Syasuko.eckert@amd.com
11910235Syasuko.eckert@amd.com    files = os.listdir(testdir)
12010235Syasuko.eckert@amd.com    for file in files:
12110235Syasuko.eckert@amd.com        if "power_region" in file and ".xml" in file:
12210235Syasuko.eckert@amd.com            power_region_file_found = True
12310235Syasuko.eckert@amd.com            fileparts = file.split(".")
12410235Syasuko.eckert@amd.com            region_index = fileparts[0][12:]
12510235Syasuko.eckert@amd.com            regression_output = os.path.join(
12610235Syasuko.eckert@amd.com                    testdir, "region%s.out.ref" % region_index)
12710235Syasuko.eckert@amd.com            if os.path.exists(regression_output):
12810235Syasuko.eckert@amd.com                if options.verbose:
12910235Syasuko.eckert@amd.com                    print "Valid regression test: %s/%s" % (testdir, file)
13010235Syasuko.eckert@amd.com            else:
13110235Syasuko.eckert@amd.com                valid_regression = False
13210235Syasuko.eckert@amd.com
13310235Syasuko.eckert@amd.com    return valid_regression and power_region_file_found
13410235Syasuko.eckert@amd.com
13510235Syasuko.eckert@amd.com################################
13610235Syasuko.eckert@amd.com# Execute here
13710235Syasuko.eckert@amd.com################################
13810235Syasuko.eckert@amd.com
13910235Syasuko.eckert@amd.comoptionsparser = optparse.OptionParser(
14010235Syasuko.eckert@amd.com        formatter = optparse.TitledHelpFormatter(),
14110235Syasuko.eckert@amd.com        usage = globals()['__doc__'])
14210235Syasuko.eckert@amd.comoptionsparser.add_option(
14310235Syasuko.eckert@amd.com        "-b", "--build", action = "store_true", default = False,
14410235Syasuko.eckert@amd.com        help = "Build McPAT before running tests")
14510235Syasuko.eckert@amd.comoptionsparser.add_option(
14610235Syasuko.eckert@amd.com        "-c", "--cleanup", action = "store_true", default = False,
14710235Syasuko.eckert@amd.com        help = "Clean up the specified regression directory")
14810235Syasuko.eckert@amd.comoptionsparser.add_option(
14910235Syasuko.eckert@amd.com        "-f", "--force", action = "store_true", default = False,
15010235Syasuko.eckert@amd.com        help = "Force run regression even if directory isn't set up")
15110235Syasuko.eckert@amd.comoptionsparser.add_option(
15210235Syasuko.eckert@amd.com        "-m", "--maketest", action = "store_true", default = False,
15310235Syasuko.eckert@amd.com        help = "Set up the specified test directory")
15410235Syasuko.eckert@amd.comoptionsparser.add_option(
15510235Syasuko.eckert@amd.com        "-v", "--verbose", action = "store_true", default = False,
15610235Syasuko.eckert@amd.com        help = "Print verbose output")
15710235Syasuko.eckert@amd.com(options, args) = optionsparser.parse_args()
15810235Syasuko.eckert@amd.com
15910235Syasuko.eckert@amd.comif not os.path.exists(mcpat_binary) and not options.build:
16010235Syasuko.eckert@amd.com    print "ERROR: McPAT binary does not exist: %s" % mcpat_binary
16110235Syasuko.eckert@amd.com    exit(0)
16210235Syasuko.eckert@amd.com
16310235Syasuko.eckert@amd.comif options.build:
16410235Syasuko.eckert@amd.com    print "Building McPAT..."
16510235Syasuko.eckert@amd.com    bin_dir = os.path.dirname(mcpat_binary)
16610235Syasuko.eckert@amd.com    directory = os.path.join(bin_dir, "../../ext/mcpat")
16710235Syasuko.eckert@amd.com    build_output = os.popen(
16810235Syasuko.eckert@amd.com            "cd %s; make clean; make -j 8 dbg 2>&1" % directory).read()
16910235Syasuko.eckert@amd.com    if "error" in build_output.lower():
17010235Syasuko.eckert@amd.com        print "Error during build: %s" % build_output
17110235Syasuko.eckert@amd.com        exit(0)
17210235Syasuko.eckert@amd.com
17310235Syasuko.eckert@amd.comif len(args) < 1:
17410235Syasuko.eckert@amd.com    print "ERROR: Must specify regressions directory"
17510235Syasuko.eckert@amd.com    exit(0)
17610235Syasuko.eckert@amd.com
17710235Syasuko.eckert@amd.com# check params
17810235Syasuko.eckert@amd.comrootdir = args[0];
17910235Syasuko.eckert@amd.comif not os.path.exists(rootdir):
18010235Syasuko.eckert@amd.com    print "ERROR: Regressions directory does not exist: %s" % rootdir
18110235Syasuko.eckert@amd.com    exit(0)
18210235Syasuko.eckert@amd.com
18310235Syasuko.eckert@amd.comif options.maketest:
18410235Syasuko.eckert@amd.com    # The specified rootdir must exist since we got here
18510235Syasuko.eckert@amd.com    # Check if directory has tests
18610235Syasuko.eckert@amd.com    list = os.listdir(rootdir)
18710235Syasuko.eckert@amd.com    found_test = False
18810235Syasuko.eckert@amd.com    for file in list:
18910235Syasuko.eckert@amd.com        if "power_region" in file and "out" not in file and "ref" not in file:
19010235Syasuko.eckert@amd.com            found_test = True
19110235Syasuko.eckert@amd.com            # Prepare to run the test in order to set it up
19210235Syasuko.eckert@amd.com            fileparts = file.split(".")
19310235Syasuko.eckert@amd.com            region_index = fileparts[0][12:]
19410235Syasuko.eckert@amd.com            regression_test = os.path.join(rootdir, file)
19510235Syasuko.eckert@amd.com            regression_output = os.path.join(
19610235Syasuko.eckert@amd.com                    rootdir, "region%s.out.ref" % region_index)
19710235Syasuko.eckert@amd.com            if os.path.exists(regression_output):
19810235Syasuko.eckert@amd.com                print "WARN: Overwriting old regression output: " \
19910235Syasuko.eckert@amd.com                        "%s" % regression_output
20010235Syasuko.eckert@amd.com            # Run the test to set it up
20110235Syasuko.eckert@amd.com            print "Writing new regression output..."
20210235Syasuko.eckert@amd.com            os.system(
20310235Syasuko.eckert@amd.com                    "%s -infile %s -print_level 10 > %s" %
20410235Syasuko.eckert@amd.com                    (mcpat_binary, regression_test, regression_output))
20510235Syasuko.eckert@amd.com
20610235Syasuko.eckert@amd.com    if not found_test:
20710235Syasuko.eckert@amd.com        print "ERROR: Invalid test directory: %s" % rootdir
20810235Syasuko.eckert@amd.com        print "ERROR: Must contain XML file power_region*.xml"
20910235Syasuko.eckert@amd.com
21010235Syasuko.eckert@amd.com    exit(0)
21110235Syasuko.eckert@amd.com
21210235Syasuko.eckert@amd.comfound_test = False
21310235Syasuko.eckert@amd.comif has_power_region_files(rootdir):
21410235Syasuko.eckert@amd.com    found_test = True
21510235Syasuko.eckert@amd.com    if is_valid_test_directory(rootdir) or options.force:
21610235Syasuko.eckert@amd.com        run_test(rootdir)
21710235Syasuko.eckert@amd.com    else:
21810235Syasuko.eckert@amd.com        print "WARN: Regression directory is not set up: %s" % rootdir
21910235Syasuko.eckert@amd.comelse:
22010235Syasuko.eckert@amd.com    folders = os.listdir(rootdir)
22110235Syasuko.eckert@amd.com    folders.sort()
22210235Syasuko.eckert@amd.com    for folder in folders:
22310235Syasuko.eckert@amd.com        testdir = os.path.join(rootdir, folder)
22410235Syasuko.eckert@amd.com        if os.path.isdir(testdir):
22510235Syasuko.eckert@amd.com            if has_power_region_files(testdir):
22610235Syasuko.eckert@amd.com                found_test = True
22710235Syasuko.eckert@amd.com                if is_valid_test_directory(testdir):
22810235Syasuko.eckert@amd.com                    run_test(testdir)
22910235Syasuko.eckert@amd.com                else:
23010235Syasuko.eckert@amd.com                    if options.force:
23110235Syasuko.eckert@amd.com                        print "WARN: Regression directory is not set up: " \
23210235Syasuko.eckert@amd.com                                "%s" % testdir
23310235Syasuko.eckert@amd.com                        print "WARN: Running test anyway: %s..." % testdir
23410235Syasuko.eckert@amd.com                        run_test(testdir)
23510235Syasuko.eckert@amd.com                    else:
23610235Syasuko.eckert@amd.com                        print "Regression directory is not set up: %s" % testdir
23710235Syasuko.eckert@amd.com            else:
23810235Syasuko.eckert@amd.com                print "Not a valid test directory: %s" % testdir
23910235Syasuko.eckert@amd.com
24010235Syasuko.eckert@amd.comif not found_test:
24110235Syasuko.eckert@amd.com    print "No valid regressions found in %s" % rootdir
242