Skip to content

Commit 5c88cbb

Browse files
committed
issue/594 - cumulating total time in tests
1 parent d2afb65 commit 5c88cbb

File tree

4 files changed

+126
-17
lines changed

4 files changed

+126
-17
lines changed

test/infinicore/framework/base.py

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

55
from abc import ABC, abstractmethod
66
from typing import List, Dict, Any, Optional
@@ -12,8 +12,6 @@
1212
create_test_comparator,
1313
infinicore_tensor_from_torch,
1414
profile_operation,
15-
synchronize_device,
16-
convert_infinicore_to_torch,
1715
)
1816

1917

@@ -244,6 +242,12 @@ def __init__(self, test_cases, test_config):
244242
self.passed_tests = (
245243
[]
246244
) # Track passed tests (both operators implemented and passed)
245+
# Add benchmark timing statistics
246+
self.benchmark_times = {
247+
"torch_total": 0.0,
248+
"infinicore_total": 0.0,
249+
"per_test_case": {}, # Store timing per test case
250+
}
247251

248252
def run_tests(self, devices, test_func, test_type="Test"):
249253
"""
@@ -344,9 +348,35 @@ def print_summary(self):
344348
else:
345349
print(f"\n\033[92mAll tests passed!\033[0m")
346350

351+
# Print benchmark summary if benchmarking was enabled
352+
if self.config.bench and (
353+
self.benchmark_times["torch_total"] > 0
354+
or self.benchmark_times["infinicore_total"] > 0
355+
):
356+
self._print_benchmark_summary()
357+
347358
print(f"{'='*60}")
348359
return result
349360

361+
def _print_benchmark_summary(self):
362+
"""Print benchmark timing summary"""
363+
print(f"{'-'*60}")
364+
print("BENCHMARK SUMMARY")
365+
366+
torch_total = self.benchmark_times["torch_total"]
367+
infinicore_total = self.benchmark_times["infinicore_total"]
368+
369+
if torch_total > 0:
370+
print(f"PyTorch Total Time: {torch_total * 1000:.3f} ms")
371+
if infinicore_total > 0:
372+
print(f"InfiniCore Total Time: {infinicore_total * 1000:.3f} ms")
373+
374+
if torch_total > 0 and infinicore_total > 0:
375+
speedup = (
376+
torch_total / infinicore_total if infinicore_total > 0 else float("inf")
377+
)
378+
print(f"Speedup (PyTorch/InfiniCore): {speedup:.2f}x")
379+
350380

351381
class BaseOperatorTest(ABC):
352382
"""Base operator test"""
@@ -711,8 +741,13 @@ def _run_benchmarking(
711741
comparison_target,
712742
):
713743
"""
714-
Unified benchmarking logic
744+
Unified benchmarking logic with timing accumulation
715745
"""
746+
747+
# Initialize timing variables
748+
torch_time = 0.0
749+
infini_time = 0.0
750+
716751
if torch_implemented:
717752
if output_count > 1:
718753
# For multiple outputs, just call the operator
@@ -735,12 +770,13 @@ def torch_op():
735770
else inputs[comparison_target]
736771
)
737772

738-
profile_operation(
773+
torch_time = profile_operation(
739774
"PyTorch ",
740775
torch_op,
741776
device_str,
742777
config.num_prerun,
743778
config.num_iterations,
779+
total=True,
744780
)
745781

746782
if infini_implemented:
@@ -759,10 +795,17 @@ def infini_op():
759795
else infini_inputs[comparison_target]
760796
)
761797

762-
profile_operation(
798+
infini_time = profile_operation(
763799
"InfiniCore",
764800
infini_op,
765801
device_str,
766802
config.num_prerun,
767803
config.num_iterations,
804+
total=True,
768805
)
806+
807+
# Store timing information in the test runner
808+
if hasattr(config, "_test_runner") and config._test_runner:
809+
# Accumulate total times
810+
config._test_runner.benchmark_times["torch_total"] += torch_time
811+
config._test_runner.benchmark_times["infinicore_total"] += infini_time

test/infinicore/framework/runner.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ def run(self):
3232
)
3333

3434
runner = TestRunner(self.operator_test.test_cases, config)
35+
36+
# Pass the test runner instance to config for benchmark timing accumulation
37+
config._test_runner = runner
38+
3539
devices = get_test_devices(self.args)
3640

3741
# Run unified tests - returns True if no tests failed

test/infinicore/framework/utils.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ def timed_op(func, num_iterations, device):
2222
for _ in range(num_iterations):
2323
func()
2424
synchronize_device(device)
25-
return (time.time() - start) / num_iterations
25+
return time.time() - start
2626

2727

28-
def profile_operation(desc, func, torch_device, num_prerun, num_iterations):
28+
def profile_operation(
29+
desc, func, torch_device, num_prerun, num_iterations, total=False
30+
):
2931
"""
3032
Performance profiling workflow
3133
"""
@@ -35,7 +37,11 @@ def profile_operation(desc, func, torch_device, num_prerun, num_iterations):
3537

3638
# Timed execution
3739
elapsed = timed_op(lambda: func(), num_iterations, torch_device)
38-
print(f" {desc} time: {elapsed * 1000 :6f} ms")
40+
print(f" {desc} time: {elapsed / num_iterations * 1000 :6f} ms")
41+
if total:
42+
return elapsed
43+
else:
44+
return elapsed / num_iterations
3945

4046

4147
def debug(actual, desired, atol=0, rtol=1e-2, equal_nan=False, verbose=True):

test/infinicore/run.py

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ def run_all_op_tests(ops_dir=None, specific_ops=None, extra_args=None):
125125
# Check if verbose mode is enabled
126126
verbose_mode = extra_args and "--verbose" in extra_args
127127

128+
# Check if bench mode is enabled for cumulative timing
129+
bench_mode = extra_args and "--bench" in extra_args
130+
cumulative_timing = {
131+
"total_torch_time": 0.0,
132+
"total_infinicore_time": 0.0,
133+
"operators_tested": 0,
134+
}
135+
128136
for test_file in operator_test_files:
129137
test_name = test_file.stem
130138

@@ -157,7 +165,7 @@ def run_all_op_tests(ops_dir=None, specific_ops=None, extra_args=None):
157165
# Both operators not implemented - skipped test
158166
success = False # Not a failure, but skipped
159167
returncode = -2 # Special code for skipped
160-
elif "one operator not implemented" in stdout_lower:
168+
elif "operator not implemented" in stdout_lower:
161169
# One operator not implemented - partial test
162170
success = False # Not fully successful
163171
returncode = -3 # Special code for partial
@@ -202,6 +210,34 @@ def run_all_op_tests(ops_dir=None, specific_ops=None, extra_args=None):
202210
f"{status_icon} {test_name}: {status_text} (return code: {returncode})"
203211
)
204212

213+
# Extract benchmark timing if in bench mode
214+
if bench_mode and success:
215+
# Look for benchmark summary in stdout
216+
lines = result.stdout.split("\n")
217+
torch_time = 0.0
218+
infini_time = 0.0
219+
220+
for line in lines:
221+
if "PyTorch Total Time:" in line:
222+
try:
223+
# Extract time value (e.g., "PyTorch Total Time: 123.456 ms")
224+
torch_time = (
225+
float(line.split(":")[1].strip().split()[0]) / 1000.0
226+
) # Convert to seconds
227+
except:
228+
pass
229+
elif "InfiniCore Total Time:" in line:
230+
try:
231+
infini_time = (
232+
float(line.split(":")[1].strip().split()[0]) / 1000.0
233+
) # Convert to seconds
234+
except:
235+
pass
236+
237+
cumulative_timing["total_torch_time"] += torch_time
238+
cumulative_timing["total_infinicore_time"] += infini_time
239+
cumulative_timing["operators_tested"] += 1
240+
205241
# In verbose mode, stop execution on first failure
206242
if verbose_mode and not success and returncode not in [-2, -3]:
207243
break
@@ -219,11 +255,13 @@ def run_all_op_tests(ops_dir=None, specific_ops=None, extra_args=None):
219255
print(f"{'!'*60}")
220256
break
221257

222-
return results
258+
return results, cumulative_timing
223259

224260

225-
def print_summary(results, verbose_mode=False, total_expected_tests=0):
226-
"""Print a comprehensive summary of test results."""
261+
def print_summary(
262+
results, verbose_mode=False, total_expected_tests=0, cumulative_timing=None
263+
):
264+
"""Print a comprehensive summary of test results including benchmark data."""
227265
print(f"\n{'='*80}")
228266
print("CUMULATIVE TEST SUMMARY")
229267
print(f"{'='*80}")
@@ -272,6 +310,19 @@ def print_summary(results, verbose_mode=False, total_expected_tests=0):
272310
if partial > 0:
273311
print(f"Partial: {partial}")
274312

313+
# Print benchmark summary if cumulative_timing data is available
314+
if cumulative_timing and cumulative_timing["operators_tested"] > 0:
315+
print(f"{'-'*40}")
316+
print("BENCHMARK SUMMARY:")
317+
print(f" Operators Tested: {cumulative_timing['operators_tested']}")
318+
print(
319+
f" Total PyTorch Time: {cumulative_timing['total_torch_time'] * 1000:.3f} ms"
320+
)
321+
print(
322+
f" Total InfiniCore Time: {cumulative_timing['total_infinicore_time'] * 1000:.3f} ms"
323+
)
324+
print(f"{'-'*40}")
325+
275326
# Display passed operators
276327
if passed_operators:
277328
print(f"\n✅ PASSED OPERATORS ({len(passed_operators)}):")
@@ -304,7 +355,7 @@ def print_summary(results, verbose_mode=False, total_expected_tests=0):
304355
print(" " + ", ".join(line_ops))
305356

306357
if total > 0:
307-
# Calculate success rate based on executed tests only
358+
# Calculate success rate based on actual executed tests
308359
executed_tests = passed + failed + partial
309360
if executed_tests > 0:
310361
success_rate = passed / executed_tests * 100
@@ -387,6 +438,9 @@ def generate_help_epilog(ops_dir):
387438
)
388439
epilog_parts.append(" python run.py --cpu --nvidia --verbose")
389440
epilog_parts.append("")
441+
epilog_parts.append(" # Run with benchmarking to get cumulative timing")
442+
epilog_parts.append(" python run.py --cpu --bench")
443+
epilog_parts.append("")
390444
epilog_parts.append(" # List available tests without running")
391445
epilog_parts.append(" python run.py --list")
392446
epilog_parts.append("")
@@ -413,7 +467,7 @@ def generate_help_epilog(ops_dir):
413467
" - Operators are automatically discovered from the ops directory"
414468
)
415469
epilog_parts.append(
416-
" - --bench option is disabled in batch mode (run individual tests for benchmarking)"
470+
" - --bench mode now shows cumulative timing across all operators"
417471
)
418472
epilog_parts.append(
419473
" - --verbose mode stops execution on first error and shows full traceback"
@@ -527,14 +581,16 @@ def main():
527581
print()
528582

529583
# Run all tests
530-
results = run_all_op_tests(
584+
results, cumulative_timing = run_all_op_tests(
531585
ops_dir=ops_dir,
532586
specific_ops=args.ops,
533587
extra_args=unknown_args,
534588
)
535589

536590
# Print summary and exit with appropriate code
537-
all_passed = print_summary(results, args.verbose, total_expected_tests)
591+
all_passed = print_summary(
592+
results, args.verbose, total_expected_tests, cumulative_timing
593+
)
538594

539595
# Check if there were any tests with missing implementations
540596
has_missing_implementations = any(

0 commit comments

Comments
 (0)