Skip to content

Commit

Permalink
First attempt to get pause/resume working by ignoring time spent when…
Browse files Browse the repository at this point in the history
… paused.

Basically instead of pause/resume pausing profiling, it instead will
now pause measurement.
  • Loading branch information
japgolly committed Apr 25, 2012
1 parent 05d278c commit 896e974
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 8 deletions.
17 changes: 17 additions & 0 deletions ext/ruby_prof/rp_stack.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@
#define INITIAL_STACK_SIZE 8


void
frame_pause(prof_frame_t *frame, double current_measurement)
{
frame->pause_time = current_measurement;
}

void
frame_unpause(prof_frame_t *frame, double current_measurement)
{
if (frame->pause_time >= 0) {
frame->dead_time += (current_measurement - frame->pause_time);
frame->pause_time = -1;
}
}



/* Creates a stack of prof_frame_t to keep track
of timings for active methods. */
prof_stack_t *
Expand Down
5 changes: 5 additions & 0 deletions ext/ruby_prof/rp_stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ typedef struct
double switch_time; /* Time at switch to different thread */
double wait_time;
double child_time;
double pause_time; // Time pause() was initiated
double dead_time; // Time to ignore (i.e. total amount of time between pause/resume blocks)
int depth;
unsigned int line;
} prof_frame_t;

void frame_pause(prof_frame_t*, double current_measurement);
void frame_unpause(prof_frame_t*, double current_measurement);

/* Current stack of active methods.*/
typedef struct
{
Expand Down
54 changes: 46 additions & 8 deletions ext/ruby_prof/ruby_prof.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ pop_frame(prof_profile_t* profile, thread_data_t *thread_data)
return NULL;

/* Calculate the total time this method took */
total_time = measurement - frame->start_time;
frame_unpause(frame, measurement);
total_time = measurement - frame->start_time - frame->dead_time;
self_time = total_time - frame->child_time - frame->wait_time;

/* Update information about the current method */
Expand Down Expand Up @@ -340,6 +341,8 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
frame->call_info = call_info;
frame->call_info->depth = frame->depth;
frame->start_time = measurement;
frame->pause_time = profile->paused == Qtrue ? measurement : -1;
frame->dead_time = 0;
frame->line = rb_sourceline();
break;
}
Expand Down Expand Up @@ -497,6 +500,36 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
return self;
}

static int pause_or_unpause_thread(st_data_t key, st_data_t value, st_data_t data) {
VALUE thread_id = (VALUE)key;
thread_data_t* thread_data = (thread_data_t *) value;
prof_profile_t* profile = (prof_profile_t*) data;

prof_frame_t* frame = stack_peek(thread_data->stack);
if (profile->paused == Qtrue)
frame_pause(frame, profile->measurement_at_pause_resume);
else
frame_unpause(frame, profile->measurement_at_pause_resume);

return ST_CONTINUE;
}

static void prof_pause_or_unpause_threads(prof_profile_t* profile) {
profile->measurement_at_pause_resume = profile->measurer->measure();
st_foreach(profile->threads_tbl, pause_or_unpause_thread, (st_data_t) profile);
}

/* call-seq:
paused? -> boolean
Returns whether a profile is currently paused.*/
static VALUE
prof_paused(VALUE self)
{
prof_profile_t* profile = prof_get_profile(self);
return profile->paused;
}

/* call-seq:
running? -> boolean
Expand Down Expand Up @@ -524,6 +557,7 @@ prof_start(VALUE self)
}

profile->running = Qtrue;
profile->paused = Qfalse;
profile->last_thread_data = NULL;


Expand Down Expand Up @@ -562,9 +596,12 @@ prof_pause(VALUE self)
rb_raise(rb_eRuntimeError, "RubyProf is not running.");
}

profile->running = Qfalse;
if (profile->paused == Qfalse)
{
profile->paused = Qtrue;
prof_pause_or_unpause_threads(profile);
}

prof_remove_hook();
return self;
}

Expand All @@ -578,12 +615,12 @@ prof_resume(VALUE self)
prof_profile_t* profile = prof_get_profile(self);
if (profile->running == Qfalse)
{
prof_start(self);
rb_raise(rb_eRuntimeError, "RubyProf is not running.");
}
else
if (profile->paused == Qtrue)
{
profile->running = Qtrue;
prof_install_hook(self);
profile->paused = Qfalse;
prof_pause_or_unpause_threads(profile);
}

if (rb_block_given_p())
Expand Down Expand Up @@ -628,7 +665,7 @@ prof_stop(VALUE self)

/* Unset the last_thread_data (very important!)
and the threads table */
profile->running = Qfalse;
profile->running = profile->paused = Qfalse;
profile->last_thread_data = NULL;

/* Post process result */
Expand Down Expand Up @@ -690,5 +727,6 @@ void Init_ruby_prof()
rb_define_method(cProfile, "resume", prof_resume, 0);
rb_define_method(cProfile, "pause", prof_pause, 0);
rb_define_method(cProfile, "running?", prof_running, 0);
rb_define_method(cProfile, "paused?", prof_paused, 0);
rb_define_method(cProfile, "threads", prof_threads, 0);
}
2 changes: 2 additions & 0 deletions ext/ruby_prof/ruby_prof.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ void method_key(prof_method_key_t* key, VALUE klass, ID mid);
typedef struct
{
VALUE running;
VALUE paused;
prof_measurer_t* measurer;
VALUE threads;
st_table* threads_tbl;
st_table* exclude_threads_tbl;
thread_data_t* last_thread_data;
double measurement_at_pause_resume;
} prof_profile_t;


Expand Down

0 comments on commit 896e974

Please sign in to comment.