0c2c61d2f1
* Added python test runner to execute rccl tests * Disabled capture output to avoid hangs * Add RCCL_TEST_MPI_HOSTFILE env var to get the hostfile * Converted test_type to boolean gtest flag * Removed unused return values * Added custom rccl library usage * Removed json output * Updates to test_runner: added num_gpus field * Address review comments * Prepend env vars for single node, single process executions * Added separate enums for exit and result codes * Update configuration files * Moved configurations to its own dir * Address review comments * Update tools/scripts/test_runner/README.md Co-authored-by: Corey Derochie <161367113+corey-derochie-amd@users.noreply.github.com> --------- Co-authored-by: Corey Derochie <161367113+corey-derochie-amd@users.noreply.github.com>
168 linhas
5.1 KiB
Python
168 linhas
5.1 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
#
|
|
# See LICENSE.txt for license information
|
|
"""
|
|
Test Parser Module
|
|
Handles command-line argument parsing and test output parsing
|
|
"""
|
|
|
|
import re
|
|
import argparse
|
|
|
|
|
|
class ArgumentParserInterface:
|
|
"""Command-line argument parser for RCCL test runner"""
|
|
|
|
def __init__(self):
|
|
self.parser = argparse.ArgumentParser(
|
|
description="RCCL Test Runner - Execute and manage RCCL unit tests and MPI tests",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
# Run all tests from config
|
|
%(prog)s -c test_config.json
|
|
|
|
# Run specific test
|
|
%(prog)s -c test_config.json --test-name NET_AllTests_2Nodes_ETH
|
|
|
|
# Run with verbose output
|
|
%(prog)s -c test_config.json -v
|
|
|
|
# Skip build and use existing build
|
|
%(prog)s -c test_config.json --no-build
|
|
|
|
# Generate coverage report from existing data
|
|
%(prog)s -c test_config.json --no-build --skip-tests --coverage-report
|
|
"""
|
|
)
|
|
|
|
def add_arguments(self):
|
|
"""Add all command-line arguments"""
|
|
self.parser.add_argument(
|
|
'-c', '--config',
|
|
type=str,
|
|
required=True,
|
|
help="Test configuration file (JSON format)"
|
|
)
|
|
self.parser.add_argument(
|
|
'-v', '--verbose',
|
|
action='store_true',
|
|
help="Enable verbose output (detailed logging)"
|
|
)
|
|
self.parser.add_argument(
|
|
'-o', '--output',
|
|
type=str,
|
|
help="Output directory for logs and reports (default: auto-generated)"
|
|
)
|
|
self.parser.add_argument(
|
|
'--test-name',
|
|
type=str,
|
|
help="Run only specific test by name"
|
|
)
|
|
self.parser.add_argument(
|
|
'--no-build',
|
|
action='store_true',
|
|
help="Skip build step and use existing build artifacts"
|
|
)
|
|
self.parser.add_argument(
|
|
'--skip-tests',
|
|
action='store_true',
|
|
help="Skip test execution (useful with --coverage-report)"
|
|
)
|
|
self.parser.add_argument(
|
|
'--coverage-report',
|
|
action='store_true',
|
|
help="Generate code coverage report from profraw files"
|
|
)
|
|
self.parser.add_argument(
|
|
'--overwrite',
|
|
action='store_true',
|
|
help="Overwrite previous build/log directories (default: append timestamp)"
|
|
)
|
|
self.parser.add_argument(
|
|
'--report-suffix',
|
|
type=str,
|
|
default='',
|
|
help="Suffix for report directory name (default: blank)"
|
|
)
|
|
|
|
def parse_arguments(self):
|
|
"""Parse command-line arguments"""
|
|
return self.parser.parse_args()
|
|
|
|
def process_arguments(self):
|
|
"""Process and validate command-line arguments"""
|
|
self.add_arguments()
|
|
args = self.parse_arguments()
|
|
self.handle_arguments(args)
|
|
return args
|
|
|
|
def handle_arguments(self, args):
|
|
"""Handle and display parsed arguments"""
|
|
if args.verbose:
|
|
print("="*80)
|
|
print("RCCL Test Runner - Configuration")
|
|
print("="*80)
|
|
print(f"Config file: {args.config}")
|
|
print(f"Verbose mode: {args.verbose}")
|
|
print(f"Output dir: {args.output if args.output else 'auto-generated'}")
|
|
print(f"Test name filter: {args.test_name if args.test_name else 'all tests'}")
|
|
print(f"No build: {args.no_build}")
|
|
print(f"Skip tests: {args.skip_tests}")
|
|
print(f"Coverage report: {args.coverage_report}")
|
|
print(f"Overwrite: {args.overwrite}")
|
|
print(f"Report suffix: {args.report_suffix}")
|
|
print("="*80)
|
|
print()
|
|
|
|
|
|
def parse_test_output(output):
|
|
"""
|
|
Parse test output and extract results
|
|
|
|
Args:
|
|
output: String containing test output
|
|
|
|
Returns:
|
|
dict: Parsed test results including pass/fail status
|
|
"""
|
|
results = {
|
|
'passed': False,
|
|
'failed': False,
|
|
'skipped': False,
|
|
'tests_run': 0,
|
|
'tests_passed': 0,
|
|
'tests_failed': 0,
|
|
'errors': []
|
|
}
|
|
|
|
# Google Test output patterns
|
|
gtest_passed = re.search(r'\[\s*PASSED\s*\]\s*(\d+)\s*test', output)
|
|
gtest_failed = re.search(r'\[\s*FAILED\s*\]\s*(\d+)\s*test', output)
|
|
gtest_run = re.search(r'\[==========\]\s*(\d+)\s*test.*ran', output)
|
|
|
|
if gtest_run:
|
|
results['tests_run'] = int(gtest_run.group(1))
|
|
|
|
if gtest_passed:
|
|
results['tests_passed'] = int(gtest_passed.group(1))
|
|
|
|
if gtest_failed:
|
|
results['tests_failed'] = int(gtest_failed.group(1))
|
|
results['failed'] = True
|
|
else:
|
|
results['passed'] = results['tests_run'] > 0
|
|
|
|
# Check for skipped tests
|
|
if 'SKIPPED' in output or 'Skipped' in output:
|
|
results['skipped'] = True
|
|
|
|
# Extract error messages
|
|
error_pattern = re.compile(r'(ERROR|FAILED|TIMEOUT).*', re.MULTILINE)
|
|
errors = error_pattern.findall(output)
|
|
results['errors'] = errors[:10] # Limit to first 10 errors
|
|
|
|
return results
|
|
|