Skip to content

Commit

Permalink
Move GVL instrumentation tests in their own files
Browse files Browse the repository at this point in the history
  • Loading branch information
byroot committed Jan 26, 2022
1 parent 316c44d commit cd2222b
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 67 deletions.
50 changes: 0 additions & 50 deletions ext/-test-/gvl/call_without_gvl/call_without_gvl.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "ruby/ruby.h"
#include "ruby/thread.h"
#include "ruby/thread_native.h"

static void*
native_sleep_callback(void *data)
Expand Down Expand Up @@ -69,60 +68,11 @@ thread_ubf_async_safe(VALUE thread, VALUE notify_fd)
return Qnil;
}

void
ex_callback(uint32_t e, struct gvl_hook_event_args args) {
fprintf(stderr, "calling callback\n");
}

static gvl_hook_t * single_hook = NULL;

static VALUE
thread_register_gvl_callback(VALUE thread) {
single_hook = rb_gvl_event_new(*ex_callback, RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER);

return Qnil;
}

static VALUE
thread_unregister_gvl_callback(VALUE thread) {
if (single_hook) {
rb_gvl_event_delete(single_hook);
single_hook = NULL;
}

return Qnil;
}

static VALUE
thread_call_gvl_callback(VALUE thread) {
rb_gvl_execute_hooks(RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER, 1);
return Qnil;
}

static VALUE
thread_register_and_unregister_gvl_callback(VALUE thread) {
gvl_hook_t * hooks[5];
for (int i = 0; i < 5; i++) {
hooks[i] = rb_gvl_event_new(*ex_callback, RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER);
}

if (!rb_gvl_event_delete(hooks[4])) return Qfalse;
if (!rb_gvl_event_delete(hooks[0])) return Qfalse;
if (!rb_gvl_event_delete(hooks[3])) return Qfalse;
if (!rb_gvl_event_delete(hooks[2])) return Qfalse;
if (!rb_gvl_event_delete(hooks[1])) return Qfalse;
return Qtrue;
}

void
Init_call_without_gvl(void)
{
VALUE mBug = rb_define_module("Bug");
VALUE klass = rb_define_module_under(mBug, "Thread");
rb_define_singleton_method(klass, "runnable_sleep", thread_runnable_sleep, 1);
rb_define_singleton_method(klass, "ubf_async_safe", thread_ubf_async_safe, 1);
rb_define_singleton_method(klass, "register_callback", thread_register_gvl_callback, 0);
rb_define_singleton_method(klass, "unregister_callback", thread_unregister_gvl_callback, 0);
rb_define_singleton_method(klass, "register_and_unregister_callbacks", thread_register_and_unregister_gvl_callback, 0);
rb_define_singleton_method(klass, "call_callbacks", thread_call_gvl_callback, 0);
}
161 changes: 161 additions & 0 deletions ext/-test-/gvl/instrumentation/instrumentation/depend
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# AUTOGENERATED DEPENDENCIES START
call_without_gvl.o: $(RUBY_EXTCONF_H)
call_without_gvl.o: $(arch_hdrdir)/ruby/config.h
call_without_gvl.o: $(hdrdir)/ruby/assert.h
call_without_gvl.o: $(hdrdir)/ruby/backward.h
call_without_gvl.o: $(hdrdir)/ruby/backward/2/assume.h
call_without_gvl.o: $(hdrdir)/ruby/backward/2/attributes.h
call_without_gvl.o: $(hdrdir)/ruby/backward/2/bool.h
call_without_gvl.o: $(hdrdir)/ruby/backward/2/inttypes.h
call_without_gvl.o: $(hdrdir)/ruby/backward/2/limits.h
call_without_gvl.o: $(hdrdir)/ruby/backward/2/long_long.h
call_without_gvl.o: $(hdrdir)/ruby/backward/2/stdalign.h
call_without_gvl.o: $(hdrdir)/ruby/backward/2/stdarg.h
call_without_gvl.o: $(hdrdir)/ruby/defines.h
call_without_gvl.o: $(hdrdir)/ruby/intern.h
call_without_gvl.o: $(hdrdir)/ruby/internal/anyargs.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/char.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/double.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/int.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/long.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/short.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
call_without_gvl.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
call_without_gvl.o: $(hdrdir)/ruby/internal/assume.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/artificial.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/cold.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/const.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/constexpr.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/deprecated.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/error.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/forceinline.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/format.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noalias.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noinline.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/pure.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/restrict.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/warning.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/weakref.h
call_without_gvl.o: $(hdrdir)/ruby/internal/cast.h
call_without_gvl.o: $(hdrdir)/ruby/internal/compiler_is.h
call_without_gvl.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
call_without_gvl.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
call_without_gvl.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
call_without_gvl.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
call_without_gvl.o: $(hdrdir)/ruby/internal/compiler_since.h
call_without_gvl.o: $(hdrdir)/ruby/internal/config.h
call_without_gvl.o: $(hdrdir)/ruby/internal/constant_p.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rarray.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rbasic.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rbignum.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rclass.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rdata.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rfile.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rhash.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/robject.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rregexp.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rstring.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rstruct.h
call_without_gvl.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
call_without_gvl.o: $(hdrdir)/ruby/internal/ctype.h
call_without_gvl.o: $(hdrdir)/ruby/internal/dllexport.h
call_without_gvl.o: $(hdrdir)/ruby/internal/dosish.h
call_without_gvl.o: $(hdrdir)/ruby/internal/error.h
call_without_gvl.o: $(hdrdir)/ruby/internal/eval.h
call_without_gvl.o: $(hdrdir)/ruby/internal/event.h
call_without_gvl.o: $(hdrdir)/ruby/internal/fl_type.h
call_without_gvl.o: $(hdrdir)/ruby/internal/gc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/glob.h
call_without_gvl.o: $(hdrdir)/ruby/internal/globals.h
call_without_gvl.o: $(hdrdir)/ruby/internal/has/attribute.h
call_without_gvl.o: $(hdrdir)/ruby/internal/has/builtin.h
call_without_gvl.o: $(hdrdir)/ruby/internal/has/c_attribute.h
call_without_gvl.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
call_without_gvl.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
call_without_gvl.o: $(hdrdir)/ruby/internal/has/extension.h
call_without_gvl.o: $(hdrdir)/ruby/internal/has/feature.h
call_without_gvl.o: $(hdrdir)/ruby/internal/has/warning.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/array.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/bignum.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/class.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/compar.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/complex.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/cont.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/dir.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/enum.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/error.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/eval.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/file.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/gc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/hash.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/io.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/load.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/marshal.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/numeric.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/object.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/parse.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/proc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/process.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/random.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/range.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/rational.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/re.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/ruby.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/select.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/signal.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/string.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/struct.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/thread.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/time.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/variable.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/vm.h
call_without_gvl.o: $(hdrdir)/ruby/internal/interpreter.h
call_without_gvl.o: $(hdrdir)/ruby/internal/iterator.h
call_without_gvl.o: $(hdrdir)/ruby/internal/memory.h
call_without_gvl.o: $(hdrdir)/ruby/internal/method.h
call_without_gvl.o: $(hdrdir)/ruby/internal/module.h
call_without_gvl.o: $(hdrdir)/ruby/internal/newobj.h
call_without_gvl.o: $(hdrdir)/ruby/internal/rgengc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/scan_args.h
call_without_gvl.o: $(hdrdir)/ruby/internal/special_consts.h
call_without_gvl.o: $(hdrdir)/ruby/internal/static_assert.h
call_without_gvl.o: $(hdrdir)/ruby/internal/stdalign.h
call_without_gvl.o: $(hdrdir)/ruby/internal/stdbool.h
call_without_gvl.o: $(hdrdir)/ruby/internal/symbol.h
call_without_gvl.o: $(hdrdir)/ruby/internal/value.h
call_without_gvl.o: $(hdrdir)/ruby/internal/value_type.h
call_without_gvl.o: $(hdrdir)/ruby/internal/variable.h
call_without_gvl.o: $(hdrdir)/ruby/internal/warning_push.h
call_without_gvl.o: $(hdrdir)/ruby/internal/xmalloc.h
call_without_gvl.o: $(hdrdir)/ruby/missing.h
call_without_gvl.o: $(hdrdir)/ruby/ruby.h
call_without_gvl.o: $(hdrdir)/ruby/st.h
call_without_gvl.o: $(hdrdir)/ruby/subst.h
call_without_gvl.o: $(hdrdir)/ruby/thread.h
call_without_gvl.o: call_without_gvl.c
# AUTOGENERATED DEPENDENCIES END
2 changes: 2 additions & 0 deletions ext/-test-/gvl/instrumentation/instrumentation/extconf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# frozen_string_literal: false
create_makefile("-test-/gvl/instrumentation")
95 changes: 95 additions & 0 deletions ext/-test-/gvl/instrumentation/instrumentation/instrumentation.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include "ruby/ruby.h"
#include "ruby/atomic.h"
#include "ruby/thread.h"
#include "ruby/thread_native.h"

static rb_atomic_t acquire_enter_count = 0;
static rb_atomic_t acquire_exit_count = 0;
static rb_atomic_t release_count = 0;

void
ex_callback(rb_event_flag_t event, gvl_hook_event_args_t args)
{
switch(event) {
case RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER:
RUBY_ATOMIC_INC(acquire_enter_count);
break;
case RUBY_INTERNAL_EVENT_GVL_ACQUIRE_EXIT:
RUBY_ATOMIC_INC(acquire_exit_count);
break;
case RUBY_INTERNAL_EVENT_GVL_RELEASE:
RUBY_ATOMIC_INC(release_count);
break;
}
}

static gvl_hook_t * single_hook = NULL;

static VALUE
thread_counters(VALUE thread)
{
VALUE array = rb_ary_new2(3);
rb_ary_push(array, UINT2NUM(acquire_enter_count));
rb_ary_push(array, UINT2NUM(acquire_exit_count));
rb_ary_push(array, UINT2NUM(release_count));
return array;
}

static VALUE
thread_reset_counters(VALUE thread)
{
RUBY_ATOMIC_SET(acquire_enter_count, 0);
RUBY_ATOMIC_SET(acquire_exit_count, 0);
RUBY_ATOMIC_SET(release_count, 0);
return Qtrue;
}

static VALUE
thread_register_gvl_callback(VALUE thread)
{
single_hook = rb_gvl_event_new(
*ex_callback,
RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER | RUBY_INTERNAL_EVENT_GVL_ACQUIRE_EXIT | RUBY_INTERNAL_EVENT_GVL_RELEASE
);

return Qnil;
}

static VALUE
thread_unregister_gvl_callback(VALUE thread)
{
if (single_hook) {
rb_gvl_event_delete(single_hook);
single_hook = NULL;
}

return Qnil;
}

static VALUE
thread_register_and_unregister_gvl_callback(VALUE thread)
{
gvl_hook_t * hooks[5];
for (int i = 0; i < 5; i++) {
hooks[i] = rb_gvl_event_new(*ex_callback, RUBY_INTERNAL_EVENT_GVL_ACQUIRE_ENTER);
}

if (!rb_gvl_event_delete(hooks[4])) return Qfalse;
if (!rb_gvl_event_delete(hooks[0])) return Qfalse;
if (!rb_gvl_event_delete(hooks[3])) return Qfalse;
if (!rb_gvl_event_delete(hooks[2])) return Qfalse;
if (!rb_gvl_event_delete(hooks[1])) return Qfalse;
return Qtrue;
}

void
Init_instrumentation(void)
{
VALUE mBug = rb_define_module("Bug");
VALUE klass = rb_define_module_under(mBug, "GVLInstrumentation");
rb_define_singleton_method(klass, "counters", thread_counters, 0);
rb_define_singleton_method(klass, "reset_counters", thread_reset_counters, 0);
rb_define_singleton_method(klass, "register_callback", thread_register_gvl_callback, 0);
rb_define_singleton_method(klass, "unregister_callback", thread_unregister_gvl_callback, 0);
rb_define_singleton_method(klass, "register_and_unregister_callbacks", thread_register_and_unregister_gvl_callback, 0);
}
1 change: 0 additions & 1 deletion include/ruby/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ void *rb_nogvl(void *(*func)(void *), void *data1,
*/
#define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_


RBIMPL_SYMBOL_EXPORT_END()

#endif /* RUBY_THREAD_H */
24 changes: 24 additions & 0 deletions test/-ext-/gvl/test_instrumentation_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: false
class TestGVLInstrumentation < Test::Unit::TestCase
def test_gvl_instrumentation
require '-test-/gvl/instrumentation'
Bug::GVLInstrumentation.reset_counters
Bug::GVLInstrumentation::register_callback

begin
threads = 5.times.map { Thread.new { sleep 0.05; 1 + 1; sleep 0.02 } }
threads.each(&:join)
Bug::GVLInstrumentation.counters.each do |c|
assert_predicate c,:nonzero?
end
ensure
Bug::GVLInstrumentation::unregister_callback
end
end

def test_gvl_instrumentation_unregister
require '-test-/gvl/instrumentation'
assert Bug::GVLInstrumentation::register_and_unregister_callbacks
end
end

16 changes: 0 additions & 16 deletions test/-ext-/gvl/test_last_thread.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,5 @@ def test_last_thread
assert_in_delta(1.0, t, 0.16)
end;
end

def test_gvl_instrumentation
require '-test-/gvl/call_without_gvl'
Bug::Thread::register_callback

begin
Bug::Thread::call_callbacks
ensure
Bug::Thread::unregister_callback
end
end

def test_gvl_instrumentation_unregister
require '-test-/gvl/call_without_gvl'
assert Bug::Thread::register_and_unregister_callbacks
end
end

0 comments on commit cd2222b

Please sign in to comment.