llvm-project/lldb/scripts/reproducer-replay.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

120 lines
3.8 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
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)
success = proc.returncode == 0
result = 'PASSED' if success else 'FAILED'
if not success:
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()
success = False
outs, errs = proc.communicate()
result = 'TIMEOUT'
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)
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')
parser.add_argument('-v',
'--verbose',
help='Print replay output.',
action='store_true')
parser.add_argument('--failure-only',
help='Only log failures.',
action='store_true')
args = parser.parse_args()
global LLDB
global TIMEOUT
global VERBOSE
global FAILURE_ONLY
LLDB = args.lldb
TIMEOUT = args.timeout
VERBOSE = args.verbose
FAILURE_ONLY = args.failure_only
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')