2020-07-15 15:31:13 +08:00
|
|
|
#!/usr/bin/env python3
|
2020-04-16 01:24:34 +08:00
|
|
|
|
|
|
|
from multiprocessing import Pool
|
|
|
|
import multiprocessing
|
|
|
|
import argparse
|
|
|
|
import tempfile
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
|
|
|
def run_reproducer(path):
|
|
|
|
proc = subprocess.Popen([LLDB, '--replay', path],
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE)
|
|
|
|
reason = None
|
|
|
|
try:
|
|
|
|
outs, errs = proc.communicate(timeout=TIMEOUT)
|
2020-04-22 02:29:47 +08:00
|
|
|
success = proc.returncode == 0
|
2020-04-20 23:52:07 +08:00
|
|
|
result = 'PASSED' if success else 'FAILED'
|
|
|
|
if not success:
|
2020-04-16 01:24:34 +08:00
|
|
|
outs = outs.decode()
|
|
|
|
errs = errs.decode()
|
|
|
|
# Do some pattern matching to find out the cause of the failure.
|
|
|
|
if 'Encountered unexpected packet during replay' in errs:
|
|
|
|
reason = 'Unexpected packet'
|
|
|
|
elif 'Assertion failed' in errs:
|
|
|
|
reason = 'Assertion failed'
|
|
|
|
elif 'UNREACHABLE' in errs:
|
|
|
|
reason = 'Unreachable executed'
|
|
|
|
elif 'Segmentation fault' in errs:
|
|
|
|
reason = 'Segmentation fault'
|
|
|
|
elif 'Illegal instruction' in errs:
|
|
|
|
reason = 'Illegal instruction'
|
|
|
|
else:
|
|
|
|
reason = f'Exit code {proc.returncode}'
|
|
|
|
except subprocess.TimeoutExpired:
|
|
|
|
proc.kill()
|
2020-04-20 23:52:07 +08:00
|
|
|
success = False
|
2020-04-16 01:24:34 +08:00
|
|
|
outs, errs = proc.communicate()
|
|
|
|
result = 'TIMEOUT'
|
|
|
|
|
2020-04-20 23:52:07 +08:00
|
|
|
if not FAILURE_ONLY or not success:
|
|
|
|
reason_str = f' ({reason})' if reason else ''
|
|
|
|
print(f'{result}: {path}{reason_str}')
|
|
|
|
if VERBOSE:
|
|
|
|
if outs:
|
|
|
|
print(outs)
|
|
|
|
if errs:
|
|
|
|
print(errs)
|
2020-04-16 01:24:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
def find_reproducers(path):
|
|
|
|
for root, dirs, files in os.walk(path):
|
|
|
|
for dir in dirs:
|
|
|
|
_, extension = os.path.splitext(dir)
|
|
|
|
if dir.startswith('Test') and extension == '.py':
|
|
|
|
yield os.path.join(root, dir)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description='LLDB API Test Replay Driver. '
|
|
|
|
'Replay one or more reproducers in parallel using the specified LLDB driver. '
|
|
|
|
'The script will look for reproducers generated by the API lit test suite. '
|
|
|
|
'To generate the reproducers, pass --param \'lldb-run-with-repro=capture\' to lit.'
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
'-j',
|
|
|
|
'--threads',
|
|
|
|
type=int,
|
|
|
|
default=multiprocessing.cpu_count(),
|
|
|
|
help='Number of threads. The number of CPU threads if not specified.')
|
|
|
|
parser.add_argument(
|
|
|
|
'-t',
|
|
|
|
'--timeout',
|
|
|
|
type=int,
|
|
|
|
default=60,
|
|
|
|
help='Replay timeout in seconds. 60 seconds if not specified.')
|
|
|
|
parser.add_argument(
|
|
|
|
'-p',
|
|
|
|
'--path',
|
|
|
|
type=str,
|
|
|
|
default=os.getcwd(),
|
|
|
|
help=
|
|
|
|
'Path to the directory containing the reproducers. The current working directory if not specified.'
|
|
|
|
)
|
|
|
|
parser.add_argument('-l',
|
|
|
|
'--lldb',
|
|
|
|
type=str,
|
|
|
|
required=True,
|
|
|
|
help='Path to the LLDB command line driver')
|
2020-04-20 23:52:07 +08:00
|
|
|
parser.add_argument('-v',
|
|
|
|
'--verbose',
|
|
|
|
help='Print replay output.',
|
|
|
|
action='store_true')
|
|
|
|
parser.add_argument('--failure-only',
|
|
|
|
help='Only log failures.',
|
|
|
|
action='store_true')
|
2020-04-16 01:24:34 +08:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
global LLDB
|
|
|
|
global TIMEOUT
|
2020-04-20 23:52:07 +08:00
|
|
|
global VERBOSE
|
|
|
|
global FAILURE_ONLY
|
2020-04-16 01:24:34 +08:00
|
|
|
LLDB = args.lldb
|
|
|
|
TIMEOUT = args.timeout
|
2020-04-20 23:52:07 +08:00
|
|
|
VERBOSE = args.verbose
|
|
|
|
FAILURE_ONLY = args.failure_only
|
2020-04-16 01:24:34 +08:00
|
|
|
|
|
|
|
print(
|
|
|
|
f'Replaying reproducers in {args.path} with {args.threads} threads and a {args.timeout} seconds timeout'
|
|
|
|
)
|
|
|
|
|
|
|
|
try:
|
|
|
|
pool = Pool(args.threads)
|
|
|
|
pool.map(run_reproducer, find_reproducers(args.path))
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
print('Interrupted')
|