From 359980cf049f4dbab6b3a85c725400db171978ad Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Thu, 10 Oct 2024 11:49:34 -0500 Subject: [PATCH 01/10] add ratio_in_yjit When ruby's extended YJIT stats are available (`--yjit-stat`), then we have access to numerous additional stats. This adds `:ratio_in_yjit`, which is only present when additional stats are enabled. Example: ``` RUBYOPT='--yjit --yjit-stats=quiet' ruby -e ' def foo = "a" * 10 300.times{foo} puts "ratio_in_yjit: #{::RubyVM::YJIT.runtime_stats[:ratio_in_yjit]}" ' ratio_in_yjit: 0.9550806290358625 ``` Motivation: This should allow for better understanding of how to tune `--yjit-exec-mem-size`. From https://github.com/ruby/ruby/blob/ef084cc8f4958c1b6e4ead99136631bef6d8ddba/doc/yjit/yjit.md?plain=1#L213-L223: > If you start Ruby with `--yjit-stats`, e.g. using an environment variable `RUBYOPT=--yjit-stats`, > `RubyVM::YJIT.runtime_stats[:ratio_in_yjit]` shows the ratio of YJIT-executed instructions in %. > Ideally, `ratio_in_yjit` should be as large as 99%, and increasing `--yjit-exec-mem-size` often > helps improving `ratio_in_yjit`. How to test the change?: ``` RUBYOPT="--yjit --yjit-stats=quiet" bundle exec rake spec:yjit bundle exec rake spec:yjit # skipped ``` --- lib/datadog/core/environment/yjit.rb | 9 +++++++++ lib/datadog/core/runtime/ext.rb | 1 + lib/datadog/core/runtime/metrics.rb | 4 ++++ spec/datadog/core/runtime/metrics_spec.rb | 18 ++++++++++++++++++ 4 files changed, 32 insertions(+) diff --git a/lib/datadog/core/environment/yjit.rb b/lib/datadog/core/environment/yjit.rb index ffe1cdf8344..3e11787bb85 100644 --- a/lib/datadog/core/environment/yjit.rb +++ b/lib/datadog/core/environment/yjit.rb @@ -52,11 +52,20 @@ def yjit_alloc_size ::RubyVM::YJIT.runtime_stats[:yjit_alloc_size] end + # Ratio of YJIT-executed instructions + def ratio_in_yjit + ::RubyVM::YJIT.runtime_stats[:ratio_in_yjit] + end + def available? defined?(::RubyVM::YJIT) \ && ::RubyVM::YJIT.enabled? \ && ::RubyVM::YJIT.respond_to?(:runtime_stats) end + + def stats_available? + available? && ::RubyVM::YJIT.respond_to?(:stats_enabled?) + end end end end diff --git a/lib/datadog/core/runtime/ext.rb b/lib/datadog/core/runtime/ext.rb index d07901b865a..c858969732c 100644 --- a/lib/datadog/core/runtime/ext.rb +++ b/lib/datadog/core/runtime/ext.rb @@ -31,6 +31,7 @@ module Metrics METRIC_YJIT_OBJECT_SHAPE_COUNT = 'runtime.ruby.yjit.object_shape_count' METRIC_YJIT_OUTLINED_CODE_SIZE = 'runtime.ruby.yjit.outlined_code_size' METRIC_YJIT_YJIT_ALLOC_SIZE = 'runtime.ruby.yjit.yjit_alloc_size' + METRIC_YJIT_RATIO_IN_YJIT= 'runtime.ruby.yjit.ratio_in_yjit' TAG_SERVICE = 'service' end diff --git a/lib/datadog/core/runtime/metrics.rb b/lib/datadog/core/runtime/metrics.rb index 6c89d5b7dc7..a7d34f10d77 100644 --- a/lib/datadog/core/runtime/metrics.rb +++ b/lib/datadog/core/runtime/metrics.rb @@ -181,6 +181,10 @@ def flush_yjit_stats Core::Runtime::Ext::Metrics::METRIC_YJIT_YJIT_ALLOC_SIZE, Core::Environment::YJIT.yjit_alloc_size ) + gauge_if_not_nil( + Core::Runtime::Ext::Metrics::METRIC_YJIT_RATIO_IN_YJIT, + Core::Environment::YJIT.ratio_in_yjit + ) end end end diff --git a/spec/datadog/core/runtime/metrics_spec.rb b/spec/datadog/core/runtime/metrics_spec.rb index f3480969ef4..24947ad8abf 100644 --- a/spec/datadog/core/runtime/metrics_spec.rb +++ b/spec/datadog/core/runtime/metrics_spec.rb @@ -248,6 +248,24 @@ end end end + + context 'with YJIT enabled and RubyVM::YJIT.stats_enabled? true' do + before do + unless Datadog::Core::Environment::YJIT.stats_available? + skip('Test only runs with YJIT enabled and RubyVM::YJIT.stats_enabled? true') + end + skip('Test only runs on Ruby >= 3.3') if RUBY_VERSION < '3.3.' + allow(runtime_metrics).to receive(:gauge) + end + + it do + flush + + expect(runtime_metrics).to have_received(:gauge) + .with(Datadog::Core::Runtime::Ext::Metrics::METRIC_YJIT_RATIO_IN_YJIT, kind_of(Numeric)) + .once + end + end end end From ea2f656fb1f782e3dce353f4393a3122edfcca70 Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Fri, 11 Oct 2024 11:29:44 -0500 Subject: [PATCH 02/10] fix lint issue/typo --- lib/datadog/core/runtime/ext.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/datadog/core/runtime/ext.rb b/lib/datadog/core/runtime/ext.rb index c858969732c..328e5daad2c 100644 --- a/lib/datadog/core/runtime/ext.rb +++ b/lib/datadog/core/runtime/ext.rb @@ -31,7 +31,7 @@ module Metrics METRIC_YJIT_OBJECT_SHAPE_COUNT = 'runtime.ruby.yjit.object_shape_count' METRIC_YJIT_OUTLINED_CODE_SIZE = 'runtime.ruby.yjit.outlined_code_size' METRIC_YJIT_YJIT_ALLOC_SIZE = 'runtime.ruby.yjit.yjit_alloc_size' - METRIC_YJIT_RATIO_IN_YJIT= 'runtime.ruby.yjit.ratio_in_yjit' + METRIC_YJIT_RATIO_IN_YJIT = 'runtime.ruby.yjit.ratio_in_yjit' TAG_SERVICE = 'service' end From 90bf9e6668de1a44e9e67700c2f809a86bdd9e4b Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Tue, 15 Oct 2024 21:59:01 -0500 Subject: [PATCH 03/10] inline test-only .stats_available? into spec --- lib/datadog/core/environment/yjit.rb | 4 ---- spec/datadog/core/runtime/metrics_spec.rb | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/datadog/core/environment/yjit.rb b/lib/datadog/core/environment/yjit.rb index 3e11787bb85..42be908c33d 100644 --- a/lib/datadog/core/environment/yjit.rb +++ b/lib/datadog/core/environment/yjit.rb @@ -62,10 +62,6 @@ def available? && ::RubyVM::YJIT.enabled? \ && ::RubyVM::YJIT.respond_to?(:runtime_stats) end - - def stats_available? - available? && ::RubyVM::YJIT.respond_to?(:stats_enabled?) - end end end end diff --git a/spec/datadog/core/runtime/metrics_spec.rb b/spec/datadog/core/runtime/metrics_spec.rb index 24947ad8abf..6339aad13cf 100644 --- a/spec/datadog/core/runtime/metrics_spec.rb +++ b/spec/datadog/core/runtime/metrics_spec.rb @@ -251,10 +251,10 @@ context 'with YJIT enabled and RubyVM::YJIT.stats_enabled? true' do before do - unless Datadog::Core::Environment::YJIT.stats_available? + skip('Test only runs on Ruby >= 3.3') if RUBY_VERSION < '3.3.' + unless Datadog::Core::Environment::YJIT.available? && ::RubyVM::YJIT.stats_enabled? skip('Test only runs with YJIT enabled and RubyVM::YJIT.stats_enabled? true') end - skip('Test only runs on Ruby >= 3.3') if RUBY_VERSION < '3.3.' allow(runtime_metrics).to receive(:gauge) end From 237c93983f1b9e513bd1505ad3067fbacf7adc45 Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Tue, 15 Oct 2024 22:14:38 -0500 Subject: [PATCH 04/10] add ratio_in_yjit rbs signature --- sig/datadog/core/environment/yjit.rbs | 1 + 1 file changed, 1 insertion(+) diff --git a/sig/datadog/core/environment/yjit.rbs b/sig/datadog/core/environment/yjit.rbs index e8413bd1554..af483a351e1 100644 --- a/sig/datadog/core/environment/yjit.rbs +++ b/sig/datadog/core/environment/yjit.rbs @@ -11,6 +11,7 @@ module Datadog def self?.code_region_size: () -> untyped def self?.object_shape_count: () -> untyped def self?.yjit_alloc_size: () -> untyped + def self?.ratio_in_yjit: () -> untyped def self?.available?: () -> untyped end From e85f56134e0b81c65c3a51ae9cc4301b1fe33caf Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Tue, 15 Oct 2024 22:59:45 -0500 Subject: [PATCH 05/10] update yjit github CI action for `--yjit-stats` --- .github/workflows/test-yjit.yaml | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-yjit.yaml b/.github/workflows/test-yjit.yaml index 23b16bacbe9..d1f53df40bd 100644 --- a/.github/workflows/test-yjit.yaml +++ b/.github/workflows/test-yjit.yaml @@ -11,7 +11,7 @@ jobs: - '3.2' - '3.3' # ADD NEW RUBIES HERE - name: Test (${{ matrix.os }}, ${{ matrix.ruby }}) + name: Test YJIT (${{ matrix.os }}, ${{ matrix.ruby }}) runs-on: ${{ matrix.os }} env: RUBYOPT: "--yjit" @@ -32,3 +32,33 @@ jobs: bundler: latest # needed to fix issue with steep on Ruby 3.0/3.1 cache-version: v2 # bump this to invalidate cache - run: bundle exec rake spec:yjit + test-yjit-stats: + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + ruby: + - '3.3' + # ADD NEW RUBIES HERE + name: Test YJIT Stats (${{ matrix.os }}, ${{ matrix.ruby }}) + runs-on: ${{ matrix.os }} + env: + RUBYOPT: "--yjit --yjit-stats=quiet" + SKIP_SIMPLECOV: 1 + DD_INSTRUMENTATION_TELEMETRY_ENABLED: false + DD_REMOTE_CONFIGURATION_ENABLED: false + steps: + - uses: actions/checkout@v4 + # bundler appears to match both prerelease and release rubies when we + # want the former only. relax the constraint to allow any version for + # head rubies + - if: ${{ matrix.ruby == 'head' }} + run: sed -i~ -e '/spec\.required_ruby_version/d' datadog.gemspec + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + bundler: latest # needed to fix issue with steep on Ruby 3.0/3.1 + cache-version: v2 # bump this to invalidate cache + - run: bundle exec rake spec:yjit From d2226af0e6337cac5f6ec20b8adf6c55c24e1933 Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Wed, 16 Oct 2024 09:21:59 -0500 Subject: [PATCH 06/10] cleanup test-yjit.yaml --- .github/workflows/test-yjit.yaml | 37 +++++--------------------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/.github/workflows/test-yjit.yaml b/.github/workflows/test-yjit.yaml index d1f53df40bd..a7eb37da602 100644 --- a/.github/workflows/test-yjit.yaml +++ b/.github/workflows/test-yjit.yaml @@ -10,41 +10,14 @@ jobs: ruby: - '3.2' - '3.3' + rubyopt: + - '--yjit' + - '--yjit --yjit-stats=quiet' # ADD NEW RUBIES HERE - name: Test YJIT (${{ matrix.os }}, ${{ matrix.ruby }}) + name: Test YJIT (${{ matrix.os }}, ${{ matrix.ruby }} ${{ matrix.rubyopt }}) runs-on: ${{ matrix.os }} env: - RUBYOPT: "--yjit" - SKIP_SIMPLECOV: 1 - DD_INSTRUMENTATION_TELEMETRY_ENABLED: false - DD_REMOTE_CONFIGURATION_ENABLED: false - steps: - - uses: actions/checkout@v4 - # bundler appears to match both prerelease and release rubies when we - # want the former only. relax the constraint to allow any version for - # head rubies - - if: ${{ matrix.ruby == 'head' }} - run: sed -i~ -e '/spec\.required_ruby_version/d' datadog.gemspec - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true # runs 'bundle install' and caches installed gems automatically - bundler: latest # needed to fix issue with steep on Ruby 3.0/3.1 - cache-version: v2 # bump this to invalidate cache - - run: bundle exec rake spec:yjit - test-yjit-stats: - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - ruby: - - '3.3' - # ADD NEW RUBIES HERE - name: Test YJIT Stats (${{ matrix.os }}, ${{ matrix.ruby }}) - runs-on: ${{ matrix.os }} - env: - RUBYOPT: "--yjit --yjit-stats=quiet" + RUBYOPT: ${{ matrix.rubyopt }} SKIP_SIMPLECOV: 1 DD_INSTRUMENTATION_TELEMETRY_ENABLED: false DD_REMOTE_CONFIGURATION_ENABLED: false From bd56f1ff0448824b0d0897904afa0f4a52dac35c Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Wed, 16 Oct 2024 09:23:34 -0500 Subject: [PATCH 07/10] fix spec context/skip wording --- spec/datadog/core/runtime/metrics_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/datadog/core/runtime/metrics_spec.rb b/spec/datadog/core/runtime/metrics_spec.rb index 6339aad13cf..bace1d9d0cd 100644 --- a/spec/datadog/core/runtime/metrics_spec.rb +++ b/spec/datadog/core/runtime/metrics_spec.rb @@ -198,10 +198,10 @@ skip('Test only runs on Ruby >= 3.2') if RUBY_VERSION < '3.2.' end - context 'with YJIT enabled and RubyVM::YJIT.stats_enabled? false' do + context 'with YJIT enabled' do before do unless Datadog::Core::Environment::YJIT.available? - skip('Test only runs with YJIT enabled and RubyVM::YJIT.stats_enabled? false') + skip('Test only runs with YJIT enabled') end allow(runtime_metrics).to receive(:gauge) end From 47547fc2a55743c38742946a18f3f6aab57b112a Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Wed, 16 Oct 2024 09:37:18 -0500 Subject: [PATCH 08/10] fix lint issue --- spec/datadog/core/runtime/metrics_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/datadog/core/runtime/metrics_spec.rb b/spec/datadog/core/runtime/metrics_spec.rb index bace1d9d0cd..b7d2d957b40 100644 --- a/spec/datadog/core/runtime/metrics_spec.rb +++ b/spec/datadog/core/runtime/metrics_spec.rb @@ -200,9 +200,7 @@ context 'with YJIT enabled' do before do - unless Datadog::Core::Environment::YJIT.available? - skip('Test only runs with YJIT enabled') - end + skip('Test only runs with YJIT enabled') unless Datadog::Core::Environment::YJIT.available? allow(runtime_metrics).to receive(:gauge) end From e04c3265be295e79d1f6f3fb24f4665dac5e9422 Mon Sep 17 00:00:00 2001 From: Mark Delk Date: Wed, 16 Oct 2024 10:55:03 -0500 Subject: [PATCH 09/10] rearrange a comment --- .github/workflows/test-yjit.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-yjit.yaml b/.github/workflows/test-yjit.yaml index a7eb37da602..6b467f443fb 100644 --- a/.github/workflows/test-yjit.yaml +++ b/.github/workflows/test-yjit.yaml @@ -10,10 +10,10 @@ jobs: ruby: - '3.2' - '3.3' + # ADD NEW RUBIES HERE rubyopt: - '--yjit' - '--yjit --yjit-stats=quiet' - # ADD NEW RUBIES HERE name: Test YJIT (${{ matrix.os }}, ${{ matrix.ruby }} ${{ matrix.rubyopt }}) runs-on: ${{ matrix.os }} env: From a06708a799872b00f07becb1237c422792a93c63 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Thu, 17 Oct 2024 08:16:57 +0100 Subject: [PATCH 10/10] Exclude --yjit-stats configuration on Ruby 3.2 --- .github/workflows/test-yjit.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-yjit.yaml b/.github/workflows/test-yjit.yaml index 6b467f443fb..bf934c5fdc1 100644 --- a/.github/workflows/test-yjit.yaml +++ b/.github/workflows/test-yjit.yaml @@ -14,6 +14,9 @@ jobs: rubyopt: - '--yjit' - '--yjit --yjit-stats=quiet' + exclude: + - ruby: '3.2' + rubyopt: '--yjit --yjit-stats=quiet' name: Test YJIT (${{ matrix.os }}, ${{ matrix.ruby }} ${{ matrix.rubyopt }}) runs-on: ${{ matrix.os }} env: