aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/aarch64/test-assembler-aarch64.h10
-rw-r--r--test/aarch64/test-simulator-aarch64.cc6
-rw-r--r--test/test-api.cc10
-rw-r--r--tools/known_test_failures.py16
-rw-r--r--tools/printer.py14
-rwxr-xr-xtools/test.py5
-rw-r--r--tools/thread_pool.py55
-rw-r--r--tools/threaded_tests.py102
8 files changed, 162 insertions, 56 deletions
diff --git a/test/aarch64/test-assembler-aarch64.h b/test/aarch64/test-assembler-aarch64.h
index b45c7ae8..cc4160b4 100644
--- a/test/aarch64/test-assembler-aarch64.h
+++ b/test/aarch64/test-assembler-aarch64.h
@@ -302,10 +302,12 @@ inline bool CanRun(const CPUFeatures& required, bool* queried_can_run) {
if (!*queried_can_run) {
*queried_can_run = true;
CPUFeatures missing = required.Without(cpu);
- std::cout << "Warning: This test cannot execute its generated code on this "
- "CPU.\n";
- std::cout << " Required: { " << required << " }\n";
- std::cout << " Missing: { " << missing << " }\n";
+ // Note: This message needs to match REGEXP_MISSING_FEATURES from
+ // tools/threaded_test.py.
+ std::cout << "SKIPPED: Missing features: { " << missing << " }\n";
+ std::cout << "This test requires the following features to run its "
+ "generated code on this CPU: "
+ << required << "\n";
}
return false;
}
diff --git a/test/aarch64/test-simulator-aarch64.cc b/test/aarch64/test-simulator-aarch64.cc
index b145bb9a..257326f1 100644
--- a/test/aarch64/test-simulator-aarch64.cc
+++ b/test/aarch64/test-simulator-aarch64.cc
@@ -142,8 +142,10 @@ namespace aarch64 {
*skipped = false; \
} else { \
std::stringstream os; \
- os << "Warning: skipping test due to missing CPU features.\n"; \
- os << " Missing: {" << requirements.Without(this_machine) << "}\n"; \
+ /* Note: This message needs to match REGEXP_MISSING_FEATURES from */ \
+ /* tools/threaded_test.py. */ \
+ os << "SKIPPED: Missing features: { "; \
+ os << requirements.Without(this_machine) << " }\n"; \
printf("%s", os.str().c_str()); \
*skipped = true; \
} \
diff --git a/test/test-api.cc b/test/test-api.cc
index 53eaae38..5e0001e6 100644
--- a/test/test-api.cc
+++ b/test/test-api.cc
@@ -559,9 +559,13 @@ TEST(CPUFeatures_infer_from_id_registers) {
VIXL_CHECK(os_auto.Has(os_with_id_regs));
VIXL_CHECK(os_with_id_regs.Has(os_auto));
} else {
- printf(
- "Warning: skipping test because ID register emulation is not "
- "available.\n");
+ // Note: This message needs to match REGEXP_MISSING_FEATURES from
+ // tools/threaded_test.py.
+ std::cout << "SKIPPED: Missing features: { "
+ << CPUFeatures::kIDRegisterEmulation << " }\n";
+ std::cout << "This test requires the following features to run its "
+ "generated code on this CPU: "
+ << CPUFeatures::kIDRegisterEmulation << "\n";
}
}
diff --git a/tools/known_test_failures.py b/tools/known_test_failures.py
index ad7ff1b5..262d6e62 100644
--- a/tools/known_test_failures.py
+++ b/tools/known_test_failures.py
@@ -45,8 +45,8 @@ def FilterKnownValgrindTestFailures(tests):
if major > 3 or (major == 3 and minor > 10):
return tests
- # Valgrind versions before 3.11 have issues with fused multiply-add,
- # so disable the affected tests.
+ reason = "Valgrind versions before 3.11 have issues with fused multiply-add, " \
+ "so disable the affected tests."
known_valgrind_test_failures = {
'AARCH64_SIM_fmadd_d',
'AARCH64_SIM_fmadd_s',
@@ -76,13 +76,13 @@ def FilterKnownValgrindTestFailures(tests):
'AARCH64_SIM_frsqrts_D'
}
- for t in sorted(known_valgrind_test_failures):
- print('Skipping ' + t + '...')
-
- return filter(lambda x: x not in known_valgrind_test_failures, tests)
+ filtered_list = filter(lambda x: x not in known_valgrind_test_failures, tests)
+ return (filtered_list, len(tests) - len(filtered_list), reason)
def FilterKnownTestFailures(tests, **env):
+ skipped = []
if env.get('under_valgrind'):
- tests = FilterKnownValgrindTestFailures(tests)
+ tests, n_tests_skipped, reason = FilterKnownValgrindTestFailures(tests)
+ skipped.append( (n_tests_skipped, reason) )
- return tests
+ return (tests, skipped)
diff --git a/tools/printer.py b/tools/printer.py
index 4a37a340..a28b433f 100644
--- a/tools/printer.py
+++ b/tools/printer.py
@@ -104,18 +104,22 @@ def PrintOverwritableLine(string, has_lock = False, type = LINE_TYPE_NONE):
# Display the run progress:
# prefix [time| progress|+ passed|- failed] name
-def UpdateProgress(start_time, passed, failed, count, name, prefix = '',
- prevent_next_overwrite = False, has_lock = False):
+def UpdateProgress(start_time, passed, failed, count, skipped, known_failures,
+ name, prefix = '', prevent_next_overwrite = False,
+ has_lock = False):
minutes, seconds = divmod(time.time() - start_time, 60)
- progress = float(passed + failed) / count * 100
+ progress = float(passed + failed + skipped) / count * 100
passed_colour = COLOUR_GREEN if passed != 0 else ''
failed_colour = COLOUR_RED if failed != 0 else ''
+ skipped_colour = COLOUR_ORANGE if (skipped + known_failures) != 0 else ''
indicator = '[%02d:%02d| %3d%%|'
indicator += passed_colour + '+ %d' + NO_COLOUR + '|'
- indicator += failed_colour + '- %d' + NO_COLOUR + ']'
+ indicator += failed_colour + '- %d' + NO_COLOUR + '|'
+ indicator += skipped_colour + '? %d' + NO_COLOUR + ']'
progress_string = prefix
- progress_string += indicator % (minutes, seconds, progress, passed, failed)
+ progress_string += indicator % (minutes, seconds, progress, passed, failed,
+ skipped + known_failures)
progress_string += ' ' + name
PrintOverwritableLine(progress_string, type = LINE_TYPE_PROGRESS,
diff --git a/tools/test.py b/tools/test.py
index 9f2b6539..0d6bcb82 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -34,7 +34,6 @@ import multiprocessing
import os
from os.path import join
import platform
-import re
import subprocess
import sys
import time
@@ -144,6 +143,8 @@ def BuildOptions():
help='''Don't actually build or run anything,
but print the configurations that would be
tested.''')
+ general_arguments.add_argument('--verbose', action='store_true',
+ help='''Print extra information.''')
general_arguments.add_argument(
'--jobs', '-j', metavar='N', type=int, nargs='?',
default=multiprocessing.cpu_count(),
@@ -429,7 +430,7 @@ if __name__ == '__main__':
if not args.nobench:
rc.Combine(RunBenchmarks(options, args))
- rc.Combine(tests.Run(args.jobs))
+ rc.Combine(tests.Run(args.jobs, args.verbose))
if not args.dry_run:
rc.PrintStatus()
diff --git a/tools/thread_pool.py b/tools/thread_pool.py
new file mode 100644
index 00000000..60abafa2
--- /dev/null
+++ b/tools/thread_pool.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2019, VIXL authors
+# 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 ARM Limited 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 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 multiprocessing
+import signal
+import sys
+
+# Catch SIGINT to gracefully exit when ctrl+C is pressed.
+def SigIntHandler(signal, frame):
+ sys.exit(1)
+
+signal.signal(signal.SIGINT, SigIntHandler)
+
+# This function can't run in parallel due to constraints from the
+# multiprocessing module.
+__run_tests_lock__ = multiprocessing.Lock()
+def Multithread(function, list_of_args, num_threads=1, init_function=None):
+ with __run_tests_lock__:
+ if init_function:
+ if not init_function():
+ # Init failed: early exit
+ return
+
+ pool = multiprocessing.Pool(num_threads)
+ # The '.get(9999999)' is a workaround to allow killing the test script with
+ # ctrl+C from the shell. This bug is documented at
+ # http://bugs.python.org/issue8296.
+ pool.map_async(function, list_of_args).get(9999999)
+ pool.close()
+ pool.join()
diff --git a/tools/threaded_tests.py b/tools/threaded_tests.py
index 035e96b7..a2655330 100644
--- a/tools/threaded_tests.py
+++ b/tools/threaded_tests.py
@@ -24,22 +24,18 @@
# 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 collections
import multiprocessing
import re
-import signal
import subprocess
-import sys
import time
from known_test_failures import FilterKnownTestFailures
import printer
+import thread_pool
import util
-# Catch SIGINT to gracefully exit when ctrl+C is pressed.
-def SigIntHandler(signal, frame):
- sys.exit(1)
-
-signal.signal(signal.SIGINT, SigIntHandler)
+REGEXP_MISSING_FEATURES = "Missing features: { ([^,}]+(, [^,}]+)*) }"
# Scan matching tests and return a test manifest.
def GetTests(runner, filters = []):
@@ -48,7 +44,6 @@ def GetTests(runner, filters = []):
tests = output.split()
for f in filters:
- print f
tests = filter(re.compile(f).search, tests)
return tests
@@ -61,7 +56,20 @@ def RunTest(test):
rc = p.poll()
if rc == 0:
- with Test.n_tests_passed.get_lock(): Test.n_tests_passed.value += 1
+ skipped = False
+ lines = p_out.split('\n')
+ skipped_id = "SKIPPED: "
+ for i in range(len(lines)):
+ if lines[i].startswith(skipped_id):
+ skipped = True
+ reason = lines[i][len(skipped_id):]
+ with Test.n_tests_skipped.get_lock():
+ Test.n_tests_skipped.value += 1
+ test.shared.tests_skipped.setdefault(reason, 0)
+ test.shared.tests_skipped[reason] += 1
+ break
+ if not skipped:
+ with Test.n_tests_passed.get_lock(): Test.n_tests_passed.value += 1
else:
with Test.n_tests_failed.get_lock(): Test.n_tests_failed.value += 1
@@ -71,6 +79,8 @@ def RunTest(test):
Test.n_tests_passed.value,
Test.n_tests_failed.value,
test.shared.n_tests,
+ Test.n_tests_skipped.value,
+ test.shared.n_known_failures,
test.name,
prevent_next_overwrite = (rc != 0),
has_lock = True,
@@ -91,6 +101,8 @@ class Test(object):
# or static, or no work is started.
n_tests_passed = multiprocessing.Value('i', 0)
n_tests_failed = multiprocessing.Value('i', 0)
+ n_tests_skipped = multiprocessing.Value('i', 0)
+ manager = multiprocessing.Manager()
def __init__(self, test_runner, test, runtime_options, use_valgrind, shared):
self.command = [test_runner, test] + runtime_options
@@ -104,10 +116,18 @@ class TestQueue(object):
self.progress_prefix = prefix
self.under_valgrind = under_valgrind
self.queue = []
+ self.tests_skipped = Test.manager.dict()
+ self.n_known_failures = 0
+ self.known_failures = collections.Counter()
def Add(self, test_runner_command, filters, runtime_options):
tests = GetTests(test_runner_command, filters)
- tests = FilterKnownTestFailures(tests, under_valgrind = self.under_valgrind)
+ n_tests_total = len(tests)
+ tests, skipped = FilterKnownTestFailures(tests, under_valgrind = self.under_valgrind)
+ for n_tests, reason in skipped:
+ if n_tests > 0:
+ self.n_known_failures += n_tests
+ self.known_failures[reason] += n_tests
if len(tests) == 0:
printer.Print('No tests to run.')
@@ -118,35 +138,53 @@ class TestQueue(object):
runtime_options, self.under_valgrind, self))
# Run the specified tests.
- # This function won't run in parallel due to constraints from the
- # multiprocessing module.
- __run_tests_lock__ = multiprocessing.Lock()
- def Run(self, jobs):
- with TestQueue.__run_tests_lock__:
+ def Run(self, jobs, verbose):
+ def InitGlobals():
# Initialisation.
self.start_time = time.time()
self.n_tests = len(self.queue)
if self.n_tests == 0:
printer.Print('No tests to run.')
- return 0
+ return False
Test.n_tests_passed.value = 0
Test.n_tests_failed.value = 0
-
- pool = multiprocessing.Pool(jobs)
- # The '.get(9999999)' is a workaround to allow killing the test script with
- # ctrl+C from the shell. This bug is documented at
- # http://bugs.python.org/issue8296.
- work = pool.map_async(RunTest, self.queue).get(9999999)
- pool.close()
- pool.join()
-
- printer.UpdateProgress(self.start_time,
- Test.n_tests_passed.value,
- Test.n_tests_failed.value,
- self.n_tests,
- '== Done ==',
- prevent_next_overwrite = True,
- prefix = self.progress_prefix)
+ Test.n_tests_skipped.value = 0
+ self.tests_skipped.clear()
+ return True
+
+ thread_pool.Multithread(RunTest, self.queue, jobs, InitGlobals)
+
+ printer.UpdateProgress(self.start_time,
+ Test.n_tests_passed.value,
+ Test.n_tests_failed.value,
+ self.n_tests,
+ Test.n_tests_skipped.value,
+ self.n_known_failures,
+ '== Done ==',
+ prevent_next_overwrite = True,
+ prefix = self.progress_prefix)
+ n_tests_features = 0
+ features = set()
+ for reason, n_tests in self.tests_skipped.items():
+ m = re.match(REGEXP_MISSING_FEATURES, reason)
+ if m:
+ if verbose:
+ printer.Print("%d tests skipped because the following features are not "
+ "available '%s'" % (n_tests, m.group(1)))
+ else:
+ n_tests_features += n_tests
+ features.update(m.group(1).split(', '))
+ else:
+ printer.Print("%d tests skipped because '%s'" % (n_tests, reason))
+
+ n_tests_other = 0
+ if n_tests_features > 0 :
+ printer.Print("%d tests skipped because the CPU does not support "
+ "the following features: '%s'" %
+ (n_tests_features, ", ".join(features)))
+
+ for reason, n_tests in self.known_failures.items():
+ printer.Print("%d tests skipped because '%s'" % (n_tests, reason))
# Empty the queue now that the tests have been run.
self.queue = []