@@ -121,100 +121,121 @@ int event_flag_return_p(rb_event_flag_t event_flags) {
121121 return event_flags & (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN );
122122}
123123
124+ const char * event_flag_name (rb_event_flag_t event_flag ) {
125+ switch (event_flag ) {
126+ case RUBY_EVENT_CALL : return "call" ;
127+ case RUBY_EVENT_C_CALL : return "c-call" ;
128+ case RUBY_EVENT_RETURN : return "return" ;
129+ case RUBY_EVENT_C_RETURN : return "c-return" ;
130+ default : return "unknown" ;
131+ }
132+ }
133+
134+ static struct IO_Event_Profiler_Call * profiler_event_record_call (struct IO_Event_Profiler * profiler , rb_event_flag_t event_flag , ID id , VALUE klass ) {
135+ struct IO_Event_Profiler_Call * call = IO_Event_Array_push (& profiler -> calls );
136+
137+ call -> event_flag = event_flag ;
138+
139+ call -> parent = profiler -> current ;
140+ profiler -> current = call ;
141+
142+ call -> nesting = profiler -> nesting ;
143+ profiler -> nesting += 1 ;
144+
145+ if (id ) {
146+ call -> id = id ;
147+ call -> klass = klass ;
148+ } else {
149+ rb_frame_method_id_and_class (& call -> id , & call -> klass );
150+ }
151+
152+ const char * path = rb_sourcefile ();
153+ if (path ) {
154+ call -> path = strdup (path );
155+ }
156+ call -> line = rb_sourceline ();
157+
158+ return call ;
159+ }
160+
124161static void profiler_event_callback (rb_event_flag_t event_flag , VALUE data , VALUE self , ID id , VALUE klass ) {
125162 struct IO_Event_Profiler * profiler = IO_Event_Profiler_get (data );
126163
127164 if (event_flag_call_p (event_flag )) {
128- struct IO_Event_Profiler_Call * call = IO_Event_Array_push ( & profiler -> calls );
165+ struct IO_Event_Profiler_Call * call = profiler_event_record_call ( profiler , event_flag , id , klass );
129166 IO_Event_Time_current (& call -> enter_time );
130-
131- call -> event_flag = event_flag ;
132-
133- call -> parent = profiler -> current ;
134- profiler -> current = call ;
135-
136- call -> nesting = profiler -> nesting ;
137- profiler -> nesting += 1 ;
138-
139- if (id ) {
140- call -> id = id ;
141- call -> klass = klass ;
142- } else {
143- rb_frame_method_id_and_class (& call -> id , & call -> klass );
144- }
145-
146- const char * path = rb_sourcefile ();
147- if (path ) {
148- call -> path = strdup (path );
149- }
150- call -> line = rb_sourceline ();
151167 } else if (event_flag_return_p (event_flag )) {
152168 struct IO_Event_Profiler_Call * call = profiler -> current ;
153169
154- // Bad call sequence?
155- if (call == NULL ) return ;
170+ // We may encounter returns without a preceeding call. This isn't an error, but we should pretend like the call started at the beginning of the profiling session:
171+ if (call == NULL ) {
172+ struct IO_Event_Profiler_Call * last_call = IO_Event_Array_last (& profiler -> calls );
173+ call = profiler_event_record_call (profiler , event_flag , id , klass );
174+
175+ if (last_call ) {
176+ call -> enter_time = last_call -> enter_time ;
177+ } else {
178+ call -> enter_time = profiler -> start_time ;
179+ }
180+ }
156181
157182 IO_Event_Time_current (& call -> exit_time );
158183
159184 profiler -> current = call -> parent ;
160- profiler -> nesting -= 1 ;
185+
186+ // We may encounter returns without a preceeding call.
187+ if (profiler -> nesting > 0 )
188+ profiler -> nesting -= 1 ;
161189 }
162190}
163191
164- void IO_Event_Profiler_restart (struct IO_Event_Profiler * profiler ) {
192+ void IO_Event_Profiler_start (struct IO_Event_Profiler * profiler ) {
193+ profiler -> running = 1 ;
194+
165195 IO_Event_Time_current (& profiler -> start_time );
166196
167197 profiler -> nesting = 0 ;
168198 profiler -> current = NULL ;
169199
170- IO_Event_Array_truncate (& profiler -> calls , 0 );
171- }
172-
173- void IO_Event_Profiler_start (struct IO_Event_Profiler * profiler ) {
174- if (DEBUG ) fprintf (stderr , "Starting profiler (tracking calls: %d)\n" , profiler -> track_calls );
175-
176- profiler -> running = 1 ;
177-
178- IO_Event_Profiler_restart (profiler );
179-
180200 // Since fibers are currently limited to a single thread, we use this in the hope that it's a little more efficient:
181201 if (profiler -> track_calls ) {
182202 VALUE thread = rb_thread_current ();
183203 rb_thread_add_event_hook (thread , profiler_event_callback , RUBY_EVENT_CALL | RUBY_EVENT_C_CALL | RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN , profiler -> self );
184204 }
185205}
186206
187- void IO_Event_Profiler_stop (struct IO_Event_Profiler * profiler ) {
188- if (DEBUG ) fprintf (stderr , "Stopping profiler...\n" );
189-
190- profiler -> running = 0 ;
191-
192- if (profiler -> track_calls ) {
193- VALUE thread = rb_thread_current ();
194- rb_thread_remove_event_hook_with_data (thread , profiler_event_callback , profiler -> self );
195- }
196- }
197-
198207static inline float IO_Event_Profiler_duration (struct IO_Event_Profiler * profiler ) {
199208 struct timespec duration ;
200209
201- IO_Event_Time_elapsed (& profiler -> start_time , & profiler -> finish_time , & duration );
210+ IO_Event_Time_elapsed (& profiler -> start_time , & profiler -> stop_time , & duration );
202211
203212 return IO_Event_Time_duration (& duration );
204213}
205214
206215void IO_Event_Profiler_print (struct IO_Event_Profiler * profiler , FILE * restrict stream );
207216
208- void IO_Event_Profile_finish (struct IO_Event_Profiler * profiler ) {
209- IO_Event_Time_current (& profiler -> finish_time );
217+ void IO_Event_Profiler_stop (struct IO_Event_Profiler * profiler ) {
218+ profiler -> running = 0 ;
219+
220+ if (profiler -> track_calls ) {
221+ VALUE thread = rb_thread_current ();
222+ rb_thread_remove_event_hook_with_data (thread , profiler_event_callback , profiler -> self );
223+ }
210224
225+ IO_Event_Time_current (& profiler -> stop_time );
211226 float duration = IO_Event_Profiler_duration (profiler );
212227
213228 if (duration > profiler -> log_threshold ) {
214229 IO_Event_Profiler_print (profiler , stderr );
215230 }
216231}
217232
233+ void IO_Event_Profiler_restart (struct IO_Event_Profiler * profiler ) {
234+ IO_Event_Profiler_stop (profiler );
235+ IO_Event_Array_truncate (& profiler -> calls , 0 );
236+ IO_Event_Profiler_start (profiler );
237+ }
238+
218239VALUE IO_Event_Profiler_fiber_transfer (VALUE self , VALUE fiber , int argc , VALUE * argv ) {
219240 struct IO_Event_Profiler * profiler = IO_Event_Profiler_get (self );
220241 int running = 0 ;
@@ -226,7 +247,6 @@ VALUE IO_Event_Profiler_fiber_transfer(VALUE self, VALUE fiber, int argc, VALUE
226247 running = profiler -> running ;
227248
228249 // We are switching to a different fiber, so consider the current profile complete:
229- IO_Event_Profile_finish (profiler );
230250 IO_Event_Profiler_restart (profiler );
231251 }
232252
@@ -238,7 +258,6 @@ VALUE IO_Event_Profiler_fiber_transfer(VALUE self, VALUE fiber, int argc, VALUE
238258 IO_Event_Profiler_restart (profiler );
239259 } else {
240260 // Otherwise, we need to stop it:
241- IO_Event_Profile_finish (profiler );
242261 IO_Event_Profiler_stop (profiler );
243262 }
244263
@@ -249,7 +268,7 @@ static const float IO_EVENT_PROFILER_PRINT_MINIMUM_PROPORTION = 0.01;
249268
250269void IO_Event_Profiler_print_tty (struct IO_Event_Profiler * profiler , FILE * restrict stream ) {
251270 struct timespec total_duration = {};
252- IO_Event_Time_elapsed (& profiler -> start_time , & profiler -> finish_time , & total_duration );
271+ IO_Event_Time_elapsed (& profiler -> start_time , & profiler -> stop_time , & total_duration );
253272
254273 fprintf (stderr , "Fiber stalled for %.3f seconds\n" , IO_Event_Time_duration (& total_duration ));
255274
@@ -260,10 +279,13 @@ void IO_Event_Profiler_print_tty(struct IO_Event_Profiler *profiler, FILE *restr
260279 struct timespec duration = {};
261280 IO_Event_Time_elapsed (& call -> enter_time , & call -> exit_time , & duration );
262281
282+ const char * prefix = "" ;
283+
263284 // Skip calls that are too short to be meaningful:
264285 if (IO_Event_Time_proportion (& duration , & total_duration ) < IO_EVENT_PROFILER_PRINT_MINIMUM_PROPORTION ) {
265286 skipped += 1 ;
266287 continue ;
288+ //prefix = "*";
267289 }
268290
269291 for (size_t i = 0 ; i < call -> nesting ; i += 1 ) {
@@ -273,7 +295,7 @@ void IO_Event_Profiler_print_tty(struct IO_Event_Profiler *profiler, FILE *restr
273295 VALUE class_inspect = rb_inspect (call -> klass );
274296 const char * name = rb_id2name (call -> id );
275297
276- fprintf (stream , "\t%s :%d in '%s#%s' (" IO_EVENT_TIME_PRINTF_TIMESPEC "s)\n" , call -> path , call -> line , RSTRING_PTR (class_inspect ), name , IO_EVENT_TIME_PRINTF_TIMESPEC_ARGUMENTS (duration ));
298+ fprintf (stream , "%s%s :%d in %s '%s#%s' (" IO_EVENT_TIME_PRINTF_TIMESPEC "s)\n" , prefix , call -> path , call -> line , event_flag_name ( call -> event_flag ) , RSTRING_PTR (class_inspect ), name , IO_EVENT_TIME_PRINTF_TIMESPEC_ARGUMENTS (duration ));
277299 }
278300
279301 if (skipped > 0 ) {
@@ -283,7 +305,7 @@ void IO_Event_Profiler_print_tty(struct IO_Event_Profiler *profiler, FILE *restr
283305
284306void IO_Event_Profiler_print_json (struct IO_Event_Profiler * profiler , FILE * restrict stream ) {
285307 struct timespec total_duration = {};
286- IO_Event_Time_elapsed (& profiler -> start_time , & profiler -> finish_time , & total_duration );
308+ IO_Event_Time_elapsed (& profiler -> start_time , & profiler -> stop_time , & total_duration );
287309
288310 fputc ('{' , stream );
289311
0 commit comments