diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 69f38f3f482fa3..0d02e2db09eb5b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -75,17 +75,17 @@ jobs: run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb - name: Initialize CodeQL - uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 + uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 with: languages: ${{ matrix.language }} trap-caching: false debug: true - name: Autobuild - uses: github/codeql-action/autobuild@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 + uses: github/codeql-action/autobuild@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 + uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 with: category: '/language:${{ matrix.language }}' upload: False @@ -115,7 +115,7 @@ jobs: continue-on-error: true - name: Upload SARIF - uses: github/codeql-action/upload-sarif@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 + uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 with: sarif_file: sarif-results/${{ matrix.language }}.sarif continue-on-error: true diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index b8e5af7f0f6e65..1393ffd6ddc199 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -208,7 +208,7 @@ jobs: matrix: include: # Using the same setup as ZJIT jobs - - bench_opts: '--warmup=1 --bench=1 --excludes=lobsters,shipit' + - bench_opts: '--warmup=1 --bench=1 --excludes=shipit' runs-on: ubuntu-24.04 diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index 820fa91f1a1e90..4b4b49473b7df9 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -158,7 +158,7 @@ jobs: include: # Test --call-threshold=2 with 2 iterations in total - ruby_opts: '--zjit-call-threshold=2' - bench_opts: '--warmup=1 --bench=1 --excludes=lobsters,shipit' + bench_opts: '--warmup=1 --bench=1 --excludes=shipit' configure: '--enable-zjit=dev_nodebug' # --enable-zjit=dev is too slow runs-on: macos-14 diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index d3e954bd723cb8..03ece9906bc772 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -215,7 +215,7 @@ jobs: include: # Test --call-threshold=2 with 2 iterations in total - ruby_opts: '--zjit-call-threshold=2' - bench_opts: '--warmup=1 --bench=1 --excludes=lobsters,shipit' + bench_opts: '--warmup=1 --bench=1 --excludes=shipit' configure: '--enable-zjit=dev_nodebug' # --enable-zjit=dev is too slow runs-on: ubuntu-24.04 diff --git a/common.mk b/common.mk index 5ba7fef4a8601d..383414ae2e8716 100644 --- a/common.mk +++ b/common.mk @@ -761,7 +761,7 @@ timestamp/distclean:: ext/distclean .bundle/distclean timestamp/realclean:: ext/realclean .bundle/realclean timestamp/clean timestamp/distclean timestamp/realclean:: - $(Q)$(RM) $(TIMESTAMPDIR)/.*.time $(TIMESTAMPDIR)/$(arch)/.time + $(Q)$(RM) $(TIMESTAMPDIR)/*.time $(TIMESTAMPDIR)/.*.time $(TIMESTAMPDIR)/$(arch)/.time $(Q)$(RMDIRS) $(TIMESTAMPDIR)/$(arch) $(TIMESTAMPDIR) 2> $(NULL) || $(NULLCMD) clean-ext:: @@ -900,8 +900,8 @@ test: test-short # Separate to skip updating encs and exts by `make -o test-precheck` # for GNU make. -test-precheck: $(ENCSTATIC:static=lib)encs $(RUBYSPEC_CAPIEXT_BUILD) exts PHONY $(DOT_WAIT) -yes-test-all-precheck: programs $(DOT_WAIT) test-precheck +test-precheck: $(ENCSTATIC:static=lib)encs exts PHONY $(DOT_WAIT) +yes-test-all-precheck: programs $(DOT_WAIT) test-precheck yes-fake PRECHECK_TEST_ALL = yes-test-all-precheck @@ -951,7 +951,7 @@ $(RBCONFIG): test-rubyspec: test-spec yes-test-rubyspec: yes-test-spec -yes-test-spec-precheck: yes-test-all-precheck yes-fake +yes-test-spec-precheck: yes-test-all-precheck $(RUBYSPEC_CAPIEXT_BUILD) test-spec: $(TEST_RUNNABLE)-test-spec yes-test-spec: yes-test-spec-precheck @@ -1561,8 +1561,11 @@ yes-install-for-test-bundled-gems: yes-update-default-gemspecs test-bundled-gems-fetch: yes-test-bundled-gems-fetch yes-test-bundled-gems-fetch: clone-bundled-gems-src -clone-bundled-gems-src: PHONY +clone-bundled-gems-src: PHONY $(TIMESTAMPDIR)/bundled-gems-src.time +$(TIMESTAMPDIR)/bundled-gems-src.time: $(srcdir)/gems/bundled_gems + $(Q) $(MAKEDIRS) $(@D) $(Q) $(BASERUBY) -C $(srcdir) tool/fetch-bundled_gems.rb BUNDLED_GEMS="$(BUNDLED_GEMS)" gems/src gems/bundled_gems + $(Q) $(TOUCH) $@ no-test-bundled-gems-fetch: test-bundled-gems-prepare: $(TEST_RUNNABLE)-test-bundled-gems-prepare @@ -1596,7 +1599,7 @@ yes-test-bundled-gems-run: $(PREPARE_BUNDLED_GEMS) no-test-bundled-gems-run: $(PREPARE_BUNDLED_GEMS) test-bundled-gems-spec: $(TEST_RUNNABLE)-test-bundled-gems-spec -yes-test-bundled-gems-spec: yes-test-spec-precheck $(PREPARE_BUNDLED_GEMS) +yes-test-bundled-gems-spec: yes-test-all-precheck $(PREPARE_BUNDLED_GEMS) $(ACTIONS_GROUP) $(gnumake_recursive)$(Q) \ $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/lib/_tmpdir \ @@ -1635,6 +1638,8 @@ test-bundler: $(TEST_RUNNABLE)-test-bundler yes-test-bundler: $(PREPARE_BUNDLER) $(gnumake_recursive)$(XRUBY) \ -r./$(arch)-fake \ + -r$(tooldir)/lib/_tmpdir \ + -e '$$no_report_tmpdir = true' \ -I$(srcdir)/spec/bundler -I$(srcdir)/spec/lib \ -e 'Dir.chdir(ARGV.shift); load("spec/bin/rspec")' $(srcdir) \ -r spec_helper $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS) @@ -1645,6 +1650,8 @@ test-bundler-parallel: $(TEST_RUNNABLE)-test-bundler-parallel yes-test-bundler-parallel: $(PREPARE_BUNDLER) $(gnumake_recursive)$(XRUBY) \ -r./$(arch)-fake \ + -r$(tooldir)/lib/_tmpdir \ + -e '$$no_report_tmpdir = true' \ -I$(srcdir)/spec/bundler \ -e "ruby = ENV['RUBY']" \ -e "ARGV[-1] = File.expand_path(ARGV[-1])" \ diff --git a/complex.c b/complex.c index c47afc1a61df73..30220f254b23c7 100644 --- a/complex.c +++ b/complex.c @@ -52,20 +52,6 @@ static ID id_abs, id_arg, #define id_quo idQuo #define id_fdiv idFdiv -#define fun1(n) \ -inline static VALUE \ -f_##n(VALUE x)\ -{\ - return rb_funcall(x, id_##n, 0);\ -} - -#define fun2(n) \ -inline static VALUE \ -f_##n(VALUE x, VALUE y)\ -{\ - return rb_funcall(x, id_##n, 1, y);\ -} - #define PRESERVE_SIGNEDZERO inline static VALUE @@ -276,8 +262,6 @@ f_to_f(VALUE x) return rb_funcall(x, id_to_f, 0); } -fun1(to_r) - inline static int f_eqeq_p(VALUE x, VALUE y) { @@ -288,8 +272,18 @@ f_eqeq_p(VALUE x, VALUE y) return (int)rb_equal(x, y); } -fun2(expt) -fun2(fdiv) +static VALUE +f_fdiv(VALUE x, VALUE y) +{ + if (RB_INTEGER_TYPE_P(x)) + return rb_int_fdiv(x, y); + if (RB_FLOAT_TYPE_P(x)) + return rb_float_div(x, y); + if (RB_TYPE_P(x, T_RATIONAL)) + return rb_rational_fdiv(x, y); + + return rb_funcallv(x, id_fdiv, 1, &y); +} static VALUE f_quo(VALUE x, VALUE y) @@ -318,24 +312,6 @@ f_negative_p(VALUE x) #define f_positive_p(x) (!f_negative_p(x)) -inline static bool -f_zero_p(VALUE x) -{ - if (RB_FLOAT_TYPE_P(x)) { - return FLOAT_ZERO_P(x); - } - else if (RB_INTEGER_TYPE_P(x)) { - return FIXNUM_ZERO_P(x); - } - else if (RB_TYPE_P(x, T_RATIONAL)) { - const VALUE num = RRATIONAL(x)->num; - return FIXNUM_ZERO_P(num); - } - return rb_equal(x, ZERO) != 0; -} - -#define f_nonzero_p(x) (!f_zero_p(x)) - static inline bool always_finite_type_p(VALUE x) { @@ -1216,11 +1192,10 @@ rb_complex_pow(VALUE self, VALUE other) if (RB_BIGNUM_TYPE_P(other)) rb_warn("in a**b, b may be too big"); - r = f_abs(self); - theta = f_arg(self); + r = rb_num_pow(f_abs(self), other); + theta = f_mul(f_arg(self), other); - return f_complex_polar(CLASS_OF(self), f_expt(r, other), - f_mul(theta, other)); + return f_complex_polar(CLASS_OF(self), r, theta); } return rb_num_coerce_bin(self, other, id_expt); } @@ -1873,7 +1848,7 @@ nucomp_to_r(VALUE self) self); } } - return f_to_r(dat->real); + return rb_funcallv(dat->real, id_to_r, 0, 0); } /* diff --git a/internal/numeric.h b/internal/numeric.h index d3905f048c2ab5..6391b1e9bc0f5c 100644 --- a/internal/numeric.h +++ b/internal/numeric.h @@ -78,6 +78,7 @@ VALUE rb_int_gt(VALUE x, VALUE y); VALUE rb_float_gt(VALUE x, VALUE y); VALUE rb_int_ge(VALUE x, VALUE y); enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts); +VALUE rb_int_fdiv(VALUE x, VALUE y); double rb_int_fdiv_double(VALUE x, VALUE y); VALUE rb_int_pow(VALUE x, VALUE y); VALUE rb_float_pow(VALUE x, VALUE y); diff --git a/internal/rational.h b/internal/rational.h index f11fab4583b32e..f7e382af8cf8a5 100644 --- a/internal/rational.h +++ b/internal/rational.h @@ -28,6 +28,7 @@ VALUE rb_rational_plus(VALUE self, VALUE other); VALUE rb_rational_minus(VALUE self, VALUE other); VALUE rb_rational_mul(VALUE self, VALUE other); VALUE rb_rational_div(VALUE self, VALUE other); +VALUE rb_rational_fdiv(VALUE self, VALUE other); VALUE rb_lcm(VALUE x, VALUE y); VALUE rb_rational_reciprocal(VALUE x); VALUE rb_cstr_to_rat(const char *, int); @@ -68,4 +69,22 @@ RATIONAL_SET_DEN(VALUE r, VALUE d) RB_OBJ_WRITE(r, &RRATIONAL(r)->den, d); } +inline static bool +f_zero_p(VALUE x) +{ + if (RB_INTEGER_TYPE_P(x)) { + return FIXNUM_ZERO_P(x); + } + else if (RB_FLOAT_TYPE_P(x)) { + return FLOAT_ZERO_P(x); + } + else if (RB_TYPE_P(x, T_RATIONAL)) { + const VALUE num = RRATIONAL(x)->num; + return FIXNUM_ZERO_P(num); + } + return rb_equal(x, INT2FIX(0)) != 0; +} + +#define f_nonzero_p(x) (!f_zero_p(x)) + #endif /* INTERNAL_RATIONAL_H */ diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb index fd6da6cf6dec71..3c68e5181224db 100644 --- a/lib/bundler/plugin.rb +++ b/lib/bundler/plugin.rb @@ -253,10 +253,13 @@ def loaded?(plugin) # @param [Array] names of inferred source plugins that can be ignored def save_plugins(plugins, specs, optional_plugins = []) plugins.each do |name| - next if index.installed?(name) - spec = specs[name] + # It's possible that the `plugin` found in the Gemfile don't appear in the specs. For instance when + # calling `BUNDLE_WITHOUT=default bundle install`, the plugins will not get installed. + next if spec.nil? + next if index.installed?(name) + save_plugin(name, spec, optional_plugins.include?(name)) end end diff --git a/rational.c b/rational.c index fba93a5c3ff550..d207fb7f4581f9 100644 --- a/rational.c +++ b/rational.c @@ -175,22 +175,6 @@ f_idiv(VALUE x, VALUE y) #define f_expt10(x) rb_int_pow(INT2FIX(10), x) -inline static int -f_zero_p(VALUE x) -{ - if (RB_INTEGER_TYPE_P(x)) { - return FIXNUM_ZERO_P(x); - } - else if (RB_TYPE_P(x, T_RATIONAL)) { - VALUE num = RRATIONAL(x)->num; - - return FIXNUM_ZERO_P(num); - } - return (int)rb_equal(x, ZERO); -} - -#define f_nonzero_p(x) (!f_zero_p(x)) - inline static int f_one_p(VALUE x) { @@ -970,8 +954,8 @@ rb_rational_div(VALUE self, VALUE other) * Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333 * Rational(2).fdiv(3) #=> 0.6666666666666666 */ -static VALUE -nurat_fdiv(VALUE self, VALUE other) +VALUE +rb_rational_fdiv(VALUE self, VALUE other) { VALUE div; if (f_zero_p(other)) @@ -2774,7 +2758,7 @@ Init_Rational(void) rb_define_method(rb_cRational, "*", rb_rational_mul, 1); rb_define_method(rb_cRational, "/", rb_rational_div, 1); rb_define_method(rb_cRational, "quo", rb_rational_div, 1); - rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1); + rb_define_method(rb_cRational, "fdiv", rb_rational_fdiv, 1); rb_define_method(rb_cRational, "**", nurat_expt, 1); rb_define_method(rb_cRational, "<=>", rb_rational_cmp, 1); diff --git a/spec/bundler/install/global_cache_spec.rb b/spec/bundler/install/global_cache_spec.rb index 77ab94609ee566..d0eb27065bd5e6 100644 --- a/spec/bundler/install/global_cache_spec.rb +++ b/spec/bundler/install/global_cache_spec.rb @@ -48,6 +48,8 @@ def source2_global_cache(*segments) end it "shows a proper error message if a cached gem is corrupted" do + skip "This example is not working on ruby/ruby repo" if ruby_core? + source_global_cache.mkpath FileUtils.touch(source_global_cache("myrack-1.0.0.gem")) diff --git a/spec/bundler/plugins/install_spec.rb b/spec/bundler/plugins/install_spec.rb index 6cace961f5228b..36672f0085e617 100644 --- a/spec/bundler/plugins/install_spec.rb +++ b/spec/bundler/plugins/install_spec.rb @@ -265,6 +265,18 @@ def exec(command, args) plugin_should_be_installed("foo") end + it "respects bundler groups" do + gemfile <<-G + source 'https://gem.repo2' + plugin 'foo' + gem 'myrack', "1.0.0" + G + + bundle "install", env: { "BUNDLE_WITHOUT" => "default" } + + expect(out).to include("Bundle complete! 1 Gemfile dependency, 0 gems now installed.") + end + it "accepts plugin version" do update_repo2 do build_plugin "foo", "1.1.0" diff --git a/tool/fetch-bundled_gems.rb b/tool/fetch-bundled_gems.rb index 127ea236f3d5e4..4d2af06a8503c7 100755 --- a/tool/fetch-bundled_gems.rb +++ b/tool/fetch-bundled_gems.rb @@ -28,16 +28,10 @@ system(*%W"git clone --depth=1 --no-tags #{u} #{n}") or abort end -if r - puts "fetching #{color.notice(r)} ..." - system("git", "fetch", "origin", r, chdir: n) or abort - c = r -else - c = ["v#{v}", v].find do |c| - puts "fetching #{color.notice(c)} ..." - system("git", "fetch", "origin", "refs/tags/#{c}:refs/tags/#{c}", chdir: n) - end or abort -end +c = (r ? [r] : ["v#{v}", v]).find do |c| + puts "fetching #{n} #{color.notice(c)} ..." + system("git", "fetch", "origin", r || "refs/tags/#{c}:refs/tags/#{c}", chdir: n) +end or abort checkout = %w"git -c advice.detachedHead=false checkout" info = %[, r=#{color.info(r)}] if r diff --git a/tool/lib/_tmpdir.rb b/tool/lib/_tmpdir.rb index daa1a1f2350c69..1518d46ee585cf 100644 --- a/tool/lib/_tmpdir.rb +++ b/tool/lib/_tmpdir.rb @@ -28,66 +28,68 @@ Dir.rmdir(tmpdir) rescue Errno::ENOENT rescue Errno::ENOTEMPTY - require_relative "colorize" - colorize = Colorize.new - ls = Struct.new(:colorize) do - def mode_inspect(m, s) - [ - (m & 0o4 == 0 ? ?- : ?r), - (m & 0o2 == 0 ? ?- : ?w), - (m & 0o1 == 0 ? (s ? s.upcase : ?-) : (s || ?x)), - ] - end - def decorate_path(path, st) - case - when st.directory? - color = "bold;blue" - type = "/" - when st.symlink? - color = "bold;cyan" - # type = "@" - when st.executable? - color = "bold;green" - type = "*" - when path.end_with?(".gem") - color = "green" + unless $no_report_tmpdir + require_relative "colorize" + colorize = Colorize.new + ls = Struct.new(:colorize) do + def mode_inspect(m, s) + [ + (m & 0o4 == 0 ? ?- : ?r), + (m & 0o2 == 0 ? ?- : ?w), + (m & 0o1 == 0 ? (s ? s.upcase : ?-) : (s || ?x)), + ] end - colorize.decorate(path, color) + (type || "") - end - def list_tree(parent, indent = "", &block) - children = Dir.children(parent).map do |child| - [child, path = File.join(parent, child), File.lstat(path)] + def decorate_path(path, st) + case + when st.directory? + color = "bold;blue" + type = "/" + when st.symlink? + color = "bold;cyan" + # type = "@" + when st.executable? + color = "bold;green" + type = "*" + when path.end_with?(".gem") + color = "green" + end + colorize.decorate(path, color) + (type || "") end - nlink_width = children.map {|child, path, st| st.nlink}.max.to_s.size - size_width = children.map {|child, path, st| st.size}.max.to_s.size + def list_tree(parent, indent = "", &block) + children = Dir.children(parent).map do |child| + [child, path = File.join(parent, child), File.lstat(path)] + end + nlink_width = children.map {|child, path, st| st.nlink}.max.to_s.size + size_width = children.map {|child, path, st| st.size}.max.to_s.size - children.each do |child, path, st| - m = st.mode - m = [ - (st.file? ? ?- : st.ftype[0]), - mode_inspect(m >> 6, (?s unless m & 04000 == 0)), - mode_inspect(m >> 3, (?s unless m & 02000 == 0)), - mode_inspect(m, (?t unless m & 01000 == 0)), - ].join("") - warn sprintf("%s* %s %*d %*d %s % s%s", - indent, m, nlink_width, st.nlink, size_width, st.size, - st.mtime.to_s, decorate_path(child, st), - (" -> " + decorate_path(File.readlink(path), File.stat(path)) if - st.symlink?)) - if st.directory? - list_tree(File.join(parent, child), indent + " ", &block) + children.each do |child, path, st| + m = st.mode + m = [ + (st.file? ? ?- : st.ftype[0]), + mode_inspect(m >> 6, (?s unless m & 04000 == 0)), + mode_inspect(m >> 3, (?s unless m & 02000 == 0)), + mode_inspect(m, (?t unless m & 01000 == 0)), + ].join("") + warn sprintf("%s* %s %*d %*d %s % s%s", + indent, m, nlink_width, st.nlink, size_width, st.size, + st.mtime.to_s, decorate_path(child, st), + (" -> " + decorate_path(File.readlink(path), File.stat(path)) if + st.symlink?)) + if st.directory? + list_tree(File.join(parent, child), indent + " ", &block) + end + yield path, st if block end - yield path, st if block end - end - end.new(colorize) - warn colorize.notice("Children under ")+colorize.fail(tmpdir)+":" - Dir.chdir(tmpdir) do - ls.list_tree(".") do |path, st| - if st.directory? - Dir.rmdir(path) - else - File.unlink(path) + end.new(colorize) + warn colorize.notice("Children under ")+colorize.fail(tmpdir)+":" + Dir.chdir(tmpdir) do + ls.list_tree(".") do |path, st| + if st.directory? + Dir.rmdir(path) + else + File.unlink(path) + end end end end diff --git a/tool/test-bundled-gems.rb b/tool/test-bundled-gems.rb index 778fe3311aa6f4..58394f4d517bc7 100644 --- a/tool/test-bundled-gems.rb +++ b/tool/test-bundled-gems.rb @@ -93,6 +93,7 @@ puts "#{github_actions ? "::group::\e\[93m" : "\n"}Testing the #{gem} gem#{github_actions ? "\e\[m" : ""}" print "[command]" if github_actions p test_command + start_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) timeouts = {nil => first_timeout, INT: 30, TERM: 10, KILL: nil} if /mingw|mswin/ =~ RUBY_PLATFORM timeouts.delete(:TERM) # Inner process signal on Windows @@ -119,12 +120,17 @@ break end + elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_at print "::endgroup::\n" if github_actions - unless $?.success? + t = " in %.6f sec" % elapsed + + if $?.success? + puts colorize.decorate("Test passed#{t}", "pass") + else mesg = "Tests failed " + ($?.signaled? ? "by SIG#{Signal.signame($?.termsig)}" : - "with exit code #{$?.exitstatus}") + "with exit code #{$?.exitstatus}") + t puts colorize.decorate(mesg, "fail") if allowed_failures.include?(gem) mesg = "Ignoring test failures for #{gem} due to \$TEST_BUNDLED_GEMS_ALLOW_FAILURES or DEFAULT_ALLOWED_FAILURES" diff --git a/zjit.rb b/zjit.rb index f73ef12a63b06f..7c515c391b95c6 100644 --- a/zjit.rb +++ b/zjit.rb @@ -174,6 +174,9 @@ def stats_string if stats[:guard_shape_count]&.nonzero? stats[:guard_shape_exit_ratio] = stats[:exit_guard_shape_failure].to_f / stats[:guard_shape_count] * 100 end + if stats[:code_region_bytes]&.nonzero? + stats[:side_exit_size_ratio] = stats[:side_exit_size].to_f / stats[:code_region_bytes] * 100 + end # Show counters independent from exit_* or dynamic_send_* print_counters_with_prefix(prefix: 'not_inlined_cfuncs_', prompt: 'not inlined C methods', buf:, stats:, limit: 20) @@ -239,7 +242,9 @@ def stats_string :guard_shape_count, :guard_shape_exit_ratio, + :side_exit_size, :code_region_bytes, + :side_exit_size_ratio, :zjit_alloc_bytes, :total_mem_bytes, @@ -291,7 +296,7 @@ def print_counters(keys, buf:, stats:, right_align: false, base: nil) case key when :ratio_in_zjit value = '%0.1f%%' % value - when :guard_type_exit_ratio, :guard_shape_exit_ratio + when :guard_type_exit_ratio, :guard_shape_exit_ratio, :side_exit_size_ratio value = '%0.1f%%' % value when /_time_ns\z/ key = key.to_s.sub(/_time_ns\z/, '_time') diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs index b2ec95a9d4a84c..0a504b8bcc8b4a 100644 --- a/zjit/src/backend/lir.rs +++ b/zjit/src/backend/lir.rs @@ -2273,6 +2273,15 @@ impl Assembler // Map from SideExit to compiled Label. This table is used to deduplicate side exit code. let mut compiled_exits: HashMap = HashMap::new(); + // Mark the start of side-exit code so we can measure its size + if !targets.is_empty() { + self.pos_marker(move |start_pos, cb| { + let end_pos = cb.get_write_ptr(); + let size = end_pos.as_offset() - start_pos.as_offset(); + crate::stats::incr_counter_by(crate::stats::Counter::side_exit_size, size as u64); + }); + } + for ((block_id, idx), target) in targets { // Compile a side exit. Note that this is past the split pass and alloc_regs(), // so you can't use an instruction that returns a VReg. diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 6fc754007f6a82..b9771aad0a7b03 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -160,6 +160,8 @@ make_counters! { profile_time_ns, gc_time_ns, invalidation_time_ns, + + side_exit_size, } // Exit counters that are summed as side_exit_count