ext/ruby_prof.c in ruby-prof-0.7.4 vs ext/ruby_prof.c in ruby-prof-0.7.5

- old
+ new

@@ -46,12 +46,12 @@ caller or callee method, thereby making it easy to navigate through the call hierarchy in ruby - which is very helpful for creating call graphs. */ #include "ruby_prof.h" +#include <stdio.h> - /* ================ Helper Functions =================*/ static VALUE figure_singleton_name(VALUE klass) { VALUE result = Qnil; @@ -376,11 +376,11 @@ } /* call-seq: called -> int -Returns the total amount of time this method was called. */ +Returns the total amount of times this method was called. */ static VALUE prof_call_info_called(VALUE self) { prof_call_info_t *result = prof_get_call_info_result(self); return INT2NUM(result->called); @@ -870,10 +870,16 @@ return "c-call"; case RUBY_EVENT_C_RETURN: return "c-return"; case RUBY_EVENT_RAISE: return "raise"; + +#ifdef RUBY_VM + case RUBY_EVENT_SWITCH: + return "thread-interrupt"; +#endif + default: return "unknown"; } } #endif @@ -916,49 +922,53 @@ update_result(prof_measure_t total_time, prof_frame_t *parent_frame, prof_frame_t *frame) { prof_measure_t self_time = total_time - frame->child_time - frame->wait_time; - + prof_call_info_t *call_info = frame->call_info; /* Update information about the current method */ call_info->called++; call_info->total_time += total_time; call_info->self_time += self_time; call_info->wait_time += frame->wait_time; - + /* Note where the current method was called from */ if (parent_frame) call_info->line = parent_frame->line; } static thread_data_t * switch_thread(VALUE thread_id, prof_measure_t now) { prof_frame_t *frame = NULL; prof_measure_t wait_time = 0; - /* Get new thread information. */ thread_data_t *thread_data = threads_table_lookup(threads_tbl, thread_id); /* How long has this thread been waiting? */ wait_time = now - thread_data->last_switch; + thread_data->last_switch = 0; /* Get the frame at the top of the stack. This may represent the current method (EVENT_LINE, EVENT_RETURN) or the previous method (EVENT_CALL).*/ frame = stack_peek(thread_data->stack); - if (frame) + if (frame) { frame->wait_time += wait_time; + } + + /* Save on the last thread the time of the context switch and reset this thread's last context switch to 0.*/ - if (last_thread_data) - last_thread_data->last_switch = now; + if (last_thread_data) { + last_thread_data->last_switch = now; + } last_thread_data = thread_data; return thread_data; } @@ -967,15 +977,14 @@ { prof_frame_t *frame = NULL; prof_frame_t* parent_frame = NULL; prof_measure_t total_time; - frame = stack_pop(thread_data->stack); - + frame = stack_pop(thread_data->stack); // only time it's called /* Frame can be null. This can happen if RubProf.start is called from a method that exits. And it can happen if an exception is raised - in code that is being profiled and the stack unwinds (RubProf is + in code that is being profiled and the stack unwinds (RubyProf is not notified of that by the ruby runtime. */ if (frame == NULL) return NULL; /* Calculate the total time this method took */ total_time = now - frame->start_time; @@ -987,11 +996,11 @@ if (parent_frame) { parent_frame->child_time += total_time; } - update_result(total_time, parent_frame, frame); + update_result(total_time, parent_frame, frame); // only time it's called return frame; } static int pop_frames(st_data_t key, st_data_t value, st_data_t now_arg) @@ -1027,11 +1036,10 @@ #else static void prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE klass) #endif { - VALUE thread = Qnil; VALUE thread_id = Qnil; prof_measure_t now = 0; thread_data_t* thread_data = NULL; prof_frame_t *frame = NULL; @@ -1064,12 +1072,13 @@ if (klass != 0) klass = (BUILTIN_TYPE(klass) == T_ICLASS ? RBASIC(klass)->klass : klass); class_name = rb_class2name(klass); - if (last_thread_id != thread_id) + if (last_thread_id != thread_id) { printf("\n"); + } printf("%2u: %-8s :%2d %s#%s\n", thread_id, event_name, source_line, class_name, method_name); fflush(stdout); last_thread_id = thread_id; @@ -1180,10 +1189,11 @@ break; } case RUBY_EVENT_RETURN: case RUBY_EVENT_C_RETURN: { + // this assumes that all C calls take 100% user cpu, I guess. pop_frame(thread_data, now); break; } } } @@ -1236,11 +1246,11 @@ { if (BUILTIN_TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RUBY_DATA_FUNC) prof_result_free) { /* Should never happen */ - rb_raise(rb_eTypeError, "wrong result object"); + rb_raise(rb_eTypeError, "wrong result object (%d %d) ", BUILTIN_TYPE(obj) != T_DATA, RDATA(obj)->dfree != (RUBY_DATA_FUNC) prof_result_free); } return (prof_result_t *) DATA_PTR(obj); } /* call-seq: @@ -1400,10 +1410,10 @@ { #ifdef RUBY_VM rb_add_event_hook(prof_event_hook, RUBY_EVENT_CALL | RUBY_EVENT_RETURN | RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN - | RUBY_EVENT_LINE, Qnil); + | RUBY_EVENT_LINE | RUBY_EVENT_SWITCH, Qnil); #else rb_add_event_hook(prof_event_hook, RUBY_EVENT_CALL | RUBY_EVENT_RETURN | RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN | RUBY_EVENT_LINE);