120 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
#!/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')
 |