88
99from dataclasses import dataclass
1010from functools import wraps
11- from typing import Callable , List , Optional
11+ from typing import Any , Callable , List , Optional
1212
1313from .core import Analysis , benchmark_function
14+ from .profiles import DEFAULT_ASSERTION_PROFILE_NAME , resolve_profile
1415
1516
1617# Complexity ordering for comparison
@@ -94,7 +95,12 @@ def check_threshold(
9495def assert_threshold (
9596 max_complexity : str ,
9697 sizes : Optional [List [int ]] = None ,
97- trials : int = 3 ,
98+ trials : Optional [int ] = None ,
99+ warmup : Optional [int ] = None ,
100+ profile : Optional [str ] = None ,
101+ setup : Optional [Callable [[int ], tuple [tuple [Any , ...], dict [str , Any ]]]] = None ,
102+ arg_factory : Optional [Callable [[int ], tuple [tuple [Any , ...], dict [str , Any ]]]] = None ,
103+ robust : Optional [bool ] = None ,
98104) -> Callable :
99105 """
100106 Decorator to assert function complexity is within threshold.
@@ -103,6 +109,11 @@ def assert_threshold(
103109 max_complexity: Maximum acceptable complexity (e.g., "O(n)").
104110 sizes: Input sizes for benchmarking.
105111 trials: Number of trials per size.
112+ warmup: Warmup runs.
113+ profile: Optional benchmark profile name.
114+ setup: Optional callable returning (args, kwargs) outside the timed region.
115+ arg_factory: Optional callable returning (args, kwargs) inside the timed region.
116+ robust: Override profile robust aggregation setting.
106117
107118 Returns:
108119 Decorated function.
@@ -117,8 +128,14 @@ def assert_threshold(
117128 >>>
118129 >>> my_sort(100) # First call triggers verification
119130 """
120- if sizes is None :
121- sizes = [100 , 500 , 1000 , 5000 ]
131+ options = resolve_profile (
132+ profile = profile or DEFAULT_ASSERTION_PROFILE_NAME ,
133+ sizes = sizes ,
134+ trials = trials ,
135+ warmup = warmup ,
136+ robust = robust ,
137+ default_profile = DEFAULT_ASSERTION_PROFILE_NAME ,
138+ )
122139
123140 def decorator (func : Callable ) -> Callable :
124141 _verified = False
@@ -129,7 +146,15 @@ def wrapper(*args, **kwargs):
129146
130147 if not _verified :
131148 # Run benchmark
132- analysis = benchmark_function (func , sizes = sizes , trials = trials )
149+ analysis = benchmark_function (
150+ func ,
151+ sizes = options .sizes ,
152+ trials = options .trials ,
153+ warmup = options .warmup ,
154+ setup = setup ,
155+ arg_factory = arg_factory ,
156+ robust = options .robust ,
157+ )
133158 result = check_threshold (analysis , max_complexity )
134159
135160 if not result .passed :
@@ -149,11 +174,16 @@ def wrapper(*args, **kwargs):
149174
150175def monitor_complexity (
151176 func : Callable ,
152- sizes : List [int ],
177+ sizes : Optional [ List [int ] ],
153178 max_complexity : str ,
154179 * ,
155180 on_exceed : str = "warn" ,
156- trials : int = 3 ,
181+ trials : Optional [int ] = None ,
182+ warmup : Optional [int ] = None ,
183+ profile : Optional [str ] = None ,
184+ setup : Optional [Callable [[int ], tuple [tuple [Any , ...], dict [str , Any ]]]] = None ,
185+ arg_factory : Optional [Callable [[int ], tuple [tuple [Any , ...], dict [str , Any ]]]] = None ,
186+ robust : Optional [bool ] = None ,
157187) -> Analysis :
158188 """
159189 Monitor function complexity and take action if threshold exceeded.
@@ -181,7 +211,23 @@ def monitor_complexity(
181211 """
182212 import warnings
183213
184- analysis = benchmark_function (func , sizes = sizes , trials = trials )
214+ options = resolve_profile (
215+ profile = profile or DEFAULT_ASSERTION_PROFILE_NAME ,
216+ sizes = sizes ,
217+ trials = trials ,
218+ warmup = warmup ,
219+ robust = robust ,
220+ default_profile = DEFAULT_ASSERTION_PROFILE_NAME ,
221+ )
222+ analysis = benchmark_function (
223+ func ,
224+ sizes = options .sizes ,
225+ trials = options .trials ,
226+ warmup = options .warmup ,
227+ setup = setup ,
228+ arg_factory = arg_factory ,
229+ robust = options .robust ,
230+ )
185231 result = check_threshold (analysis , max_complexity )
186232
187233 if not result .passed :
0 commit comments