2424import tempfile
2525from pathlib import Path
2626
27- from utils import BenchmarkSuite , create_test_array , run_benchmark
27+ from utils import (
28+ DEFAULT_MIN_DURATION_S ,
29+ BenchmarkSuite ,
30+ create_test_array ,
31+ run_benchmark ,
32+ )
2833
2934# Path to the no-op tesseract for benchmarking
3035NOOP_TESSERACT_PATH = Path (__file__ ).parent / "tesseract_noop" / "tesseract_api.py"
@@ -74,9 +79,10 @@ def _build_noop_tesseract() -> str | None:
7479
7580
7681def benchmark_from_tesseract_api (
77- iterations : int = 50 ,
82+ min_iterations : int | None = None ,
7883 array_sizes : list [int ] | None = None ,
7984 profile : bool = False ,
85+ min_duration_s : float = DEFAULT_MIN_DURATION_S ,
8086) -> BenchmarkSuite :
8187 """Benchmark non-containerized Tesseract via from_tesseract_api().
8288
@@ -90,7 +96,7 @@ def benchmark_from_tesseract_api(
9096
9197 suite = BenchmarkSuite (
9298 name = "from_tesseract_api" ,
93- metadata = {"iterations " : iterations , "array_sizes" : array_sizes },
99+ metadata = {"min_iterations " : min_iterations , "array_sizes" : array_sizes },
94100 )
95101
96102 with tempfile .TemporaryDirectory () as tmpdir :
@@ -114,18 +120,20 @@ def call_apply(t=tesseract, inp=inputs):
114120 result = run_benchmark (
115121 name = f"apply_{ size :,} " ,
116122 func = call_apply ,
117- iterations = iterations ,
123+ min_iterations = min_iterations ,
118124 profile = profile ,
125+ min_duration_s = min_duration_s ,
119126 )
120127 suite .add_result (result )
121128
122129 return suite
123130
124131
125132def benchmark_containerized_http (
126- iterations : int = 20 ,
133+ min_iterations : int | None = None ,
127134 array_sizes : list [int ] | None = None ,
128135 profile : bool = False ,
136+ min_duration_s : float = DEFAULT_MIN_DURATION_S ,
129137 image_name : str | None = None ,
130138) -> BenchmarkSuite | None :
131139 """Benchmark containerized Tesseract via HTTP (Tesseract.from_image).
@@ -151,7 +159,7 @@ def benchmark_containerized_http(
151159
152160 suite = BenchmarkSuite (
153161 name = "containerized_http" ,
154- metadata = {"iterations " : iterations , "array_sizes" : array_sizes },
162+ metadata = {"min_iterations " : min_iterations , "array_sizes" : array_sizes },
155163 )
156164
157165 # Build the benchmark tesseract image if not provided
@@ -191,9 +199,10 @@ def call_apply(t=tesseract, inp=inputs):
191199 result = run_benchmark (
192200 name = f"apply_{ size :,} " ,
193201 func = call_apply ,
194- iterations = iterations ,
202+ min_iterations = min_iterations ,
195203 warmup = 2 ,
196204 profile = profile ,
205+ min_duration_s = min_duration_s ,
197206 )
198207 suite .add_result (result )
199208
@@ -205,9 +214,10 @@ def call_apply(t=tesseract, inp=inputs):
205214
206215
207216def benchmark_containerized_cli (
208- iterations : int = 10 ,
217+ min_iterations : int | None = None ,
209218 array_sizes : list [int ] | None = None ,
210219 profile : bool = False ,
220+ min_duration_s : float = DEFAULT_MIN_DURATION_S ,
211221 image_name : str | None = None ,
212222) -> BenchmarkSuite | None :
213223 """Benchmark containerized Tesseract via CLI (`tesseract run`).
@@ -234,7 +244,7 @@ def benchmark_containerized_cli(
234244
235245 suite = BenchmarkSuite (
236246 name = "containerized_cli" ,
237- metadata = {"iterations " : iterations , "array_sizes" : array_sizes },
247+ metadata = {"min_iterations " : min_iterations , "array_sizes" : array_sizes },
238248 )
239249
240250 if image_name is None :
@@ -314,34 +324,41 @@ def run_cli(
314324 result = run_benchmark (
315325 name = f"apply_{ size :,} " ,
316326 func = run_cli ,
317- iterations = iterations ,
327+ min_iterations = min_iterations ,
318328 warmup = 1 ,
319329 profile = profile ,
330+ min_duration_s = min_duration_s ,
320331 )
321332 suite .add_result (result )
322333
323334 return suite
324335
325336
326337def run_all (
327- iterations : int = 50 ,
338+ min_iterations : int | None = None ,
328339 include_containerized : bool = False ,
329340 array_sizes : list [int ] | None = None ,
341+ min_duration_s : float = DEFAULT_MIN_DURATION_S ,
330342) -> list [BenchmarkSuite ]:
331343 """Run all Tesseract benchmarks.
332344
333345 Args:
334- iterations: Number of iterations per benchmark
346+ min_iterations: Minimum iterations per benchmark (None = auto-calibrate only)
335347 include_containerized: Whether to include Docker-based benchmarks
336348 array_sizes: Array sizes to benchmark (defaults to DEFAULT_ARRAY_SIZES)
349+ min_duration_s: Minimum duration per case when auto-calibrating
337350
338351 Returns:
339352 List of BenchmarkSuites
340353 """
341354 results = []
342355
343356 print ("Running benchmark_from_tesseract_api..." )
344- suite = benchmark_from_tesseract_api (iterations = iterations , array_sizes = array_sizes )
357+ suite = benchmark_from_tesseract_api (
358+ min_iterations = min_iterations ,
359+ array_sizes = array_sizes ,
360+ min_duration_s = min_duration_s ,
361+ )
345362 if suite is not None :
346363 results .append (suite )
347364
@@ -355,9 +372,10 @@ def run_all(
355372 ]:
356373 print (f"Running { benchmark_func .__name__ } ..." )
357374 suite = benchmark_func (
358- iterations = iterations ,
375+ min_iterations = min_iterations ,
359376 array_sizes = array_sizes ,
360377 image_name = image_name ,
378+ min_duration_s = min_duration_s ,
361379 )
362380 if suite is not None :
363381 results .append (suite )
@@ -366,13 +384,15 @@ def run_all(
366384
367385
368386if __name__ == "__main__" :
369- iterations = int (sys .argv [1 ]) if len (sys .argv ) > 1 else 50
387+ min_iterations : int | None = int (sys .argv [1 ]) if len (sys .argv ) > 1 else None
370388 exclude_docker = "--no-docker" in sys .argv
371389
372390 print (
373- f"Running Tesseract benchmarks (iterations={ iterations } , docker={ not exclude_docker } )..."
391+ f"Running Tesseract benchmarks (min_iterations={ min_iterations } , docker={ not exclude_docker } )..."
392+ )
393+ suites = run_all (
394+ min_iterations = min_iterations , include_containerized = not exclude_docker
374395 )
375- suites = run_all (iterations , include_containerized = not exclude_docker )
376396
377397 for suite in suites :
378398 print (f"\n === { suite .name } ===" )
0 commit comments