From 3dd32fdf784dac5769f6a352fa16c42e2c60edf7 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Wed, 12 Nov 2025 17:06:47 -0800 Subject: [PATCH 1/8] ZJIT: Revert patch_point_count counter (#15160) --- zjit.rb | 1 - zjit/src/invariants.rs | 18 ++++++------------ zjit/src/stats.rs | 1 - 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/zjit.rb b/zjit.rb index 396f52d4b44b20..7cdf84cfbe4328 100644 --- a/zjit.rb +++ b/zjit.rb @@ -192,7 +192,6 @@ def stats_string :dynamic_getivar_count, :dynamic_setivar_count, - :patch_point_count, :compiled_iseq_count, :failed_iseq_count, diff --git a/zjit/src/invariants.rs b/zjit/src/invariants.rs index 2855d7d592abe2..b6f5abe58bcd8e 100644 --- a/zjit/src/invariants.rs +++ b/zjit/src/invariants.rs @@ -2,10 +2,10 @@ use std::{collections::{HashMap, HashSet}, mem}; -use crate::{backend::lir::{Assembler, asm_comment}, cast::IntoU64, cruby::{ID, IseqPtr, RedefinitionFlag, VALUE, iseq_name, rb_callable_method_entry_t, rb_gc_location, ruby_basic_operators, src_loc, with_vm_lock}, hir::Invariant, options::debug, state::{ZJITState, zjit_enabled_p}, stats::{decr_counter_by, incr_counter}, virtualmem::CodePtr}; +use crate::{backend::lir::{Assembler, asm_comment}, cruby::{ID, IseqPtr, RedefinitionFlag, VALUE, iseq_name, rb_callable_method_entry_t, rb_gc_location, ruby_basic_operators, src_loc, with_vm_lock}, hir::Invariant, options::debug, state::{ZJITState, zjit_enabled_p}, virtualmem::CodePtr}; use crate::payload::IseqPayload; use crate::stats::with_time_stat; -use crate::stats::Counter::{invalidation_time_ns, patch_point_count}; +use crate::stats::Counter::invalidation_time_ns; use crate::gc::remove_gc_offsets; macro_rules! compile_patch_points { @@ -37,20 +37,14 @@ struct PatchPoint { } impl PatchPoint { - /// PatchPointer constructor, which also increments `patch_point_count` + /// PatchPointer constructor fn new(patch_point_ptr: CodePtr, side_exit_ptr: CodePtr, payload_ptr: *mut IseqPayload) -> PatchPoint { - incr_counter!(patch_point_count); Self { patch_point_ptr, side_exit_ptr, payload_ptr, } } - - /// Decrease `patch_point_count` by the size of a given `HashSet` - fn decr_counter(patch_points: HashSet) { - decr_counter_by(patch_point_count, patch_points.len().as_u64()); - } } /// Used to track all of the various block references that contain assumptions @@ -100,17 +94,17 @@ impl Invariants { // generated code referencing the ISEQ are unreachable. We mark the ISEQs baked into // generated code. self.ep_escape_iseqs.remove(&iseq); - self.no_ep_escape_iseq_patch_points.remove(&iseq).map(PatchPoint::decr_counter); + self.no_ep_escape_iseq_patch_points.remove(&iseq); } /// Forget a CME when freeing it. See [Self::forget_iseq] for reasoning. pub fn forget_cme(&mut self, cme: *const rb_callable_method_entry_t) { - self.cme_patch_points.remove(&cme).map(PatchPoint::decr_counter); + self.cme_patch_points.remove(&cme); } /// Forget a class when freeing it. See [Self::forget_iseq] for reasoning. pub fn forget_klass(&mut self, klass: VALUE) { - self.no_singleton_class_patch_points.remove(&klass).map(PatchPoint::decr_counter); + self.no_singleton_class_patch_points.remove(&klass); } /// Update ISEQ references in Invariants::ep_escape_iseqs diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 6fd0ac7bb02232..5103a549ba8e93 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -114,7 +114,6 @@ macro_rules! make_counters { make_counters! { // Default counters that are available without --zjit-stats default { - patch_point_count, compiled_iseq_count, failed_iseq_count, From 057c6e3bab655dd5edb9500731a56503d22ac3f7 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 13 Nov 2025 10:57:04 +0900 Subject: [PATCH 2/8] Revert "include ruby.h to avoid load failures" This reverts commit 35783854244f8dc6a9f7fb4dfae752f8361c66bd. --- ext/io/wait/wait.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c index cf36346cf2f955..f7575191fedf2d 100644 --- a/ext/io/wait/wait.c +++ b/ext/io/wait/wait.c @@ -17,8 +17,6 @@ * IO wait methods are built in ruby now, just for backward compatibility. */ -#include "ruby.h" - void Init_wait(void) { From fe1e1c784ea762fd4b7f8d441b8a2508460646ab Mon Sep 17 00:00:00 2001 From: Edouard CHIN Date: Wed, 12 Nov 2025 19:19:05 +0100 Subject: [PATCH 3/8] [ruby/rubygems] Adjust the API_REQUEST_LIMIT: - ### Problem This limit is used when Bundler fallback to getting a dependency list from a server `/dependencies?gem=` endpoint. Bundler uses this API endpoint fallback when a server doesn't expose the compact index API. This is not used for Rubygems.org, only private servers. This limit is then divided by the number of dependency to get and the result is the number of request we'll be doing. The bottleneck on the client is the network roundtrip. On the server, getting the info of 50 or 100 gems is a bit more expensive but this operation is heavily cached. This is an example of Rubygems.org implementation at the time the dependencies API wasn't deprecated https://github.com/rubygems/rubygems.org/blob/5a3a3ec02acc3a4e3aba077953a393ad20a06842/app/models/gem_dependent.rb#L15 ### Context This limit used to be 100 a while ago but got changed to 50 in https://github.com/ruby/rubygems/commit/e745f8dc901dd419e7dc8aede3e8d49569fc7b1e I don't know why. ### Solution 50 gems to query seems arbitrary low. By doubling this number, we make twice as less API requests which ultimately can shove up to two seconds on application relying on a large number of gems. https://github.com/ruby/rubygems/commit/831894043c --- lib/bundler/source/rubygems.rb | 2 +- spec/bundler/bundler/fetcher/dependency_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 2631c860a010ba..e420d8395f8bdd 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -8,7 +8,7 @@ class Rubygems < Source autoload :Remote, File.expand_path("rubygems/remote", __dir__) # Ask for X gems per API request - API_REQUEST_SIZE = 50 + API_REQUEST_SIZE = 100 attr_accessor :remotes diff --git a/spec/bundler/bundler/fetcher/dependency_spec.rb b/spec/bundler/bundler/fetcher/dependency_spec.rb index c420b7c07f2022..61e32acfd969ee 100644 --- a/spec/bundler/bundler/fetcher/dependency_spec.rb +++ b/spec/bundler/bundler/fetcher/dependency_spec.rb @@ -212,7 +212,7 @@ let(:dep_api_uri) { double(:dep_api_uri) } let(:unmarshalled_gems) { double(:unmarshalled_gems) } let(:fetch_response) { double(:fetch_response, body: double(:body)) } - let(:rubygems_limit) { 50 } + let(:rubygems_limit) { 100 } before { allow(subject).to receive(:dependency_api_uri).with(gem_names).and_return(dep_api_uri) } From b4b7809f0be7897e194d0e215071b9a0e3fa716e Mon Sep 17 00:00:00 2001 From: Kazuhiro NISHIYAMA Date: Thu, 13 Nov 2025 13:34:33 +0900 Subject: [PATCH 4/8] Use path in tmpdir instead of IO::NULL The path already used in tool/test/test_sync_default_gems.rb . Try to fix errors on Windows. https://github.com/ruby/ruby/actions/runs/19316448613/job/55248700110 --- tool/test/test_commit_email.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/test/test_commit_email.rb b/tool/test/test_commit_email.rb index 674275279efd08..ffe28b8e57d28b 100644 --- a/tool/test/test_commit_email.rb +++ b/tool/test/test_commit_email.rb @@ -15,7 +15,7 @@ def setup git('config', 'user.email', 'johan@example.com') env = { 'GIT_AUTHOR_DATE' => '2025-10-08T12:00:00Z', - 'GIT_CONFIG_GLOBAL' => IO::NULL, + 'GIT_CONFIG_GLOBAL' => @ruby + "/gitconfig", 'TZ' => 'UTC', } git('commit', '--allow-empty', '-m', 'New repository initialized by cvs2svn.', env:) From 2c1b1751e4b28929f426e4fd92c38f550872dbf5 Mon Sep 17 00:00:00 2001 From: Edouard CHIN Date: Mon, 10 Nov 2025 23:09:55 +0100 Subject: [PATCH 5/8] [ruby/rubygems] Add debug logging information: - I'd like to be able to see how long bundler takes for basic operations such as downloading a gem from Rubygems.org and installing a gem. It will now be possible with this commit by running `DEBUG=true bundle install` and have output that looks like: Fetching rack-test 2.2.0 Downloaded rack-test in: 50.523s Installing rack-test 2.2.0 Installed rack-test in: : 0.003s https://github.com/ruby/rubygems/commit/46386d43e1 --- lib/bundler/source/rubygems.rb | 11 +++++++++-- spec/bundler/bundler/source/rubygems_spec.rb | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index e420d8395f8bdd..e1e030ffc8992f 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -211,7 +211,11 @@ def install(spec, options = {}) message += " with native extensions" if spec.extensions.any? Bundler.ui.confirm message - installed_spec = installer.install + installed_spec = nil + + Gem.time("Installed #{spec.name} in", 0, true) do + installed_spec = installer.install + end spec.full_gem_path = installed_spec.full_gem_path spec.loaded_from = installed_spec.loaded_from @@ -478,7 +482,10 @@ def download_gem(spec, download_cache_path, previous_spec = nil) uri = spec.remote.uri Bundler.ui.confirm("Fetching #{version_message(spec, previous_spec)}") gem_remote_fetcher = remote_fetchers.fetch(spec.remote).gem_remote_fetcher - Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher) + + Gem.time("Downloaded #{spec.name} in", 0, true) do + Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher) + end end # Returns the global cache path of the calling Rubygems::Source object. diff --git a/spec/bundler/bundler/source/rubygems_spec.rb b/spec/bundler/bundler/source/rubygems_spec.rb index 884fa810465f96..dde4e4ed47693e 100644 --- a/spec/bundler/bundler/source/rubygems_spec.rb +++ b/spec/bundler/bundler/source/rubygems_spec.rb @@ -44,4 +44,22 @@ end end end + + describe "log debug information" do + it "log the time spent downloading and installing a gem" do + build_repo2 do + build_gem "warning" + end + + gemfile_content = <<~G + source "https://gem.repo2" + gem "warning" + G + + stdout = install_gemfile(gemfile_content, env: { "DEBUG" => "1" }) + + expect(stdout).to match(/Downloaded warning in: \d+\.\d+s/) + expect(stdout).to match(/Installed warning in: \d+\.\d+s/) + end + end end From 13407d959ab6e481db3148ea76f46c2f5aa70479 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 13 Nov 2025 11:44:51 +0900 Subject: [PATCH 6/8] Omit assert_ractor with Windows platform --- tool/lib/core_assertions.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/tool/lib/core_assertions.rb b/tool/lib/core_assertions.rb index 5d4c733a73d3be..2a60cfc445354f 100644 --- a/tool/lib/core_assertions.rb +++ b/tool/lib/core_assertions.rb @@ -391,6 +391,7 @@ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **o # Run Ractor-related test without influencing the main test suite def assert_ractor(src, args: [], require: nil, require_relative: nil, file: nil, line: nil, ignore_stderr: nil, **opt) return unless defined?(Ractor) + omit if windows? # https://bugs.ruby-lang.org/issues/21262 shim_value = "class Ractor; alias value take; end" unless Ractor.method_defined?(:value) From 3c68b781dcf63fe29dbde569e534ab0e2b3eec0c Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 13 Nov 2025 11:45:30 +0900 Subject: [PATCH 7/8] Use omit instead of return in assertion --- tool/lib/core_assertions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/lib/core_assertions.rb b/tool/lib/core_assertions.rb index 2a60cfc445354f..a9eb9ec3dceb69 100644 --- a/tool/lib/core_assertions.rb +++ b/tool/lib/core_assertions.rb @@ -390,7 +390,7 @@ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **o # Run Ractor-related test without influencing the main test suite def assert_ractor(src, args: [], require: nil, require_relative: nil, file: nil, line: nil, ignore_stderr: nil, **opt) - return unless defined?(Ractor) + omit unless defined?(Ractor) omit if windows? # https://bugs.ruby-lang.org/issues/21262 From 253485484c08aa56b1ea154b880eea217656d195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= Date: Mon, 23 Jun 2025 13:26:52 +0200 Subject: [PATCH 8/8] [ruby/rubygems] We don't need to allow some warning because: Always build gems with RubyGems programmatically https://github.com/ruby/rubygems/commit/5cc0c34e64 --- spec/bundler/commands/install_spec.rb | 2 +- spec/bundler/support/helpers.rb | 16 +--------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index 8506005746a25b..c3d0f281a0c1da 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -118,7 +118,7 @@ it "does not state that it's constantly reinstalling empty gems" do build_repo4 do - build_gem "empty", "1.0.0", no_default: true, allowed_warning: "no files specified" + build_gem "empty", "1.0.0", no_default: true end install_gemfile <<~G diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb index 719a6e65d2626c..12ff09b714a0fb 100644 --- a/spec/bundler/support/helpers.rb +++ b/spec/bundler/support/helpers.rb @@ -192,13 +192,7 @@ def gem_command(command, options = {}) # command is expired too. So give `gem install` commands a bit more time. options[:timeout] = 120 - allowed_warning = options.delete(:allowed_warning) - - output = sys_exec("#{Path.gem_bin} #{command}", options) - stderr = last_command.stderr - - raise stderr if stderr.include?("WARNING") && !allowed_rubygems_warning?(stderr, allowed_warning) - output + sys_exec("#{Path.gem_bin} #{command}", options) end def sys_exec(cmd, options = {}, &block) @@ -537,14 +531,6 @@ def empty_repo4 private - def allowed_rubygems_warning?(text, extra_allowed_warning) - allowed_warnings = ["open-ended", "is a symlink", "rake based", "expected RubyGems version"] - allowed_warnings << extra_allowed_warning if extra_allowed_warning - allowed_warnings.any? do |warning| - text.include?(warning) - end - end - def match_source(contents) match = /source ["']?(?http[^"']+)["']?/.match(contents) return unless match