Bug #21338
closedTracePoint Not Triggered for Kernel#block_given?
Description
When updating ruby-prof for Ruby 3.4, various tests now fail because a method enter/leave tracepoint is not triggered for Kernel#block_given?
For example:
https://github.com/ruby-prof/ruby-prof/blob/master/test/line_number_test.rb#L184
In 3.3 a tracepoint was triggered but not in earlier Ruby versions.
Updated by alanwu (Alan Wu) 16 days ago
- Status changed from Open to Rejected
It's a C method in 3.4, so you can listen for :c_call
:
ruby -ve 'TracePoint.new(:c_call) { p _1 }.enable { block_given? }'
Wether something is a C or Ruby method is not something we guarantee to be stable, though, so it's not a bug now that a different event fires.
Updated by cfis (Charlie Savage) 15 days ago
· Edited
ruby-prof does listen for C calls. See:
https://github.com/ruby-prof/ruby-prof/blob/master/ext/ruby_prof/rp_profile.c#L337
void prof_install_hook(VALUE self)
{
prof_profile_t* profile = prof_get_profile(self);
VALUE event_tracepoint = rb_tracepoint_new(Qnil,
RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN |
RUBY_EVENT_LINE,
prof_event_hook, profile);
Once again, this is change in behavior between 3.3 and 3.4. Was it intentional?
Updated by alanwu (Alan Wu) 14 days ago
· Edited
Yes, we intentionally moved the implementation for block_given?
to C. Again, a method can move between C and Ruby between versions.
I just tested rb_tracepoint_new() with RUBY_EVENT_C_CALL and block_given?
, and an event definitely fires. This feels like you have a bug in your code. Are there any other behavior change you're seeing?
Updated by k0kubun (Takashi Kokubun) 14 days ago
· Edited
I see that you're calling Numeric#times
in your profiled test code. We used to use a block_given?
C call inside it to check if a block is given. @nobu (Nobuyoshi Nakada) changed it to defined?(yield)
at 3dccb716daaee74d2ae00a5766fe1779fe220a81 to protect it from possible method redefinitions of block_given?
. So block_given?
is no longer called in Ruby 3.4. I think that's what's happening in your test code.
It's effectively testing the implementation details of CRuby core methods like Numeric#times
. And it can change between different Ruby minor versions. To make the test code less fragile, I recommend you to define every method you call in the profiled code yourself.
Updated by cfis (Charlie Savage) 11 days ago
· Edited
Hi @k0kubun (Takashi Kokubun) - ok great - that sounds like an intentional change in Ruby 3.4 then.
I don't understand your recommendation though "to define every method you call in the profiled code yourself". The ruby-prof test code has remained fairly consistent over the years. What has changed is that each new version of Ruby returns slightly different results. For example, 3.3 started reporting block_given?
was called and then 3.4 removed it. Anyway, that's fine, I will update the test code. It already has a lot of version checks like this:
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.3')
....
else
...
end
See https://github.com/ruby-prof/ruby-prof/blob/master/test/measure_wall_time_test.rb#L160