Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable profiler on Ruby 3.3 when running with RUBY_MN_THREADS=1 #3259

Merged
merged 1 commit into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ void self_test_clock_id(void) {
// Safety: This function is assumed never to raise exceptions by callers
thread_cpu_time_id thread_cpu_time_id_for(VALUE thread) {
rb_nativethread_id_t thread_id = pthread_id_for(thread);

if (thread_id == 0) return (thread_cpu_time_id) {.valid = false};

clockid_t clock_id;

int error = pthread_getcpuclockid(thread_id, &clock_id);
Expand Down
3 changes: 3 additions & 0 deletions ext/ddtrace_profiling_native_extension/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ def add_compiler_flag(flag)
$defs << '-DHAVE_PTHREAD_GETCPUCLOCKID'
end

# On older Rubies, M:N threads were not available
$defs << '-DNO_MN_THREADS_AVAILABLE' if RUBY_VERSION < '3.3'

# On older Rubies, we did not need to include the ractor header (this was built into the MJIT header)
$defs << '-DNO_RACTOR_HEADER_INCLUDE' if RUBY_VERSION < '3.3'

Expand Down
40 changes: 28 additions & 12 deletions ext/ddtrace_profiling_native_extension/private_vm_api_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ static inline rb_thread_t *thread_struct_from_object(VALUE thread) {
}

rb_nativethread_id_t pthread_id_for(VALUE thread) {
// struct rb_native_thread was introduced in Ruby 3.2 (preview2): https://github.com/ruby/ruby/pull/5836
// struct rb_native_thread was introduced in Ruby 3.2: https://github.com/ruby/ruby/pull/5836
#ifndef NO_RB_NATIVE_THREAD
return thread_struct_from_object(thread)->nt->thread_id;
struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
// This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
if (native_thread == NULL) return 0;
return native_thread->thread_id;
#else
return thread_struct_from_object(thread)->thread_id;
#endif
Expand Down Expand Up @@ -113,15 +116,16 @@ bool is_current_thread_holding_the_gvl(void) {

if (current_owner == NULL) return (current_gvl_owner) {.valid = false};

return (current_gvl_owner) {
.valid = true,
.owner =
#ifndef NO_RB_NATIVE_THREAD
current_owner->nt->thread_id
#else
current_owner->thread_id
#endif
};
#ifndef NO_RB_NATIVE_THREAD
struct rb_native_thread* current_owner_native_thread = current_owner->nt;

// This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
if (current_owner_native_thread == NULL) return (current_gvl_owner) {.valid = false};

return (current_gvl_owner) {.valid = true, .owner = current_owner_native_thread->thread_id};
#else
return (current_gvl_owner) {.valid = true, .owner = current_owner->thread_id};
#endif
}
#else
current_gvl_owner gvl_owner(void) {
Expand Down Expand Up @@ -182,7 +186,9 @@ uint64_t native_thread_id_for(VALUE thread) {
// The tid is only available on Ruby >= 3.1 + Linux (and FreeBSD). It's the same as `gettid()` aka the task id as seen in /proc
#if !defined(NO_THREAD_TID) && defined(RB_THREAD_T_HAS_NATIVE_ID)
#ifndef NO_RB_NATIVE_THREAD
return thread_struct_from_object(thread)->nt->tid;
struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
if (native_thread == NULL) rb_raise(rb_eRuntimeError, "BUG: rb_native_thread* is null. Is this Ruby running with RUBY_MN_THREADS=1?");
return native_thread->tid;
#else
return thread_struct_from_object(thread)->tid;
#endif
Expand Down Expand Up @@ -811,3 +817,13 @@ VALUE invoke_location_for(VALUE thread, int *line_location) {
*line_location = NUM2INT(rb_iseq_first_lineno(iseq));
return rb_iseq_path(iseq);
}

void self_test_mn_enabled(void) {
#ifdef NO_MN_THREADS_AVAILABLE
return;
#else
if (ddtrace_get_ractor()->threads.sched.enable_mn_threads == true) {
rb_raise(rb_eRuntimeError, "Ruby VM is running with RUBY_MN_THREADS=1. This is not yet supported");
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ bool ddtrace_rb_ractor_main_p(void);
// This is what Ruby shows in `Thread#to_s`.
// The file is returned directly, and the line is recorded onto *line_location.
VALUE invoke_location_for(VALUE thread, int *line_location);

// Check if RUBY_MN_THREADS is enabled (aka main Ractor is not doing 1:1 threads)
void self_test_mn_enabled(void);
1 change: 1 addition & 0 deletions ext/ddtrace_profiling_native_extension/profiling.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ void DDTRACE_EXPORT Init_ddtrace_profiling_native_extension(void) {

static VALUE native_working_p(DDTRACE_UNUSED VALUE _self) {
self_test_clock_id();
self_test_mn_enabled();

return Qtrue;
}
Expand Down
Loading