Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Unified Diff: third_party/gtest-parallel/gtest-parallel

Issue 2588333002: Move last of third_party dirs into DEPS entries (Closed)
Patch Set: Remove junit-jar from .gitignore Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/gtest-parallel/README.webrtc ('k') | third_party/gtest-parallel/gtest-parallel-wrapper.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/gtest-parallel/gtest-parallel
diff --git a/third_party/gtest-parallel/gtest-parallel b/third_party/gtest-parallel/gtest-parallel
deleted file mode 100755
index 4e5a9fc0ed71489897afa08fbe6c70dc7d06f8ee..0000000000000000000000000000000000000000
--- a/third_party/gtest-parallel/gtest-parallel
+++ /dev/null
@@ -1,478 +0,0 @@
-#!/usr/bin/env python2
-# Copyright 2013 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-import cPickle
-import errno
-import gzip
-import json
-import multiprocessing
-import optparse
-import os
-import signal
-import subprocess
-import sys
-import tempfile
-import thread
-import threading
-import time
-import zlib
-
-# An object that catches SIGINT sent to the Python process and notices
-# if processes passed to wait() die by SIGINT (we need to look for
-# both of those cases, because pressing Ctrl+C can result in either
-# the main process or one of the subprocesses getting the signal).
-#
-# Before a SIGINT is seen, wait(p) will simply call p.wait() and
-# return the result. Once a SIGINT has been seen (in the main process
-# or a subprocess, including the one the current call is waiting for),
-# wait(p) will call p.terminate() and raise ProcessWasInterrupted.
-class SigintHandler(object):
- class ProcessWasInterrupted(Exception): pass
- sigint_returncodes = {-signal.SIGINT, # Unix
- -1073741510, # Windows
- }
- def __init__(self):
- self.__lock = threading.Lock()
- self.__processes = set()
- self.__got_sigint = False
- signal.signal(signal.SIGINT, self.__sigint_handler)
- def __on_sigint(self):
- self.__got_sigint = True
- while self.__processes:
- try:
- self.__processes.pop().terminate()
- except OSError:
- pass
- def __sigint_handler(self, signal_num, frame):
- with self.__lock:
- self.__on_sigint()
- def got_sigint(self):
- with self.__lock:
- return self.__got_sigint
- def wait(self, p):
- with self.__lock:
- if self.__got_sigint:
- p.terminate()
- self.__processes.add(p)
- code = p.wait()
- with self.__lock:
- self.__processes.discard(p)
- if code in self.sigint_returncodes:
- self.__on_sigint()
- if self.__got_sigint:
- raise self.ProcessWasInterrupted
- return code
-sigint_handler = SigintHandler()
-
-# Return the width of the terminal, or None if it couldn't be
-# determined (e.g. because we're not being run interactively).
-def term_width(out):
- if not out.isatty():
- return None
- try:
- p = subprocess.Popen(["stty", "size"],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (out, err) = p.communicate()
- if p.returncode != 0 or err:
- return None
- return int(out.split()[1])
- except (IndexError, OSError, ValueError):
- return None
-
-# Output transient and permanent lines of text. If several transient
-# lines are written in sequence, the new will overwrite the old. We
-# use this to ensure that lots of unimportant info (tests passing)
-# won't drown out important info (tests failing).
-class Outputter(object):
- def __init__(self, out_file):
- self.__out_file = out_file
- self.__previous_line_was_transient = False
- self.__width = term_width(out_file) # Line width, or None if not a tty.
- def transient_line(self, msg):
- if self.__width is None:
- self.__out_file.write(msg + "\n")
- else:
- self.__out_file.write("\r" + msg[:self.__width].ljust(self.__width))
- self.__previous_line_was_transient = True
- def flush_transient_output(self):
- if self.__previous_line_was_transient:
- self.__out_file.write("\n")
- self.__previous_line_was_transient = False
- def permanent_line(self, msg):
- self.flush_transient_output()
- self.__out_file.write(msg + "\n")
-
-stdout_lock = threading.Lock()
-
-class FilterFormat:
- if sys.stdout.isatty():
- # stdout needs to be unbuffered since the output is interactive.
- sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
-
- out = Outputter(sys.stdout)
- total_tests = 0
- finished_tests = 0
-
- tests = {}
- outputs = {}
- failures = []
-
- def print_test_status(self, last_finished_test, time_ms):
- self.out.transient_line("[%d/%d] %s (%d ms)"
- % (self.finished_tests, self.total_tests,
- last_finished_test, time_ms))
-
- def handle_meta(self, job_id, args):
- (command, arg) = args.split(' ', 1)
- if command == "TEST":
- (binary, test) = arg.split(' ', 1)
- self.tests[job_id] = (binary, test.strip())
- elif command == "EXIT":
- (exit_code, time_ms) = [int(x) for x in arg.split(' ', 1)]
- self.finished_tests += 1
- (binary, test) = self.tests[job_id]
- self.print_test_status(test, time_ms)
- if exit_code != 0:
- self.failures.append(self.tests[job_id])
- with open(self.outputs[job_id]) as f:
- for line in f.readlines():
- self.out.permanent_line(line.rstrip())
- self.out.permanent_line(
- "[%d/%d] %s returned/aborted with exit code %d (%d ms)"
- % (self.finished_tests, self.total_tests, test, exit_code, time_ms))
- elif command == "TESTCNT":
- self.total_tests = int(arg.split(' ', 1)[1])
- self.out.transient_line("[0/%d] Running tests..." % self.total_tests)
-
- def logfile(self, job_id, name):
- self.outputs[job_id] = name
-
- def log(self, line):
- stdout_lock.acquire()
- (prefix, output) = line.split(' ', 1)
-
- assert prefix[-1] == ':'
- self.handle_meta(int(prefix[:-1]), output)
- stdout_lock.release()
-
- def end(self):
- if self.failures:
- self.out.permanent_line("FAILED TESTS (%d/%d):"
- % (len(self.failures), self.total_tests))
- for (binary, test) in self.failures:
- self.out.permanent_line(" " + binary + ": " + test)
- self.out.flush_transient_output()
-
-class RawFormat:
- def log(self, line):
- stdout_lock.acquire()
- sys.stdout.write(line + "\n")
- sys.stdout.flush()
- stdout_lock.release()
- def logfile(self, job_id, name):
- with open(name) as f:
- for line in f.readlines():
- self.log(str(job_id) + '> ' + line.rstrip())
- def end(self):
- pass
-
-class CollectTestResults(object):
- def __init__(self, json_dump_filepath):
- self.test_results_lock = threading.Lock()
- self.json_dump_file = open(json_dump_filepath, 'w')
- self.test_results = {
- "interrupted": False,
- "path_delimiter": ".",
- # Third version of the file format. See the link in the flag description
- # for details.
- "version": 3,
- "seconds_since_epoch": int(time.time()),
- "num_failures_by_type": {
- "PASS": 0,
- "FAIL": 0,
- },
- "tests": {},
- }
-
- def log(self, test, result):
- with self.test_results_lock:
- self.test_results['num_failures_by_type'][result['actual']] += 1
- results = self.test_results['tests']
- for name in test.split('.'):
- results = results.setdefault(name, {})
- results.update(result)
-
- def dump_to_file_and_close(self):
- json.dump(self.test_results, self.json_dump_file)
- self.json_dump_file.close()
-
-class IgnoreTestResults(object):
- def log(self, test, result):
- pass
- def dump_to_file_and_close(self):
- pass
-
-# Record of test runtimes. Has built-in locking.
-class TestTimes(object):
- def __init__(self, save_file):
- "Create new object seeded with saved test times from the given file."
- self.__times = {} # (test binary, test name) -> runtime in ms
-
- # Protects calls to record_test_time(); other calls are not
- # expected to be made concurrently.
- self.__lock = threading.Lock()
-
- try:
- with gzip.GzipFile(save_file, "rb") as f:
- times = cPickle.load(f)
- except (EOFError, IOError, cPickle.UnpicklingError, zlib.error):
- # File doesn't exist, isn't readable, is malformed---whatever.
- # Just ignore it.
- return
-
- # Discard saved times if the format isn't right.
- if type(times) is not dict:
- return
- for ((test_binary, test_name), runtime) in times.items():
- if (type(test_binary) is not str or type(test_name) is not str
- or type(runtime) not in {int, long, type(None)}):
- return
-
- self.__times = times
-
- def get_test_time(self, binary, testname):
- """Return the last duration for the given test as an integer number of
- milliseconds, or None if the test failed or if there's no record for it."""
- return self.__times.get((binary, testname), None)
-
- def record_test_time(self, binary, testname, runtime_ms):
- """Record that the given test ran in the specified number of
- milliseconds. If the test failed, runtime_ms should be None."""
- with self.__lock:
- self.__times[(binary, testname)] = runtime_ms
-
- def write_to_file(self, save_file):
- "Write all the times to file."
- try:
- with open(save_file, "wb") as f:
- with gzip.GzipFile("", "wb", 9, f) as gzf:
- cPickle.dump(self.__times, gzf, cPickle.HIGHEST_PROTOCOL)
- except IOError:
- pass # ignore errors---saving the times isn't that important
-
-# Remove additional arguments (anything after --).
-additional_args = []
-
-for i in range(len(sys.argv)):
- if sys.argv[i] == '--':
- additional_args = sys.argv[i+1:]
- sys.argv = sys.argv[:i]
- break
-
-parser = optparse.OptionParser(
- usage = 'usage: %prog [options] binary [binary ...] -- [additional args]')
-
-parser.add_option('-d', '--output_dir', type='string',
- default=os.path.join(tempfile.gettempdir(), "gtest-parallel"),
- help='output directory for test logs')
-parser.add_option('-r', '--repeat', type='int', default=1,
- help='repeat tests')
-parser.add_option('--failed', action='store_true', default=False,
- help='run only failed and new tests')
-parser.add_option('-w', '--workers', type='int',
- default=multiprocessing.cpu_count(),
- help='number of workers to spawn')
-parser.add_option('--gtest_color', type='string', default='yes',
- help='color output')
-parser.add_option('--gtest_filter', type='string', default='',
- help='test filter')
-parser.add_option('--gtest_also_run_disabled_tests', action='store_true',
- default=False, help='run disabled tests too')
-parser.add_option('--format', type='string', default='filter',
- help='output format (raw,filter)')
-parser.add_option('--print_test_times', action='store_true', default=False,
- help='list the run time of each test at the end of execution')
-parser.add_option('--shard_count', type='int', default=1,
- help='total number of shards (for sharding test execution '
- 'between multiple machines)')
-parser.add_option('--shard_index', type='int', default=0,
- help='zero-indexed number identifying this shard (for '
- 'sharding test execution between multiple machines)')
-parser.add_option('--dump_json_test_results', type='string', default=None,
- help='Saves the results of the tests as a JSON machine-'
- 'readable file. The format of the file is specified at '
- 'https://www.chromium.org/developers/the-json-test-results-format')
-
-(options, binaries) = parser.parse_args()
-
-if binaries == []:
- parser.print_usage()
- sys.exit(1)
-
-logger = RawFormat()
-if options.format == 'raw':
- pass
-elif options.format == 'filter':
- logger = FilterFormat()
-else:
- parser.error("Unknown output format: " + options.format)
-
-if options.shard_count < 1:
- parser.error("Invalid number of shards: %d. Must be at least 1." %
- options.shard_count)
-if not (0 <= options.shard_index < options.shard_count):
- parser.error("Invalid shard index: %d. Must be between 0 and %d "
- "(less than the number of shards)." %
- (options.shard_index, options.shard_count - 1))
-
-test_results = (IgnoreTestResults() if options.dump_json_test_results is None
- else CollectTestResults(options.dump_json_test_results))
-
-# Find tests.
-save_file = os.path.join(os.path.expanduser("~"), ".gtest-parallel-times")
-times = TestTimes(save_file)
-tests = []
-for test_binary in binaries:
- command = [test_binary]
- if options.gtest_also_run_disabled_tests:
- command += ['--gtest_also_run_disabled_tests']
-
- list_command = list(command)
- if options.gtest_filter != '':
- list_command += ['--gtest_filter=' + options.gtest_filter]
-
- try:
- test_list = subprocess.Popen(list_command + ['--gtest_list_tests'],
- stdout=subprocess.PIPE).communicate()[0]
- except OSError as e:
- sys.exit("%s: %s" % (test_binary, str(e)))
-
- command += additional_args
-
- test_group = ''
- for line in test_list.split('\n'):
- if not line.strip():
- continue
- if line[0] != " ":
- # Remove comments for typed tests and strip whitespace.
- test_group = line.split('#')[0].strip()
- continue
- # Remove comments for parameterized tests and strip whitespace.
- line = line.split('#')[0].strip()
- if not line:
- continue
-
- test = test_group + line
- if not options.gtest_also_run_disabled_tests and 'DISABLED_' in test:
- continue
- tests.append((times.get_test_time(test_binary, test),
- test_binary, test, command))
-
-tests = tests[options.shard_index::options.shard_count]
-
-if options.failed:
- # The first element of each entry is the runtime of the most recent
- # run if it was successful, or None if the test is new or the most
- # recent run failed.
- tests = [x for x in tests if x[0] is None]
-
-# Sort tests by falling runtime (with None, which is what we get for
-# new and failing tests, being considered larger than any real
-# runtime).
-tests.sort(reverse=True, key=lambda x: ((1 if x[0] is None else 0), x))
-
-# Repeat tests (-r flag).
-tests *= options.repeat
-test_lock = threading.Lock()
-job_id = 0
-logger.log(str(-1) + ': TESTCNT ' + ' ' + str(len(tests)))
-
-exit_code = 0
-
-# Create directory for test log output.
-try:
- os.makedirs(options.output_dir)
-except OSError as e:
- # Ignore errors if this directory already exists.
- if e.errno != errno.EEXIST or not os.path.isdir(options.output_dir):
- raise e
-# Remove files from old test runs.
-for logfile in os.listdir(options.output_dir):
- os.remove(os.path.join(options.output_dir, logfile))
-
-# Run the specified job. Return the elapsed time in milliseconds if
-# the job succeeds, or None if the job fails. (This ensures that
-# failing tests will run first the next time.)
-def run_job((command, job_id, test)):
- begin = time.time()
-
- with tempfile.NamedTemporaryFile(dir=options.output_dir, delete=False) as log:
- sub = subprocess.Popen(command + ['--gtest_filter=' + test] +
- ['--gtest_color=' + options.gtest_color],
- stdout=log.file,
- stderr=log.file)
- try:
- code = sigint_handler.wait(sub)
- except sigint_handler.ProcessWasInterrupted:
- thread.exit()
- runtime_ms = int(1000 * (time.time() - begin))
- logger.logfile(job_id, log.name)
-
- test_results.log(test, {
- "expected": "PASS",
- "actual": "PASS" if code == 0 else "FAIL",
- "time": runtime_ms,
- })
- logger.log("%s: EXIT %s %d" % (job_id, code, runtime_ms))
- if code == 0:
- return runtime_ms
- global exit_code
- exit_code = code
- return None
-
-def worker():
- global job_id
- while True:
- job = None
- test_lock.acquire()
- if job_id < len(tests):
- (_, test_binary, test, command) = tests[job_id]
- logger.log(str(job_id) + ': TEST ' + test_binary + ' ' + test)
- job = (command, job_id, test)
- job_id += 1
- test_lock.release()
- if job is None:
- return
- times.record_test_time(test_binary, test, run_job(job))
-
-def start_daemon(func):
- t = threading.Thread(target=func)
- t.daemon = True
- t.start()
- return t
-
-workers = [start_daemon(worker) for i in range(options.workers)]
-
-[t.join() for t in workers]
-logger.end()
-times.write_to_file(save_file)
-if options.print_test_times:
- ts = sorted((times.get_test_time(test_binary, test), test_binary, test)
- for (_, test_binary, test, _) in tests
- if times.get_test_time(test_binary, test) is not None)
- for (time_ms, test_binary, test) in ts:
- print "%8s %s" % ("%dms" % time_ms, test)
-
-test_results.dump_to_file_and_close()
-sys.exit(-signal.SIGINT if sigint_handler.got_sigint() else exit_code)
« no previous file with comments | « third_party/gtest-parallel/README.webrtc ('k') | third_party/gtest-parallel/gtest-parallel-wrapper.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698