@@ -154,7 +154,7 @@ def _format_stats(title, data, p50, p90, p99, fmt):
154154{ _format_stats ("Physical RSS RAM (MB)" , rss_memories , p50_rss , p90_rss , p99_rss , ".4f" )} """
155155 print (final_output .strip ())
156156
157- def run_master (iterations , target_module , cpu = 0 , csv_path = None , clear_cache = True ):
157+ def run_master (iterations , target_module , cpu = 0 , csv_path = None , clear_cache = True , fail_threshold = None ):
158158 """Orchestrates the benchmark."""
159159 if iterations < 1 :
160160 raise ValueError ("Number of iterations must be at least 1." )
@@ -229,6 +229,14 @@ def run_master(iterations, target_module, cpu=0, csv_path=None, clear_cache=True
229229 rss_memories , p50_rss , p90_rss , p99_rss
230230 )
231231
232+ if fail_threshold is not None :
233+ if p99_time > fail_threshold :
234+ print (f"\n FAILURE: P99 import time ({ p99_time :.2f} ms) exceeds the failure threshold ({ fail_threshold } ms)." , file = sys .stderr )
235+ sys .exit (1 )
236+ else :
237+ print (f"\n SUCCESS: P99 import time ({ p99_time :.2f} ms) is within the failure threshold ({ fail_threshold } ms)." )
238+
239+
232240def run_trace (target_module ):
233241 """Generates importtime trace log and writes it to a file."""
234242 trace_file = f"import_trace_{ target_module .replace ('.' , '_' )} .log"
@@ -307,8 +315,24 @@ def validate_module_name(module_name):
307315 raise argparse .ArgumentTypeError (f"'{ module_name } ' is not a valid Python module identifier." )
308316 return module_name
309317
318+ def find_module_from_package (pkg ):
319+ candidates = [
320+ pkg .replace ('-' , '.' ),
321+ '.' .join (pkg .split ('-' )[:- 1 ]) + '_' + pkg .split ('-' )[- 1 ] if '-' in pkg else pkg ,
322+ pkg .replace ('-' , '_' )
323+ ]
324+ for mod in candidates :
325+ try :
326+ if importlib .util .find_spec (mod ):
327+ return mod
328+ except Exception :
329+ pass
330+ return candidates [0 ]
331+
310332 parser = argparse .ArgumentParser (description = "Python SDK Import Profiler" )
311- parser .add_argument ("--module" , type = validate_module_name , default = "google.cloud.compute_v1" , help = "Target module to profile" )
333+ group = parser .add_mutually_exclusive_group (required = True )
334+ group .add_argument ("--module" , type = validate_module_name , help = "Target module to profile" )
335+ group .add_argument ("--package" , help = "Target package name to profile (auto-detects module)" )
312336 parser .add_argument ("--iterations" , type = int , default = 50 , help = "Number of iterations" )
313337 default_cpu = 0 if sys .platform .startswith ("linux" ) else NO_CPU_PINNING
314338 parser .add_argument ("--cpu" , type = int , default = default_cpu , help = "CPU core to pin to (or -1 for no pinning)" )
@@ -317,20 +341,25 @@ def validate_module_name(module_name):
317341 parser .add_argument ("--cprofile" , action = "store_true" , help = "Run cProfile" )
318342 parser .add_argument ("--mprofile" , action = "store_true" , help = "Run tracemalloc memory snapshot" )
319343 parser .add_argument ("--keep-pycache" , action = "store_true" , help = "Preserve __pycache__ and allow bytecode execution (Default: False, script automatically sweeps __pycache__ for true cold-starts)" )
344+ parser .add_argument ("--fail-threshold" , type = float , help = "Fail the profiling if the P99 time exceeds this threshold (in ms)." )
320345 parser .add_argument ("--worker" , action = "store_true" , help = argparse .SUPPRESS )
321346
322347 args = parser .parse_args ()
323348
349+ target_module = args .module
350+ if args .package :
351+ target_module = find_module_from_package (args .package )
352+
324353 if args .worker :
325- run_worker (args . module )
354+ run_worker (target_module )
326355 elif args .trace :
327356 if not args .keep_pycache : clean_bytecode ()
328- run_trace (args . module )
357+ run_trace (target_module )
329358 elif args .cprofile :
330359 if not args .keep_pycache : clean_bytecode ()
331- run_cprofile (args . module )
360+ run_cprofile (target_module )
332361 elif args .mprofile :
333362 if not args .keep_pycache : clean_bytecode ()
334- run_mprofile (args . module )
363+ run_mprofile (target_module )
335364 else :
336- run_master (args .iterations , args . module , args .cpu , args .csv , not args .keep_pycache )
365+ run_master (args .iterations , target_module , args .cpu , args .csv , not args .keep_pycache , args . fail_threshold )
0 commit comments