1515
1616
1717class PythonProfiler :
18- name = "" # placeholder
19- stats_filename = "" # placeholder
20-
2118 def __init__ (self , base_folder , framework ):
2219 """Higher level class to manage execution of python profiler, dumping of python stats, and retrieval
2320 of stats based on time or step intervals.
@@ -51,6 +48,7 @@ def _reset_profiler(self):
5148 """Reset attributes to defaults
5249 """
5350 self ._step , self ._start_time_since_epoch_in_micros , self ._is_profiling = None , None , False
51+ self ._start_stepphase = ""
5452
5553 def _enable_profiler (self ):
5654 """Enable the profiler (to be implemented in subclass, where the actual profiler is defined).
@@ -64,16 +62,24 @@ def _dump_stats(self, stats_path):
6462 """Dump the stats to the provided path (to be implemented in subclass, where the actual profiler is defined).
6563 """
6664
67- def start_profiling (self , start_step = - 1 ):
65+ def _name (self ):
66+ return "default"
67+
68+ def _stats_filename (self ):
69+ # this is default value
70+ return "python_stats"
71+
72+ def start_profiling (self , start_step = - 1 , step_phase = "" ):
6873 """Start the python profiler with the provided start step.
6974 If start step is -1, then this is profiling from import time to step 0.
7075 """
7176 self ._step = start_step
7277 self ._start_time_since_epoch_in_micros = time .time () * CONVERT_TO_MICROSECS
7378 self ._is_profiling = True
79+ self ._start_stepphase = step_phase
7480 self ._enable_profiler ()
7581
76- def stop_profiling (self ):
82+ def stop_profiling (self , step_phase = "" ):
7783 """Stop the python profiler.
7884 Dump the python stats for this step with a file path dependent on the base folder, framework, time and step.
7985 Append a record of this step's profiling with the corresponding metadata.
@@ -85,15 +91,19 @@ def stop_profiling(self):
8591 self ._disable_profiler ()
8692
8793 current_time_since_epoch_in_micros = time .time () * CONVERT_TO_MICROSECS
94+ step_phase_string = ""
95+ if self ._start_stepphase != "" or step_phase != "" :
96+ step_phase_string = f"{ self ._start_stepphase } -{ step_phase } "
8897 stats_dir = TraceFileLocation .get_python_profiling_stats_dir (
8998 self ._base_folder ,
9099 self ._framework ,
91- self .name ,
100+ self ._name () ,
92101 self ._step ,
93102 self ._start_time_since_epoch_in_micros ,
94103 current_time_since_epoch_in_micros ,
104+ step_phase_string ,
95105 )
96- self ._dump_stats (os .path .join (stats_dir , self .stats_filename ))
106+ self ._dump_stats (os .path .join (stats_dir , self ._stats_filename () ))
97107
98108 self ._reset_profiler ()
99109
@@ -110,14 +120,26 @@ class cProfilePythonProfiler(PythonProfiler):
110120 This is also the default Python profiler used if profiling is enabled.
111121 """
112122
113- name = "cProfile"
114- stats_filename = "python_stats"
115-
116123 def _reset_profiler (self ):
117124 """Reset profiler and corresponding attributes to defaults
118125 """
119126 super ()._reset_profiler ()
120- self ._profiler = cProfileProfiler ()
127+ self ._profiler = cProfileProfiler (self ._total_time )
128+
129+ def _name (self ):
130+ return "cProfile"
131+
132+ def _total_time (self ):
133+ times = os .times ()
134+ return times .elapsed
135+
136+ def _off_cpu_time (self ):
137+ times = os .times ()
138+ return times .elapsed - (times .system + times .user )
139+
140+ def _stats_filename (self ):
141+ # this is default value
142+ return "python_stats"
121143
122144 def _enable_profiler (self ):
123145 """Enable the cProfile profiler.
@@ -135,20 +157,22 @@ def _dump_stats(self, stats_file_path):
135157 get_logger ("smdebug-profiler" ).info (f"Dumping cProfile stats to { stats_file_path } ." )
136158 pstats .Stats (self ._profiler ).dump_stats (stats_file_path )
137159
138-
139160class PyinstrumentPythonProfiler (PythonProfiler ):
140161 """Higher level class to oversee profiling specific to Pyinstrument, a third party Python profiler.
141162 """
142163
143- name = "pyinstrument"
144- stats_filename = "python_stats.json"
145-
146164 def _reset_profiler (self ):
147165 """Reset profiler and corresponding attributes to defaults
148166 """
149167 super ()._reset_profiler ()
150168 self ._profiler = PyinstrumentProfiler ()
151169
170+ def _name (self ):
171+ return "pyinstrument"
172+
173+ def _stats_filename (self ):
174+ return "python_stats.json"
175+
152176 def _enable_profiler (self ):
153177 """Enable the pyinstrument profiler.
154178 """
0 commit comments