You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
13 KiB
403 lines
13 KiB
2 years ago
|
commit 6d1ca6737f31b2e24664a093f1827dd74a121a9f
|
||
|
Author: Jarek Prokop <jprokop@redhat.com>
|
||
|
Date: Thu May 26 11:28:13 2022 +0200
|
||
|
|
||
|
Gc ppc64le fix
|
||
|
|
||
|
diff --git a/gc.c b/gc.c
|
||
|
index ef9327df1f..1c35856c44 100644
|
||
|
--- a/gc.c
|
||
|
+++ b/gc.c
|
||
|
@@ -9421,6 +9421,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size)
|
||
|
return (VALUE)src;
|
||
|
}
|
||
|
|
||
|
+#if GC_COMPACTION_SUPPORTED
|
||
|
static int
|
||
|
compare_free_slots(const void *left, const void *right, void *dummy)
|
||
|
{
|
||
|
@@ -9468,6 +9469,7 @@ gc_sort_heap_by_empty_slots(rb_objspace_t *objspace)
|
||
|
free(page_list);
|
||
|
}
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
static void
|
||
|
gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
|
||
|
@@ -10147,8 +10149,21 @@ gc_update_references(rb_objspace_t *objspace)
|
||
|
gc_update_table_refs(objspace, finalizer_table);
|
||
|
}
|
||
|
|
||
|
+#if GC_COMPACTION_SUPPORTED
|
||
|
+/*
|
||
|
+ * call-seq:
|
||
|
+ * GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
|
||
|
+ *
|
||
|
+ * Returns information about object moved in the most recent GC compaction.
|
||
|
+ *
|
||
|
+ * The returned hash has two keys :considered and :moved. The hash for
|
||
|
+ * :considered lists the number of objects that were considered for movement
|
||
|
+ * by the compactor, and the :moved hash lists the number of objects that
|
||
|
+ * were actually moved. Some objects can't be moved (maybe they were pinned)
|
||
|
+ * so these numbers can be used to calculate compaction efficiency.
|
||
|
+ */
|
||
|
static VALUE
|
||
|
-gc_compact_stats(rb_execution_context_t *ec, VALUE self)
|
||
|
+gc_compact_stats(VALUE self)
|
||
|
{
|
||
|
size_t i;
|
||
|
rb_objspace_t *objspace = &rb_objspace;
|
||
|
@@ -10171,7 +10186,11 @@ gc_compact_stats(rb_execution_context_t *ec, VALUE self)
|
||
|
|
||
|
return h;
|
||
|
}
|
||
|
+#else
|
||
|
+# define gc_compact_stats rb_f_notimplement
|
||
|
+#endif
|
||
|
|
||
|
+#if GC_COMPACTION_SUPPORTED
|
||
|
static void
|
||
|
root_obj_check_moved_i(const char *category, VALUE obj, void *data)
|
||
|
{
|
||
|
@@ -10221,22 +10240,78 @@ heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * call-seq:
|
||
|
+ * GC.compact
|
||
|
+ *
|
||
|
+ * This function compacts objects together in Ruby's heap. It eliminates
|
||
|
+ * unused space (or fragmentation) in the heap by moving objects in to that
|
||
|
+ * unused space. This function returns a hash which contains statistics about
|
||
|
+ * which objects were moved. See `GC.latest_gc_info` for details about
|
||
|
+ * compaction statistics.
|
||
|
+ *
|
||
|
+ * This method is implementation specific and not expected to be implemented
|
||
|
+ * in any implementation besides MRI.
|
||
|
+ *
|
||
|
+ * To test whether GC compaction is supported, use the idiom:
|
||
|
+ *
|
||
|
+ * GC.respond_to?(:compact)
|
||
|
+ */
|
||
|
static VALUE
|
||
|
-gc_compact(rb_execution_context_t *ec, VALUE self)
|
||
|
+gc_compact(VALUE self)
|
||
|
{
|
||
|
/* Run GC with compaction enabled */
|
||
|
- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qtrue);
|
||
|
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);
|
||
|
|
||
|
- return gc_compact_stats(ec, self);
|
||
|
+ return gc_compact_stats(self);
|
||
|
}
|
||
|
+#else
|
||
|
+# define gc_compact rb_f_notimplement
|
||
|
+#endif
|
||
|
|
||
|
+#if GC_COMPACTION_SUPPORTED
|
||
|
+/*
|
||
|
+ * call-seq:
|
||
|
+ * GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
|
||
|
+ *
|
||
|
+ * Verify compaction reference consistency.
|
||
|
+ *
|
||
|
+ * This method is implementation specific. During compaction, objects that
|
||
|
+ * were moved are replaced with T_MOVED objects. No object should have a
|
||
|
+ * reference to a T_MOVED object after compaction.
|
||
|
+ *
|
||
|
+ * This function doubles the heap to ensure room to move all objects,
|
||
|
+ * compacts the heap to make sure everything moves, updates all references,
|
||
|
+ * then performs a full GC. If any object contains a reference to a T_MOVED
|
||
|
+ * object, that object should be pushed on the mark stack, and will
|
||
|
+ * make a SEGV.
|
||
|
+ */
|
||
|
static VALUE
|
||
|
-gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE double_heap, VALUE toward_empty)
|
||
|
+gc_verify_compaction_references(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
rb_objspace_t *objspace = &rb_objspace;
|
||
|
+ VALUE kwargs, double_heap = Qfalse, toward_empty = Qfalse;
|
||
|
+ static ID id_toward, id_double_heap, id_empty;
|
||
|
+
|
||
|
+ if (!id_toward) {
|
||
|
+ id_toward = rb_intern("toward");
|
||
|
+ id_double_heap = rb_intern("double_heap");
|
||
|
+ id_empty = rb_intern("empty");
|
||
|
+ }
|
||
|
+
|
||
|
+ rb_scan_args(argc, argv, ":", &kwargs);
|
||
|
+ if (!NIL_P(kwargs)) {
|
||
|
+ if (rb_hash_has_key(kwargs, ID2SYM(id_toward))) {
|
||
|
+ VALUE toward = rb_hash_aref(kwargs, ID2SYM(id_toward));
|
||
|
+ toward_empty = (toward == ID2SYM(id_empty)) ? Qtrue : Qfalse;
|
||
|
+ }
|
||
|
+ if (rb_hash_has_key(kwargs, ID2SYM(id_double_heap))) {
|
||
|
+ double_heap = rb_hash_aref(kwargs, ID2SYM(id_double_heap));
|
||
|
+ }
|
||
|
+ }
|
||
|
|
||
|
/* Clear the heap. */
|
||
|
- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qfalse);
|
||
|
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qfalse);
|
||
|
|
||
|
RB_VM_LOCK_ENTER();
|
||
|
{
|
||
|
@@ -10256,13 +10331,16 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do
|
||
|
}
|
||
|
RB_VM_LOCK_LEAVE();
|
||
|
|
||
|
- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qtrue);
|
||
|
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);
|
||
|
|
||
|
objspace_reachable_objects_from_root(objspace, root_obj_check_moved_i, NULL);
|
||
|
objspace_each_objects(objspace, heap_check_moved_i, NULL, TRUE);
|
||
|
|
||
|
- return gc_compact_stats(ec, self);
|
||
|
+ return gc_compact_stats(self);
|
||
|
}
|
||
|
+#else
|
||
|
+# define gc_verify_compaction_references rb_f_notimplement
|
||
|
+#endif
|
||
|
|
||
|
VALUE
|
||
|
rb_gc_start(void)
|
||
|
@@ -10722,26 +10800,45 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
|
||
|
return rb_gc_disable();
|
||
|
}
|
||
|
|
||
|
+#if GC_COMPACTION_SUPPORTED
|
||
|
+/*
|
||
|
+ * call-seq:
|
||
|
+ * GC.auto_compact = flag
|
||
|
+ *
|
||
|
+ * Updates automatic compaction mode.
|
||
|
+ *
|
||
|
+ * When enabled, the compactor will execute on every major collection.
|
||
|
+ *
|
||
|
+ * Enabling compaction will degrade performance on major collections.
|
||
|
+ */
|
||
|
static VALUE
|
||
|
-gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v)
|
||
|
+gc_set_auto_compact(VALUE _, VALUE v)
|
||
|
{
|
||
|
/* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
|
||
|
* the read barrier, so we must disable automatic compaction. */
|
||
|
-#if !defined(__MINGW32__) && !defined(_WIN32)
|
||
|
- if (!USE_MMAP_ALIGNED_ALLOC) {
|
||
|
- rb_raise(rb_eNotImpError, "Automatic compaction isn't available on this platform");
|
||
|
- }
|
||
|
-#endif
|
||
|
|
||
|
ruby_enable_autocompact = RTEST(v);
|
||
|
return v;
|
||
|
}
|
||
|
+#else
|
||
|
+# define gc_set_auto_compact rb_f_notimplement
|
||
|
+#endif
|
||
|
|
||
|
+#if GC_COMPACTION_SUPPORTED
|
||
|
+/*
|
||
|
+ * call-seq:
|
||
|
+ * GC.auto_compact -> true or false
|
||
|
+ *
|
||
|
+ * Returns whether or not automatic compaction has been enabled.
|
||
|
+ */
|
||
|
static VALUE
|
||
|
-gc_get_auto_compact(rb_execution_context_t *ec, VALUE _)
|
||
|
+gc_get_auto_compact(VALUE _)
|
||
|
{
|
||
|
return RBOOL(ruby_enable_autocompact);
|
||
|
}
|
||
|
+#else
|
||
|
+# define gc_get_auto_compact rb_f_notimplement
|
||
|
+#endif
|
||
|
|
||
|
static int
|
||
|
get_envparam_size(const char *name, size_t *default_value, size_t lower_bound)
|
||
|
@@ -13599,6 +13696,11 @@ Init_GC(void)
|
||
|
rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
|
||
|
rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
|
||
|
#endif
|
||
|
+ rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0);
|
||
|
+ rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0);
|
||
|
+ rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1);
|
||
|
+ rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0);
|
||
|
+ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1);
|
||
|
|
||
|
#if GC_DEBUG_STRESS_TO_CLASS
|
||
|
rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1);
|
||
|
diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb
|
||
|
index 42ad028530..411d5eab69 100644
|
||
|
--- a/test/ruby/test_gc_compact.rb
|
||
|
+++ b/test/ruby/test_gc_compact.rb
|
||
|
@@ -9,14 +9,7 @@
|
||
|
end
|
||
|
|
||
|
class TestGCCompact < Test::Unit::TestCase
|
||
|
- module SupportsCompact
|
||
|
- def setup
|
||
|
- skip "autocompact not supported on this platform" unless supports_auto_compact?
|
||
|
- super
|
||
|
- end
|
||
|
-
|
||
|
- private
|
||
|
-
|
||
|
+ module CompactionSupportInspector
|
||
|
def supports_auto_compact?
|
||
|
return true unless defined?(Etc::SC_PAGE_SIZE)
|
||
|
|
||
|
@@ -30,10 +23,19 @@ def supports_auto_compact?
|
||
|
end
|
||
|
end
|
||
|
|
||
|
- include SupportsCompact
|
||
|
+ module OmitUnlessCompactSupported
|
||
|
+ include CompactionSupportInspector
|
||
|
+
|
||
|
+ def setup
|
||
|
+ omit "autocompact not supported on this platform" unless supports_auto_compact?
|
||
|
+ super
|
||
|
+ end
|
||
|
+ end
|
||
|
+
|
||
|
+ include OmitUnlessCompactSupported
|
||
|
|
||
|
class AutoCompact < Test::Unit::TestCase
|
||
|
- include SupportsCompact
|
||
|
+ include OmitUnlessCompactSupported
|
||
|
|
||
|
def test_enable_autocompact
|
||
|
before = GC.auto_compact
|
||
|
@@ -87,13 +89,39 @@ def test_implicit_compaction_does_something
|
||
|
end
|
||
|
end
|
||
|
|
||
|
- def os_page_size
|
||
|
- return true unless defined?(Etc::SC_PAGE_SIZE)
|
||
|
+ class CompactMethodsNotImplemented < Test::Unit::TestCase
|
||
|
+ include CompactionSupportInspector
|
||
|
+
|
||
|
+ def assert_not_implemented(method, *args)
|
||
|
+ omit "autocompact is supported on this platform" if supports_auto_compact?
|
||
|
+
|
||
|
+ assert_raise(NotImplementedError) { GC.send(method, *args) }
|
||
|
+ refute(GC.respond_to?(method), "GC.#{method} should be defined as rb_f_notimplement")
|
||
|
+ end
|
||
|
+
|
||
|
+ def test_gc_compact_not_implemented
|
||
|
+ assert_not_implemented(:compact)
|
||
|
+ end
|
||
|
+
|
||
|
+ def test_gc_auto_compact_get_not_implemented
|
||
|
+ assert_not_implemented(:auto_compact)
|
||
|
+ end
|
||
|
+
|
||
|
+ def test_gc_auto_compact_set_not_implemented
|
||
|
+ assert_not_implemented(:auto_compact=, true)
|
||
|
+ end
|
||
|
+
|
||
|
+ def test_gc_latest_compact_info_not_implemented
|
||
|
+ assert_not_implemented(:latest_compact_info)
|
||
|
+ end
|
||
|
+
|
||
|
+ def test_gc_verify_compaction_references_not_implemented
|
||
|
+ assert_not_implemented(:verify_compaction_references)
|
||
|
+ end
|
||
|
end
|
||
|
|
||
|
- def setup
|
||
|
- skip "autocompact not supported on this platform" unless supports_auto_compact?
|
||
|
- super
|
||
|
+ def os_page_size
|
||
|
+ return true unless defined?(Etc::SC_PAGE_SIZE)
|
||
|
end
|
||
|
|
||
|
def test_gc_compact_stats
|
||
|
diff --git a/gc.rb b/gc.rb
|
||
|
index 72637f3796..9265dd7b57 100644
|
||
|
--- a/gc.rb
|
||
|
+++ b/gc.rb
|
||
|
@@ -38,27 +38,6 @@ def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
|
||
|
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
|
||
|
end
|
||
|
|
||
|
- # call-seq:
|
||
|
- # GC.auto_compact -> true or false
|
||
|
- #
|
||
|
- # Returns whether or not automatic compaction has been enabled.
|
||
|
- #
|
||
|
- def self.auto_compact
|
||
|
- Primitive.gc_get_auto_compact
|
||
|
- end
|
||
|
-
|
||
|
- # call-seq:
|
||
|
- # GC.auto_compact = flag
|
||
|
- #
|
||
|
- # Updates automatic compaction mode.
|
||
|
- #
|
||
|
- # When enabled, the compactor will execute on every major collection.
|
||
|
- #
|
||
|
- # Enabling compaction will degrade performance on major collections.
|
||
|
- def self.auto_compact=(flag)
|
||
|
- Primitive.gc_set_auto_compact(flag)
|
||
|
- end
|
||
|
-
|
||
|
# call-seq:
|
||
|
# GC.enable -> true or false
|
||
|
#
|
||
|
@@ -210,53 +189,6 @@ def self.latest_gc_info hash_or_key = nil
|
||
|
Primitive.gc_latest_gc_info hash_or_key
|
||
|
end
|
||
|
|
||
|
- # call-seq:
|
||
|
- # GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
|
||
|
- #
|
||
|
- # Returns information about object moved in the most recent GC compaction.
|
||
|
- #
|
||
|
- # The returned hash has two keys :considered and :moved. The hash for
|
||
|
- # :considered lists the number of objects that were considered for movement
|
||
|
- # by the compactor, and the :moved hash lists the number of objects that
|
||
|
- # were actually moved. Some objects can't be moved (maybe they were pinned)
|
||
|
- # so these numbers can be used to calculate compaction efficiency.
|
||
|
- def self.latest_compact_info
|
||
|
- Primitive.gc_compact_stats
|
||
|
- end
|
||
|
-
|
||
|
- # call-seq:
|
||
|
- # GC.compact
|
||
|
- #
|
||
|
- # This function compacts objects together in Ruby's heap. It eliminates
|
||
|
- # unused space (or fragmentation) in the heap by moving objects in to that
|
||
|
- # unused space. This function returns a hash which contains statistics about
|
||
|
- # which objects were moved. See `GC.latest_gc_info` for details about
|
||
|
- # compaction statistics.
|
||
|
- #
|
||
|
- # This method is implementation specific and not expected to be implemented
|
||
|
- # in any implementation besides MRI.
|
||
|
- def self.compact
|
||
|
- Primitive.gc_compact
|
||
|
- end
|
||
|
-
|
||
|
- # call-seq:
|
||
|
- # GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
|
||
|
- #
|
||
|
- # Verify compaction reference consistency.
|
||
|
- #
|
||
|
- # This method is implementation specific. During compaction, objects that
|
||
|
- # were moved are replaced with T_MOVED objects. No object should have a
|
||
|
- # reference to a T_MOVED object after compaction.
|
||
|
- #
|
||
|
- # This function doubles the heap to ensure room to move all objects,
|
||
|
- # compacts the heap to make sure everything moves, updates all references,
|
||
|
- # then performs a full GC. If any object contains a reference to a T_MOVED
|
||
|
- # object, that object should be pushed on the mark stack, and will
|
||
|
- # make a SEGV.
|
||
|
- def self.verify_compaction_references(toward: nil, double_heap: false)
|
||
|
- Primitive.gc_verify_compaction_references(double_heap, toward == :empty)
|
||
|
- end
|
||
|
-
|
||
|
# call-seq:
|
||
|
# GC.using_rvargc? -> true or false
|
||
|
#
|