@@ -120,18 +120,18 @@ def _run_with_sync(original_cmd):
120120
121121
122122class SampleProfiler :
123- def __init__ (self , pid , sample_interval_usec , all_threads ):
123+ def __init__ (self , pid , sample_interval_usec , all_threads , * , cpu_time = False ):
124124 self .pid = pid
125125 self .sample_interval_usec = sample_interval_usec
126126 self .all_threads = all_threads
127127 if _FREE_THREADED_BUILD :
128128 self .unwinder = _remote_debugging .RemoteUnwinder (
129- self .pid , all_threads = self .all_threads
129+ self .pid , all_threads = self .all_threads , cpu_time = cpu_time
130130 )
131131 else :
132132 only_active_threads = bool (self .all_threads )
133133 self .unwinder = _remote_debugging .RemoteUnwinder (
134- self .pid , only_active_thread = only_active_threads
134+ self .pid , only_active_thread = only_active_threads , cpu_time = cpu_time
135135 )
136136 # Track sample intervals and total sample count
137137 self .sample_intervals = deque (maxlen = 100 )
@@ -596,18 +596,19 @@ def sample(
596596 show_summary = True ,
597597 output_format = "pstats" ,
598598 realtime_stats = False ,
599+ skip_idle = False ,
599600):
600601 profiler = SampleProfiler (
601- pid , sample_interval_usec , all_threads = all_threads
602+ pid , sample_interval_usec , all_threads = all_threads , cpu_time = skip_idle
602603 )
603604 profiler .realtime_stats = realtime_stats
604605
605606 collector = None
606607 match output_format :
607608 case "pstats" :
608- collector = PstatsCollector (sample_interval_usec )
609+ collector = PstatsCollector (sample_interval_usec , skip_idle = skip_idle )
609610 case "collapsed" :
610- collector = CollapsedStackCollector ()
611+ collector = CollapsedStackCollector (skip_idle = skip_idle )
611612 filename = filename or f"collapsed.{ pid } .txt"
612613 case "flamegraph" :
613614 collector = FlamegraphCollector ()
@@ -660,6 +661,7 @@ def wait_for_process_and_sample(pid, sort_value, args):
660661 filename = args .outfile
661662 if not filename and args .format == "collapsed" :
662663 filename = f"collapsed.{ pid } .txt"
664+ skip_idle = True if args .mode == "cpu" else False
663665
664666 sample (
665667 pid ,
@@ -672,6 +674,7 @@ def wait_for_process_and_sample(pid, sort_value, args):
672674 show_summary = not args .no_summary ,
673675 output_format = args .format ,
674676 realtime_stats = args .realtime_stats ,
677+ skip_idle = skip_idle ,
675678 )
676679
677680
@@ -726,6 +729,15 @@ def main():
726729 help = "Print real-time sampling statistics (Hz, mean, min, max, stdev) during profiling" ,
727730 )
728731
732+ # Mode options
733+ mode_group = parser .add_argument_group ("Mode options" )
734+ mode_group .add_argument (
735+ "--mode" ,
736+ choices = ["wall" , "cpu" ],
737+ default = "wall-time" ,
738+ help = "Sampling mode: wall-time (default, skip_idle=False) or cpu-time (skip_idle=True)" ,
739+ )
740+
729741 # Output format selection
730742 output_group = parser .add_argument_group ("Output options" )
731743 output_format = output_group .add_mutually_exclusive_group ()
@@ -850,6 +862,9 @@ def main():
850862 elif target_count > 1 :
851863 parser .error ("only one target type can be specified: -p/--pid, -m/--module, or script" )
852864
865+ # Set skip_idle based on mode
866+ skip_idle = True if args .mode == "cpu" else False
867+
853868 if args .pid :
854869 sample (
855870 args .pid ,
@@ -862,6 +877,7 @@ def main():
862877 show_summary = not args .no_summary ,
863878 output_format = args .format ,
864879 realtime_stats = args .realtime_stats ,
880+ skip_idle = skip_idle ,
865881 )
866882 elif args .module or args .args :
867883 if args .module :
0 commit comments