[Feature #10602] Add new API rb_profile_thread_frames()

Add a new API rb_profile_thread_frames(), which is essentialy a
per-thread version of rb_profile_frames().

While the original rb_profile_frames() always returns results about the
current active thread obtained by GET_EC(), this new API takes a Thread
to be profiled as an argument.

This should come in handy when profiling I/O-bound programs such as
webapps, since this new API allows us to learn about Threads performing
I/O (which do not have the GVL).

Profiling worker threads (such as Sidekiq workers) may be another
application.

Implements [Feature #10602]

Co-authored-by: Mike Perham <mike@perham.net>
This commit is contained in:
Daisuke Aritomo 2023-09-29 15:35:36 +09:00 committed by Koichi Sasada
parent 02ecc3c855
commit 4adf418be9
4 changed files with 103 additions and 3 deletions

View file

@ -1584,11 +1584,10 @@ rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
return dc->backtrace;
}
int
rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
static int
thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *buff, int *lines)
{
int i;
const rb_execution_context_t *ec = GET_EC();
const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
const rb_control_frame_t *top = cfp;
const rb_callable_method_entry_t *cme;
@ -1650,6 +1649,20 @@ rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
return i;
}
int
rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
{
rb_execution_context_t *ec = GET_EC();
return thread_profile_frames(ec, start, limit, buff, lines);
}
int
rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines)
{
rb_thread_t *th = rb_thread_ptr(thread);
return thread_profile_frames(th->ec, start, limit, buff, lines);
}
static const rb_iseq_t *
frame2iseq(VALUE frame)
{