[前][次][番号順一覧][スレッド一覧]

ruby-changes:63743

From: Aaron <ko1@a...>
Date: Wed, 25 Nov 2020 07:48:44 +0900 (JST)
Subject: [ruby-changes:63743] 63ad55cd88 (master): Disable auto compaction on platforms that can't support it

https://git.ruby-lang.org/ruby.git/commit/?id=63ad55cd88

From 63ad55cd882e4010fe313d271af006a430b5ffa8 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <tenderlove@r...>
Date: Tue, 24 Nov 2020 14:33:12 -0800
Subject: Disable auto compaction on platforms that can't support it

Auto Compaction uses mprotect to implement a read barrier.  mprotect can
only work on regions of memory that are a multiple of the OS page size.
Ruby's pages are a multiple of 4kb, but some platforms (like ppc64le)
don't have 4kb page sizes.  This commit disables the features on those
platforms.

Fixes [Bug #17306]

diff --git a/gc.c b/gc.c
index 17bc9fd..d5ad476 100644
--- a/gc.c
+++ b/gc.c
@@ -3090,6 +3090,17 @@ Init_heap(void) https://github.com/ruby/ruby/blob/trunk/gc.c#L3090
 {
     rb_objspace_t *objspace = &rb_objspace;
 
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+    /* If Ruby's heap pages are not a multiple of the system page size, we
+     * cannot use mprotect for the read barrier, so we must disable automatic
+     * compaction. */
+    int pagesize;
+    pagesize = (int)sysconf(_SC_PAGE_SIZE);
+    if ((HEAP_PAGE_SIZE % pagesize) != 0) {
+        ruby_enable_autocompact = 0;
+    }
+#endif
+
     objspace->next_object_id = INT2FIX(OBJ_ID_INITIAL);
     objspace->id_to_obj_tbl = st_init_table(&object_id_hash_type);
     objspace->obj_to_id_tbl = st_init_numtable();
@@ -9890,6 +9901,16 @@ gc_disable(rb_execution_context_t *ec, VALUE _) https://github.com/ruby/ruby/blob/trunk/gc.c#L9901
 static VALUE
 gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v)
 {
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+    /* If Ruby's heap pages are not a multiple of the system page size, we
+     * cannot use mprotect for the read barrier, so we must disable automatic
+     * compaction. */
+    int pagesize;
+    pagesize = (int)sysconf(_SC_PAGE_SIZE);
+    if ((HEAP_PAGE_SIZE % pagesize) != 0) {
+        rb_raise(rb_eNotImpError, "Automatic compaction isn't available on this platform");
+    }
+#endif
     ruby_enable_autocompact = RTEST(v);
     return v;
 }
diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb
index 3aad9e6..4a8cff3 100644
--- a/test/ruby/test_gc_compact.rb
+++ b/test/ruby/test_gc_compact.rb
@@ -1,56 +1,82 @@ https://github.com/ruby/ruby/blob/trunk/test/ruby/test_gc_compact.rb#L1
 # frozen_string_literal: true
 require 'test/unit'
 require 'fiddle'
+require 'etc'
 
 class TestGCCompact < Test::Unit::TestCase
-  def test_enable_autocompact
-    before = GC.auto_compact
-    GC.auto_compact = true
-    assert GC.auto_compact
-  ensure
-    GC.auto_compact = before
-  end
+  class AutoCompact < Test::Unit::TestCase
+    def setup
+      skip "autocompact not supported on this platform" unless supports_auto_compact?
+      super
+    end
 
-  def test_disable_autocompact
-    before = GC.auto_compact
-    GC.auto_compact = false
-    refute GC.auto_compact
-  ensure
-    GC.auto_compact = before
-  end
+    def test_enable_autocompact
+      before = GC.auto_compact
+      GC.auto_compact = true
+      assert GC.auto_compact
+    ensure
+      GC.auto_compact = before
+    end
 
-  def test_major_compacts
-    before = GC.auto_compact
-    GC.auto_compact = true
-    compact = GC.stat :compact_count
-    GC.start
-    assert_operator GC.stat(:compact_count), :>, compact
-  ensure
-    GC.auto_compact = before
-  end
+    def test_disable_autocompact
+      before = GC.auto_compact
+      GC.auto_compact = false
+      refute GC.auto_compact
+    ensure
+      GC.auto_compact = before
+    end
 
-  def test_implicit_compaction_does_something
-    before = GC.auto_compact
-    list = []
-    list2 = []
+    def test_major_compacts
+      before = GC.auto_compact
+      GC.auto_compact = true
+      compact = GC.stat :compact_count
+      GC.start
+      assert_operator GC.stat(:compact_count), :>, compact
+    ensure
+      GC.auto_compact = before
+    end
 
-    # Try to make some fragmentation
-    500.times {
-      list << Object.new
-      Object.new
-      Object.new
-    }
-    count = GC.stat :compact_count
-    GC.auto_compact = true
-    loop do
-      break if count < GC.stat(:compact_count)
-      list2 << Object.new
+    def test_implicit_compaction_does_something
+      before = GC.auto_compact
+      list = []
+      list2 = []
+
+      # Try to make some fragmentation
+      500.times {
+        list << Object.new
+        Object.new
+        Object.new
+      }
+      count = GC.stat :compact_count
+      GC.auto_compact = true
+      loop do
+        break if count < GC.stat(:compact_count)
+        list2 << Object.new
+      end
+      compact_stats = GC.latest_compact_info
+      refute_predicate compact_stats[:considered], :empty?
+      refute_predicate compact_stats[:moved], :empty?
+    ensure
+      GC.auto_compact = before
     end
-    compact_stats = GC.latest_compact_info
-    refute_predicate compact_stats[:considered], :empty?
-    refute_predicate compact_stats[:moved], :empty?
-  ensure
-    GC.auto_compact = before
+
+    private
+
+    def supports_auto_compact?
+      return true unless defined?(Etc::SC_PAGE_SIZE)
+
+      begin
+        return GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE] % Etc.sysconf(Etc::SC_PAGE_SIZE) == 0
+      rescue NotImplementedError
+      rescue ArgumentError
+      end
+
+      true
+    end
+  end
+
+  def os_page_size
+    return true unless defined?(Etc::SC_PAGE_SIZE)
   end
 
   def test_gc_compact_stats
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]