Skip to content

Commit

Permalink
[PROF-7307] Enable allocation counting feature by default for some Ru…
Browse files Browse the repository at this point in the history
…by 3 versions

**What does this PR do?**

This PR enables the Profiler's `allocation_counting_enabled` feature
by default for some Ruby 3 versions.

(This feature depends on the profiler itself being enabled).

TL;DR we were already enabling this feature by default on Ruby 2, but
did not do it on Ruby 3 because of a VM bug
( https://bugs.ruby-lang.org/issues/18464 ).

Now that this VM bug has been fixed for some Ruby versions
(3.1.4, 3.2.3, 3.3.0), we can enable it by default again.

**Motivation:**

The allocation counting feature is required to enable other
features in the future (including allocation profiling) and thus
we want to allow as many customers as possible to have it.

**Additional Notes:**

There's a second annoying VM bug that can also break
`allocation_counting_enabled` (https://bugs.ruby-lang.org/issues/19112)
but since that bug doesn't cause a VM crash and only makes it so that
data collection stops for this feature, I think we can live with it
for now.

I'm also reaching out through some contacts to see if we can get the
other bug fixed soon (and possibly backported).

**How to test the change?**

Change includes test coverage.
  • Loading branch information
ivoanjo committed Oct 2, 2023
1 parent 70bad1d commit 578baad
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 12 deletions.
27 changes: 20 additions & 7 deletions lib/datadog/core/configuration/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -314,15 +314,28 @@ def initialize(*_)

# Can be used to enable/disable the Datadog::Profiling.allocation_count feature.
#
# This feature is safe and enabled by default on Ruby 2.x, but
# on Ruby 3.x it can break in applications that make use of Ractors due to two Ruby VM bugs:
# https://bugs.ruby-lang.org/issues/19112 AND https://bugs.ruby-lang.org/issues/18464.
# This feature is safe and enabled by default on Ruby 2.x, but has a few caveats on Ruby 3.x.
#
# If you use Ruby 3.x and your application does not use Ractors (or if your Ruby has been patched), the
# feature is fully safe to enable and this toggle can be used to do so.
# Caveat 1 (severe):
# On Ruby versions 3.0 (all), 3.1.0 to 3.1.3, and 3.2.0 to 3.2.2 this is disabled by default because it
# can trigger a VM bug that causes a segmentation fault during garbage collection of Ractors
# (https://bugs.ruby-lang.org/issues/18464). We don't recommend using this feature on such Rubies.
# This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
#
# @default `true` on Ruby 2.x, `false` on Ruby 3.x
option :allocation_counting_enabled, default: RUBY_VERSION.start_with?('2.')
# Caveat 2 (annoyance):
# On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
# garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
# Thus this feature is only usable if you're not using Ractors.
#
# @default `true` on Ruby 2.x and 3.1.4+, 3.2.3+ and 3.3.0+; `false` for Ruby 3.0 and unpatched Rubies.
option :allocation_counting_enabled do |o|
o.default do
RUBY_VERSION.start_with?('2.') ||
(RUBY_VERSION.start_with?('3.1.') && RUBY_VERSION >= '3.1.4') ||
(RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION >= '3.2.3') ||
RUBY_VERSION >= '3.3.'
end
end

# Can be used to disable checking which version of `libmysqlclient` is being used by the `mysql2` gem.
#
Expand Down
19 changes: 14 additions & 5 deletions spec/datadog/core/configuration/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -500,16 +500,25 @@
describe '#allocation_counting_enabled' do
subject(:allocation_counting_enabled) { settings.profiling.advanced.allocation_counting_enabled }

context 'on Ruby 2.x' do
before { skip("Spec doesn't run on Ruby 3.x") unless RUBY_VERSION.start_with?('2.') }
before { stub_const('RUBY_VERSION', testing_version) }

context 'on Ruby 2.x' do
let(:testing_version) { '2.3.0 ' }
it { is_expected.to be true }
end

context 'on Ruby 3.x' do
before { skip("Spec doesn't run on Ruby 2.x") if RUBY_VERSION.start_with?('2.') }
['3.0.0', '3.1.0', '3.1.3', '3.2.0', '3.2.2'].each do |broken_ruby|
context "on a Ruby 3 version affected by https://bugs.ruby-lang.org/issues/18464 (#{broken_ruby})" do
let(:testing_version) { broken_ruby }
it { is_expected.to be false }
end
end

it { is_expected.to be false }
['3.1.4', '3.2.3', '3.3.0'].each do |fixed_ruby|
context "on a Ruby 3 version where https://bugs.ruby-lang.org/issues/18464 is fixed (#{fixed_ruby})" do
let(:testing_version) { fixed_ruby }
it { is_expected.to be true }
end
end
end

Expand Down

0 comments on commit 578baad

Please sign in to comment.