Project

General

Profile

Actions

Bug #8092

closed

[patch] gc: improve accuracy of objspace_live_num() and allocated/freed counters

Added by tmm1 (Aman Karmani) about 11 years ago. Updated about 11 years ago.

Status:
Closed
Target version:
-
ruby -v:
ruby 2.1.0dev (2013-03-14 trunk 39748) [x86_64-darwin12.2.1]
Backport:
[ruby-core:53392]

Description

Test with large rails app:

ruby -e'
require "./config/environment"

stat, count = {}, {}
GC.start
GC.stat(stat)
ObjectSpace.count_objects(count)

printf "%d == %d\n", stat[:heap_live_num], count[:TOTAL]-count[:FREE]

'

Without patch:

632974 == 628506

With patch:

628506 == 628506

diff --git a/gc.c b/gc.c
index bd95073..48f9470 100644
--- a/gc.c
+++ b/gc.c
@@ -1432,10 +1432,8 @@ finalize_list(rb_objspace_t *objspace, RVALUE p)
run_final(objspace, (VALUE)p);
if (!FL_TEST(p, FL_SINGLETON)) { /
not freeing page */
add_slot_local_freelist(objspace, p);

  •        if (!is_lazy_sweeping(objspace)) {
    
  •   objspace->total_freed_object_num++;
    
  •   objspace->heap.free_num++;
    
  •        }
    
  •        objspace->total_freed_object_num++;
    
  •        objspace->heap.free_num++;
    
    }
    else {
    struct heaps_slot *slot = (struct heaps_slot *)(VALUE)RDATA(p)->dmark;
    @@ -1939,9 +1937,9 @@ slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
    else {
    sweep_slot->free_next = NULL;
    }
  • objspace->total_freed_object_num += freed_num;
    objspace->heap.free_num += freed_num + empty_num;
    }
  • objspace->total_freed_object_num += freed_num;
    objspace->heap.final_num += final_num;

    if (deferred_final_list && !finalizing) {
    @@ -2965,11 +2963,11 @@ rb_gc_force_recycle(VALUE p)
    rb_objspace_t *objspace = &rb_objspace;
    struct heaps_slot *slot;

  • objspace->total_freed_object_num++;
    if (MARKED_IN_BITMAP(GET_HEAP_BITMAP(p), p)) {
    add_slot_local_freelist(objspace, (RVALUE *)p);
    }
    else {

  • objspace->total_freed_object_num++;
    objspace->heap.free_num++;
    slot = add_slot_local_freelist(objspace, (RVALUE *)p);
    if (slot->free_next == NULL) {

Related issues 1 (0 open1 closed)

Related to Backport200 - Backport #8147: Backport r39812Closednagachika (Tomoyuki Chikanaga)03/22/2013Actions

Updated by authorNari (Narihiro Nakamura) about 11 years ago

  • Category set to core
  • Assignee set to authorNari (Narihiro Nakamura)

Updated by authorNari (Narihiro Nakamura) about 11 years ago

Thank you for bug report.

But, the following test case is failure.

I think ko1-san is the implementer of GC.stat.
ko1-san, what do you think?

=== start ===
$ git diff test
diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb
index bed58f3..8cb036a 100644
--- a/test/ruby/test_gc.rb
+++ b/test/ruby/test_gc.rb
@@ -64,6 +64,15 @@ class TestGc < Test::Unit::TestCase
assert_equal(arg, res)
assert_equal(false, res.empty?)
assert_kind_of(Integer, res[:count])
+

  • stat, count = {}, {}
  • GC.start
  • GC.stat(stat)
  • ObjectSpace.count_objects(count)
  • puts ""
  • p stat
  • p count
  • assert_equal(stat[:heap_live_num], count[:TOTAL]-count[:FREE])
    end

def test_singleton_method

$ % make test-all TESTS='ruby/test_defined.rb ruby/test_integer.rb ruby/test_objectspace.rb ruby/test_sprintf_comb.rb ruby/test_argf.rb ruby/test_fiber.rb ruby/test_gc.rb'
....

Running tests:

[ 91/131] TestGc#test_stat
{:count=>351, :heap_used=>684, :heap_length=>1139, :heap_increment=>399, :heap_live_num=>46061, :heap_free_num=>152639, :heap_final_num=>0, :total_allocated_object=>402509, :total_freed_object=>356448}
{:TOTAL=>198553, :FREE=>152639, :T_OBJECT=>31312, :T_CLASS=>655, :T_MODULE=>56, :T_FLOAT=>10, :T_STRING=>8425, :T_REGEXP=>146, :T_ARRAY=>1966, :T_HASH=>49, :T_STRUCT=>10, :T_BIGNUM=>25, :T_FILE=>10, :T_DATA=>2225, :T_MATCH=>22, :T_COMPLEX=>1, :T_NODE=>934, :T_ICLASS=>68}
= 0.01 s

  1. Failure:
    test_stat(TestGc) [/home/nari/source/ruby/ruby-git/test/ruby/test_gc.rb:75]:
    <46061> expected but was
    <45914>.

Finished tests in 6.628281s, 19.7638 tests/s, 657.9383 assertions/s.
131 tests, 4361 assertions, 1 failures, 0 errors, 0 skips

ruby -v: ruby 2.1.0dev (2013-03-14 trunk 38552) [x86_64-linux]
make: *** [yes-test-all] Error 1
=== end ===

Updated by tmm1 (Aman Karmani) about 11 years ago

This test is passing for me on trunk. Before r39811 it is failing.

[ 92/132] TestGc#test_stat
{:count=>357, :heap_used=>421, :heap_length=>811, :heap_increment=>283, :heap_live_num=>14452, :heap_free_num=>156816, :heap_final_num=>0, :total_allocated_object=>389190, :total_freed_object=>374738}
{:TOTAL=>171268, :FREE=>156816, :T_OBJECT=>46, :T_CLASS=>655, :T_MODULE=>56, :T_FLOAT=>10, :T_STRING=>8268, :T_REGEXP=>145, :T_ARRAY=>1947, :T_HASH=>42, :T_STRUCT=>9, :T_BIGNUM=>25, :T_FILE=>3, :T_DATA=>2221, :T_MATCH=>21, :T_COMPLEX=>1, :T_NODE=>935, :T_ICLASS=>68}
Finished tests in 3.297242s, 40.0335 tests/s, 1313.5220 assertions/s.
132 tests, 4331 assertions, 0 failures, 0 errors, 0 skips

ruby -v: ruby 2.1.0dev (2013-03-18 trunk 39811) [x86_64-linux]

Updated by tmm1 (Aman Karmani) about 11 years ago

With this updated patch the test is passing both before and after r39811. Problem was in finalize_list. After r39811 removing heap is less common, so the failure did not appear.

diff --git a/gc.c b/gc.c
index 2afd311..e72b198 100644
--- a/gc.c
+++ b/gc.c
@@ -1431,12 +1431,10 @@ finalize_list(rb_objspace_t *objspace, RVALUE *p)
while (p) {
RVALUE *tmp = p->as.free.next;
run_final(objspace, (VALUE)p);

  • objspace->total_freed_object_num++;
    if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
    add_slot_local_freelist(objspace, p);
  •        if (!is_lazy_sweeping(objspace)) {
    
  •   objspace->total_freed_object_num++;
    
  •   objspace->heap.free_num++;
    
  •        }
    
  •        objspace->heap.free_num++;
    
    }
    else {
    struct heaps_slot *slot = (struct heaps_slot *)(VALUE)RDATA(p)->dmark;
    @@ -1940,9 +1938,9 @@ slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
    else {
    sweep_slot->free_next = NULL;
    }
  • objspace->total_freed_object_num += freed_num;
    objspace->heap.free_num += freed_num + empty_num;
    }
  • objspace->total_freed_object_num += freed_num;
    objspace->heap.final_num += final_num;

    if (deferred_final_list && !finalizing) {
    @@ -2969,11 +2967,11 @@ rb_gc_force_recycle(VALUE p)
    rb_objspace_t *objspace = &rb_objspace;
    struct heaps_slot *slot;

  • objspace->total_freed_object_num++;
    if (MARKED_IN_BITMAP(GET_HEAP_BITMAP(p), p)) {
    add_slot_local_freelist(objspace, (RVALUE *)p);
    }
    else {

  • objspace->total_freed_object_num++;
    objspace->heap.free_num++;
    slot = add_slot_local_freelist(objspace, (RVALUE *)p);
    if (slot->free_next == NULL) {
    diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb
    index 90c4787..b1e52fc 100644
    --- a/test/ruby/test_gc.rb
    +++ b/test/ruby/test_gc.rb
    @@ -64,6 +64,12 @@ class TestGc < Test::Unit::TestCase
    assert_equal(arg, res)
    assert_equal(false, res.empty?)
    assert_kind_of(Integer, res[:count])
  • stat, count = {}, {}
  • GC.start
  • GC.stat(stat)
  • ObjectSpace.count_objects(count)
  • assert_equal(count[:TOTAL]-count[:FREE], stat[:heap_live_num])
    end

def test_singleton_method

Updated by authorNari (Narihiro Nakamura) about 11 years ago

Wow, thanks!! I'll commit it soon.

Actions #6

Updated by authorNari (Narihiro Nakamura) about 11 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r39812.
Aman, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • gc.c: Improve accuracy of objspace_live_num() and
    allocated/freed counters. patched by tmm1(Aman Gupta).
    [Bug #8092] [ruby-core:53392]
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0