diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml index 07c43a0c3b0788..67a350db1c887f 100644 --- a/.github/workflows/check_misc.yml +++ b/.github/workflows/check_misc.yml @@ -35,6 +35,18 @@ jobs: if: ${{ github.repository == 'ruby/ruby' && github.ref == 'refs/heads/master' && github.event_name == 'push' }} continue-on-error: true # The next auto-style should always run + # Sync git.ruby-lang.org before pushing new commits to avoid duplicated syncs + - name: Sync git.ruby-lang.org + env: + RUBY_GIT_SYNC_PRIVATE_KEY: ${{ secrets.RUBY_GIT_SYNC_PRIVATE_KEY }} + run: | + mkdir -p ~/.ssh + echo "$RUBY_GIT_SYNC_PRIVATE_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan -t ed25519 git.ruby-lang.org >> ~/.ssh/known_hosts + ssh -i ~/.ssh/id_ed25519 git-sync@git.ruby-lang.org 'sudo -u git /home/git/git.ruby-lang.org/bin/update-ruby.sh master' + if: ${{ github.repository == 'ruby/ruby' && github.ref == 'refs/heads/master' && github.event_name == 'push' }} + - uses: ./.github/actions/setup/directories with: makeup: true diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index a638a3b1b353dd..0d2b564c41c802 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -101,9 +101,6 @@ jobs: - name: Run configure run: ../src/configure -C --disable-install-doc ${{ matrix.configure }} - - run: make prepare-gems - if: ${{ matrix.test_task == 'test-bundled-gems' }} - - run: make - name: Verify that --zjit-dump-disasm works diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index 99d5dbfdedc390..a30ff1df88fdd9 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -72,6 +72,10 @@ jobs: configure: '--enable-zjit=dev --with-gcc=clang-14' libclang_path: '/usr/lib/llvm-14/lib/libclang.so.1' + - test_task: 'test-bundled-gems' + configure: '--enable-zjit=dev' + run_opts: '--zjit-call-threshold=1' + env: GITPULLOPTIONS: --no-tags origin ${{ github.ref }} RUN_OPTS: ${{ matrix.run_opts }} diff --git a/array.c b/array.c index 2ba95bef186dae..378da150ee3e3e 100644 --- a/array.c +++ b/array.c @@ -4569,7 +4569,7 @@ take_items(VALUE obj, long n) * [:c3, :b3, :a3]] * * For an *object* in *other_arrays* that is not actually an array, - * forms the the "other array" as object.to_ary, if defined, + * forms the "other array" as object.to_ary, if defined, * or as object.each.to_a otherwise. * * Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting]. diff --git a/doc/zjit.md b/doc/zjit.md index c0378031b24bd2..d0d3e361913039 100644 --- a/doc/zjit.md +++ b/doc/zjit.md @@ -150,10 +150,10 @@ Through [Stackprof](https://github.com/tmm1/stackprof), detailed information abo ./miniruby --zjit-trace-exits script.rb ``` -A file called `zjit_exit_locations{timestamp}.dump` will be created in the same directory as `script.rb`. Viewing the side exited methods can be done with Stackprof: +A file called `zjit_exits_{pid}.dump` will be created in the same directory as `script.rb`. Viewing the side exited methods can be done with Stackprof: ```bash -stackprof path/to/zjit_exit_locations{timestamp}.dump +stackprof path/to/zjit_exits_{pid}.dump ``` ## Useful dev commands diff --git a/gems/bundled_gems b/gems/bundled_gems index d37d90bbf14eb2..4b95fa525004f7 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -41,7 +41,7 @@ benchmark 0.4.1 https://github.com/ruby/benchmark logger 1.7.0 https://github.com/ruby/logger rdoc 6.14.2 https://github.com/ruby/rdoc win32ole 1.9.2 https://github.com/ruby/win32ole -irb 1.15.2 https://github.com/ruby/irb 331c4e851296b115db766c291e8cf54a2492fb36 +irb 1.15.2 https://github.com/ruby/irb d43c3d764ae439706aa1b26a3ec299cc45eaed5b reline 0.6.2 https://github.com/ruby/reline readline 0.0.4 https://github.com/ruby/readline fiddle 1.1.8 https://github.com/ruby/fiddle diff --git a/thread_pthread.c b/thread_pthread.c index 5150a6173e6e6b..323659b64945b8 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -90,9 +90,16 @@ static const void *const condattr_monotonic = NULL; #endif #endif +#ifdef HAVE_SCHED_YIELD +#define native_thread_yield() (void)sched_yield() +#else +#define native_thread_yield() ((void)0) +#endif + // native thread wrappers #define NATIVE_MUTEX_LOCK_DEBUG 0 +#define NATIVE_MUTEX_LOCK_DEBUG_YIELD 0 static void mutex_debug(const char *msg, void *lock) @@ -111,6 +118,9 @@ void rb_native_mutex_lock(pthread_mutex_t *lock) { int r; +#if NATIVE_MUTEX_LOCK_DEBUG_YIELD + native_thread_yield(); +#endif mutex_debug("lock", lock); if ((r = pthread_mutex_lock(lock)) != 0) { rb_bug_errno("pthread_mutex_lock", r); @@ -310,12 +320,6 @@ static rb_serial_t current_fork_gen = 1; /* We can't use GET_VM()->fork_gen */ static void threadptr_trap_interrupt(rb_thread_t *); -#ifdef HAVE_SCHED_YIELD -#define native_thread_yield() (void)sched_yield() -#else -#define native_thread_yield() ((void)0) -#endif - static void native_thread_dedicated_inc(rb_vm_t *vm, rb_ractor_t *cr, struct rb_native_thread *nt); static void native_thread_dedicated_dec(rb_vm_t *vm, rb_ractor_t *cr, struct rb_native_thread *nt); static void native_thread_assign(struct rb_native_thread *nt, rb_thread_t *th); diff --git a/tool/lib/core_assertions.rb b/tool/lib/core_assertions.rb index 934ab080372d67..cc4eb327d41106 100644 --- a/tool/lib/core_assertions.rb +++ b/tool/lib/core_assertions.rb @@ -74,10 +74,7 @@ def message msg = nil, ending = nil, &default module CoreAssertions require_relative 'envutil' require 'pp' - begin - require '-test-/asan' - rescue LoadError - end + require '-test-/asan' nil.pretty_inspect @@ -162,7 +159,7 @@ def assert_no_memory_leak(args, prepare, code, message=nil, limit: 2.0, rss: fal pend 'assert_no_memory_leak may consider MJIT memory usage as leak' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # ASAN has the same problem - its shadow memory greatly increases memory usage # (plus asan has better ways to detect memory leaks than this assertion) - pend 'assert_no_memory_leak may consider ASAN memory usage as leak' if defined?(Test::ASAN) && Test::ASAN.enabled? + pend 'assert_no_memory_leak may consider ASAN memory usage as leak' if Test::ASAN.enabled? require_relative 'memory_status' raise Test::Unit::PendedError, "unsupported platform" unless defined?(Memory::Status) diff --git a/tool/test-bundled-gems.rb b/tool/test-bundled-gems.rb index 86bb747d946320..006ebd981af913 100644 --- a/tool/test-bundled-gems.rb +++ b/tool/test-bundled-gems.rb @@ -1,6 +1,7 @@ require 'rbconfig' require 'timeout' require 'fileutils' +require 'shellwords' require_relative 'lib/colorize' require_relative 'lib/gem_env' @@ -25,6 +26,7 @@ rake = File.realpath("../../.bundle/bin/rake", __FILE__) gem_dir = File.realpath('../../gems', __FILE__) rubylib = [gem_dir+'/lib', ENV["RUBYLIB"]].compact.join(File::PATH_SEPARATOR) +run_opts = ENV["RUN_OPTS"]&.shellsplit exit_code = 0 ruby = ENV['RUBY'] || RbConfig.ruby failed = [] @@ -33,7 +35,7 @@ next if bundled_gems&.none? {|pat| File.fnmatch?(pat, gem)} next unless File.directory?("#{gem_dir}/src/#{gem}/test") - test_command = [ruby, "-C", "#{gem_dir}/src/#{gem}", rake, "test"] + test_command = [ruby, *run_opts, "-C", "#{gem_dir}/src/#{gem}", rake, "test"] first_timeout = 600 # 10min toplib = gem @@ -71,7 +73,7 @@ load_path = true when "test-unit" - test_command = [ruby, "-C", "#{gem_dir}/src/#{gem}", "test/run.rb"] + test_command = [ruby, *run_opts, "-C", "#{gem_dir}/src/#{gem}", "test/run.rb"] when "csv" first_timeout = 30 diff --git a/zjit.rb b/zjit.rb index b44154ad9cef1c..75c57f9a35c195 100644 --- a/zjit.rb +++ b/zjit.rb @@ -35,18 +35,17 @@ def exit_locations return unless trace_exit_locations_enabled? results = Primitive.rb_zjit_get_exit_locations - raw_samples = results[:raw].dup - line_samples = results[:lines].dup - frames = results[:frames].dup + raw_samples = results[:raw] + line_samples = results[:lines] + frames = results[:frames] samples_count = 0 - # Loop through the instructions and set the frame hash with the data. - # We use nonexistent.def for the file name, otherwise insns.def will be displayed - # and that information isn't useful in this context. + # Use nonexistent.def as a dummy file name. + frame_template = { samples: 0, total_samples: 0, edges: {}, name: name, file: "nonexistent.def", line: nil, lines: {} } + + # Loop through all possible instructions and setup the frame hash. RubyVM::INSTRUCTION_NAMES.each_with_index do |name, frame_id| - frame_hash = { samples: 0, total_samples: 0, edges: {}, name: name, file: "nonexistent.def", line: nil, lines: {} } - results[:frames][frame_id] = frame_hash - frames[frame_id] = frame_hash + frames[frame_id] = frame_template.dup.tap { |h| h[:name] = name } end # Loop through the raw_samples and build the hashes for StackProf. @@ -100,10 +99,13 @@ def exit_locations end results[:samples] = samples_count - # Set missed_samples and gc_samples to 0 as their values - # don't matter to us in this context. + + # These values are mandatory to include for stackprof, but we don't use them. results[:missed_samples] = 0 results[:gc_samples] = 0 + + results[:frames].reject! { |k, v| v[:samples] == 0 } + results end @@ -277,7 +279,7 @@ def print_stats def dump_locations # :nodoc: return unless trace_exit_locations_enabled? - filename = "zjit_exits_#{Time.now.to_i}.dump" + filename = "zjit_exits_#{Process.pid}.dump" n_bytes = dump_exit_locations(filename) $stderr.puts("#{n_bytes} bytes written to #{filename}.")