Skip to content

Commit d2afb65

Browse files
committed
issue/593 - added verbose test mode
1 parent 576b755 commit d2afb65

File tree

4 files changed

+102
-36
lines changed

4 files changed

+102
-36
lines changed

test/infinicore/framework/base.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import torch
22
import infinicore
3+
import traceback # Add import for traceback
34

45
from abc import ABC, abstractmethod
56
from typing import List, Dict, Any, Optional
@@ -216,14 +217,19 @@ def __str__(self):
216217
class TestConfig:
217218
"""Test configuration"""
218219

219-
def __init__(self, debug=False, bench=False, num_prerun=10, num_iterations=1000):
220+
def __init__(
221+
self,
222+
debug=False,
223+
bench=False,
224+
num_prerun=10,
225+
num_iterations=1000,
226+
verbose=False,
227+
):
220228
self.debug = debug
221229
self.bench = bench
222230
self.num_prerun = num_prerun
223231
self.num_iterations = num_iterations
224-
225-
226-
# In base.py - update the TestRunner class
232+
self.verbose = verbose
227233

228234

229235
class TestRunner:
@@ -273,16 +279,11 @@ def run_tests(self, devices, test_func, test_type="Test"):
273279
# Test was skipped due to both operators not being implemented
274280
skip_msg = f"{test_case} - {InfiniDeviceNames[device]} - Both operators not implemented"
275281
self.skipped_tests.append(skip_msg)
276-
print(
277-
f"\033[93m⚠\033[0m Skipped - both operators not implemented"
278-
)
279282
elif status == "partial":
280283
# Test was partially executed (one operator not implemented)
281284
partial_msg = f"{test_case} - {InfiniDeviceNames[device]} - One operator not implemented"
282285
self.partial_tests.append(partial_msg)
283-
print(
284-
f"\033[93m⚠\033[0m Partial - one operator not implemented"
285-
)
286+
286287
# Failed tests are handled in the exception handler below
287288

288289
except Exception as e:
@@ -291,6 +292,12 @@ def run_tests(self, devices, test_func, test_type="Test"):
291292
)
292293
print(f"\033[91m✗\033[0m {error_msg}")
293294
self.failed_tests.append(error_msg)
295+
296+
# In verbose mode, print full traceback and stop execution
297+
if self.config.verbose:
298+
traceback.print_exc()
299+
return False # Stop test execution immediately
300+
294301
if self.config.debug:
295302
raise
296303

@@ -312,34 +319,16 @@ def print_summary(self):
312319

313320
print(f"\n{'='*60}")
314321
print("TEST SUMMARY")
315-
print(f"{'='*60}")
316322
print(f"Total tests: {total_tests}")
317323
print(f"\033[92mPassed: {passed_count}\033[0m")
318324

319-
# Display partial tests (one operator not implemented)
320-
if self.partial_tests:
321-
print(
322-
f"\033[93mPartial (one operator not implemented): {partial_count}\033[0m"
323-
)
324-
for test in self.partial_tests:
325-
print(f" - {test}")
326-
327-
# Display skipped tests (both operators not implemented)
328-
if self.skipped_tests:
329-
print(
330-
f"\033[93mSkipped (both operators not implemented): {skipped_count}\033[0m"
331-
)
332-
for test in self.skipped_tests:
333-
print(f" - {test}")
334-
325+
result = True
335326
# Display failed tests
336327
if self.failed_tests:
337328
print(f"\033[91mFailed: {failed_count}\033[0m")
338-
for failure in self.failed_tests:
339-
print(f" - {failure}")
340329

341330
# Return False only if there are actual test failures
342-
return False
331+
result = False
343332
else:
344333
# Calculate success rate based on actual executed tests
345334
executed_tests = passed_count + partial_count + failed_count
@@ -352,10 +341,11 @@ def print_summary(self):
352341
print(
353342
f"\n\033[93mTests completed with some implementations missing\033[0m"
354343
)
355-
return True # Skipped/partial tests don't count as failures
356344
else:
357345
print(f"\n\033[92mAll tests passed!\033[0m")
358-
return True
346+
347+
print(f"{'='*60}")
348+
return result
359349

360350

361351
class BaseOperatorTest(ABC):
@@ -537,6 +527,9 @@ def run_test(self, device, test_case, config):
537527
if torch_result is None:
538528
torch_implemented = False
539529
except NotImplementedError:
530+
if config.verbose:
531+
traceback.print_exc()
532+
return False # Stop test execution immediately
540533
torch_implemented = False
541534
torch_result = None
542535

@@ -545,6 +538,9 @@ def run_test(self, device, test_case, config):
545538
if infini_result is None:
546539
infini_implemented = False
547540
except NotImplementedError:
541+
if config.verbose:
542+
traceback.print_exc()
543+
return False # Stop test execution immediately
548544
infini_implemented = False
549545
infini_result = None
550546

test/infinicore/framework/config.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import argparse
22
from .devices import InfiniDeviceEnum
33

4-
# hardware_info.py
54
"""
65
Shared hardware platform information for the InfiniCore testing framework
76
"""
@@ -61,6 +60,9 @@ def get_args():
6160
# Run with debug mode on multiple devices
6261
python test_operator.py --cpu --nvidia --debug
6362
63+
# Run with verbose mode to stop on first error with full traceback
64+
python test_operator.py --cpu --nvidia --verbose
65+
6466
# Run performance profiling with custom iterations
6567
python test_operator.py --nvidia --bench --num_prerun 50 --num_iterations 5000
6668
@@ -90,6 +92,11 @@ def get_args():
9092
action="store_true",
9193
help="Enable debug mode for detailed tensor comparison",
9294
)
95+
parser.add_argument(
96+
"--verbose",
97+
action="store_true",
98+
help="Enable verbose mode to stop on first error with full traceback",
99+
)
93100

94101
# Device options using shared hardware info
95102
hardware_group = get_hardware_args_group(parser)

test/infinicore/framework/runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def run(self):
2828
bench=self.args.bench,
2929
num_prerun=self.args.num_prerun,
3030
num_iterations=self.args.num_iterations,
31+
verbose=self.args.verbose, # Pass verbose flag to TestConfig
3132
)
3233

3334
runner = TestRunner(self.operator_test.test_cases, config)

test/infinicore/run.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ def run_all_op_tests(ops_dir=None, specific_ops=None, extra_args=None):
122122

123123
results = {}
124124

125+
# Check if verbose mode is enabled
126+
verbose_mode = extra_args and "--verbose" in extra_args
127+
125128
for test_file in operator_test_files:
126129
test_name = test_file.stem
127130

@@ -199,14 +202,27 @@ def run_all_op_tests(ops_dir=None, specific_ops=None, extra_args=None):
199202
f"{status_icon} {test_name}: {status_text} (return code: {returncode})"
200203
)
201204

205+
# In verbose mode, stop execution on first failure
206+
if verbose_mode and not success and returncode not in [-2, -3]:
207+
break
208+
202209
except Exception as e:
203210
print(f"💥 {test_name}: ERROR - {str(e)}")
204211
results[test_name] = (False, -1, "", str(e))
205212

213+
# In verbose mode, stop execution on any exception
214+
if verbose_mode:
215+
print(f"\n{'!'*60}")
216+
print(
217+
f"VERBOSE MODE: Stopping execution due to exception in {test_name}"
218+
)
219+
print(f"{'!'*60}")
220+
break
221+
206222
return results
207223

208224

209-
def print_summary(results):
225+
def print_summary(results, verbose_mode=False, total_expected_tests=0):
210226
"""Print a comprehensive summary of test results."""
211227
print(f"\n{'='*80}")
212228
print("CUMULATIVE TEST SUMMARY")
@@ -242,7 +258,11 @@ def print_summary(results):
242258

243259
total = len(results)
244260

245-
print(f"Total tests: {total}")
261+
print(f"Total tests run: {total}")
262+
if total_expected_tests > 0 and total < total_expected_tests:
263+
print(f"Total tests expected: {total_expected_tests}")
264+
print(f"Tests not executed: {total_expected_tests - total}")
265+
246266
print(f"Passed: {passed}")
247267
print(f"Failed: {failed}")
248268

@@ -290,6 +310,10 @@ def print_summary(results):
290310
success_rate = passed / executed_tests * 100
291311
print(f"\nSuccess rate: {success_rate:.1f}%")
292312

313+
if verbose_mode and total < total_expected_tests:
314+
print(f"\n💡 Verbose mode: Execution stopped after first failure")
315+
print(f" {total_expected_tests - total} tests were not executed")
316+
293317
if failed == 0:
294318
if skipped > 0 or partial > 0:
295319
print(f"\n⚠️ Tests completed with some operators not implemented")
@@ -358,6 +382,11 @@ def generate_help_epilog(ops_dir):
358382
epilog_parts.append(" # Run with debug mode on multiple devices")
359383
epilog_parts.append(" python run.py --cpu --nvidia --debug")
360384
epilog_parts.append("")
385+
epilog_parts.append(
386+
" # Run with verbose mode to stop on first error with full traceback"
387+
)
388+
epilog_parts.append(" python run.py --cpu --nvidia --verbose")
389+
epilog_parts.append("")
361390
epilog_parts.append(" # List available tests without running")
362391
epilog_parts.append(" python run.py --list")
363392
epilog_parts.append("")
@@ -386,6 +415,12 @@ def generate_help_epilog(ops_dir):
386415
epilog_parts.append(
387416
" - --bench option is disabled in batch mode (run individual tests for benchmarking)"
388417
)
418+
epilog_parts.append(
419+
" - --verbose mode stops execution on first error and shows full traceback"
420+
)
421+
epilog_parts.append(
422+
" - In verbose mode, subsequent tests are skipped after first failure"
423+
)
389424

390425
return "\n".join(epilog_parts)
391426

@@ -413,6 +448,11 @@ def main():
413448
action="store_true",
414449
help="List all available test files without running them",
415450
)
451+
parser.add_argument(
452+
"--verbose",
453+
action="store_true",
454+
help="Enable verbose mode to stop on first error with full traceback (passed to individual tests)",
455+
)
416456

417457
from framework import get_hardware_args_group
418458

@@ -442,6 +482,10 @@ def main():
442482
print(f"Error: Ops directory '{ops_dir}' does not exist.")
443483
sys.exit(1)
444484

485+
# Add verbose flag to extra arguments if specified
486+
if args.verbose and "--verbose" not in unknown_args:
487+
unknown_args.append("--verbose")
488+
445489
# Show what extra arguments will be passed
446490
if unknown_args:
447491
print(f"Passing extra arguments to test scripts: {unknown_args}")
@@ -453,6 +497,9 @@ def main():
453497
print(f"Operating directory: {ops_dir}")
454498
print(f"Available operators: {len(available_operators)}")
455499

500+
if args.verbose:
501+
print(f"Verbose mode: ENABLED (will stop on first error with full traceback)")
502+
456503
if args.ops:
457504
# Validate requested operators
458505
valid_ops = []
@@ -469,10 +516,13 @@ def main():
469516

470517
if valid_ops:
471518
print(f"Testing operators: {', '.join(valid_ops)}")
519+
total_expected_tests = len(valid_ops)
472520
else:
473521
print("No valid operators specified. Running all available tests.")
522+
total_expected_tests = len(available_operators)
474523
else:
475524
print("Testing all available operators")
525+
total_expected_tests = len(available_operators)
476526

477527
print()
478528

@@ -484,7 +534,7 @@ def main():
484534
)
485535

486536
# Print summary and exit with appropriate code
487-
all_passed = print_summary(results)
537+
all_passed = print_summary(results, args.verbose, total_expected_tests)
488538

489539
# Check if there were any tests with missing implementations
490540
has_missing_implementations = any(
@@ -495,6 +545,18 @@ def main():
495545
print(f"\n⚠️ Note: Some operators are not fully implemented")
496546
print(f" Run individual tests for details on missing implementations")
497547

548+
if args.verbose and not all_passed:
549+
print(
550+
f"\n💡 Verbose mode tip: Use individual test commands for detailed debugging:"
551+
)
552+
failed_ops = [
553+
name
554+
for name, (success, _, _, _) in results.items()
555+
if not success and name in results
556+
]
557+
for op in failed_ops[:3]: # Show first 3 failed operators
558+
print(f" python {ops_dir / (op + '.py')} --verbose")
559+
498560
sys.exit(0 if all_passed else 1)
499561

500562

0 commit comments

Comments
 (0)