Returns a new profiler.
Measure mode (optional). Specifies the profile measure mode. If not specified, defaults to RubyProf::WALL_TIME.
Threads to exclude from the profiling results (optional).
static VALUE prof_initialize(int argc, VALUE *argv, VALUE self) { prof_profile_t* profile = prof_get_profile(self); VALUE mode; prof_measure_mode_t measurer = MEASURE_WALL_TIME; VALUE exclude_threads; int i; switch (rb_scan_args(argc, argv, "02", &mode, &exclude_threads)) { case 0: { measurer = MEASURE_WALL_TIME; exclude_threads = rb_ary_new(); break; } case 1: { measurer = (prof_measure_mode_t)NUM2INT(mode); exclude_threads = rb_ary_new(); break; } case 2: { Check_Type(exclude_threads, T_ARRAY); measurer = (prof_measure_mode_t)NUM2INT(mode); break; } } profile->measurer = prof_get_measurer(measurer); for (i = 0; i < RARRAY_LEN(exclude_threads); i++) { VALUE thread = rb_ary_entry(exclude_threads, i); VALUE thread_id = rb_obj_id(thread); st_insert(profile->exclude_threads_tbl, thread_id, Qtrue); } return self; }
Profiles the specified block and returns a RubyProf::Result object.
static VALUE prof_profile(int argc, VALUE *argv, VALUE klass) { int result; VALUE profile = rb_class_new_instance(argc, argv, cProfile); if (!rb_block_given_p()) { rb_raise(rb_eArgError, "A block must be provided to the profile method."); } prof_start(profile); rb_protect(rb_yield, profile, &result); return prof_stop(profile); }
This method detect recursive calls in the call graph.
# File lib/ruby-prof/profile.rb, line 15 def detect_recursion(thread) visited_methods = Hash.new do |hash, key| hash[key] = 0 end visitor = CallInfoVisitor.new(thread) visitor.visit do |call_info, event| case event when :enter visited_methods[call_info.target] += 1 call_info.recursive = (visited_methods[call_info.target] > 1) when :exit visited_methods[call_info.target] -= 1 if visited_methods[call_info.target] == 0 visited_methods.delete(call_info.target) end end end end
eliminate some calls from the graph by merging the information into callers. matchers can be a list of strings or regular expressions or the name of a file containing regexps.
# File lib/ruby-prof/profile.rb, line 37 def eliminate_methods!(matchers) matchers = read_regexps_from_file(matchers) if matchers.is_a?(String) eliminated = [] threads.each do |thread| matchers.each{ |matcher| eliminated.concat(eliminate_methods(thread.methods, matcher)) } end eliminated end
Pauses collecting profile data.
static VALUE prof_pause(VALUE self) { prof_profile_t* profile = prof_get_profile(self); if (profile->running == Qfalse) { rb_raise(rb_eRuntimeError, "RubyProf is not running."); } if (profile->paused == Qfalse) { profile->paused = Qtrue; profile->measurement_at_pause_resume = profile->measurer->measure(); st_foreach(profile->threads_tbl, pause_thread, (st_data_t) profile); } return self; }
Returns whether a profile is currently paused.
static VALUE prof_paused(VALUE self) { prof_profile_t* profile = prof_get_profile(self); return profile->paused; }
This method gets called once profiling has been completed but before results are returned to the user. Thus it provides a hook to do any necessary post-processing on the call graph.
# File lib/ruby-prof/profile.rb, line 8 def post_process self.threads.each do |thread| detect_recursion(thread) end end
Resumes recording profile data.
static VALUE prof_resume(VALUE self) { prof_profile_t* profile = prof_get_profile(self); if (profile->running == Qfalse) { rb_raise(rb_eRuntimeError, "RubyProf is not running."); } if (profile->paused == Qtrue) { profile->paused = Qfalse; profile->measurement_at_pause_resume = profile->measurer->measure(); st_foreach(profile->threads_tbl, unpause_thread, (st_data_t) profile); } return rb_block_given_p() ? rb_ensure(rb_yield, self, prof_pause, self) : self; }
Returns whether a profile is currently running.
static VALUE prof_running(VALUE self) { prof_profile_t* profile = prof_get_profile(self); return profile->running; }
Starts recording profile data.
static VALUE prof_start(VALUE self) { char* trace_file_name; prof_profile_t* profile = prof_get_profile(self); if (profile->running == Qtrue) { rb_raise(rb_eRuntimeError, "RubyProf.start was already called"); } #ifndef RUBY_VM if (pCurrentProfile != NULL) { rb_raise(rb_eRuntimeError, "Only one profile can run at a time on Ruby 1.8.*"); } #endif profile->running = Qtrue; profile->paused = Qfalse; profile->last_thread_data = NULL; /* open trace file if environment wants it */ trace_file_name = getenv("RUBY_PROF_TRACE"); if (trace_file_name != NULL) { if (strcmp(trace_file_name, "stdout") == 0) { trace_file = stdout; } else if (strcmp(trace_file_name, "stderr") == 0) { trace_file = stderr; } else { trace_file = fopen(trace_file_name, "w"); } } prof_install_hook(self); return self; }
Stops collecting profile data.
static VALUE prof_stop(VALUE self) { prof_profile_t* profile = prof_get_profile(self); if (profile->running == Qfalse) { rb_raise(rb_eRuntimeError, "RubyProf.start was not yet called"); } prof_remove_hook(); /* close trace file if open */ if (trace_file != NULL) { if (trace_file !=stderr && trace_file != stdout) { #ifdef _MSC_VER _fcloseall(); #else fclose(trace_file); #endif } trace_file = NULL; } prof_pop_threads(profile); /* Unset the last_thread_data (very important!) and the threads table */ profile->running = profile->paused = Qfalse; profile->last_thread_data = NULL; /* Post process result */ rb_funcall(self, rb_intern("post_process") , 0); return self; }
Returns an array of RubyProf::Thread instances that were executed while the the program was being run.
static VALUE prof_threads(VALUE self) { VALUE result = rb_ary_new(); prof_profile_t* profile = prof_get_profile(self); st_foreach(profile->threads_tbl, collect_threads, result); return result; }