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

ruby-changes:31926

From: tmm1 <ko1@a...>
Date: Thu, 5 Dec 2013 16:45:22 +0900 (JST)
Subject: [ruby-changes:31926] tmm1:r44005 (trunk): gc.c: expose GC.stat() to C-api via rb_gc_stat()

tmm1	2013-12-05 16:45:13 +0900 (Thu, 05 Dec 2013)

  New Revision: 44005

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=44005

  Log:
    gc.c: expose GC.stat() to C-api via rb_gc_stat()
    
    * include/ruby/intern.h: add rb_gc_stat() for access to GC.stat
      variables from c-api
    * gc.c (rb_gc_stat): new c-api method. accepts either VALUE hash like
      GC.stat, or VALUE symbol key and returns size_t directly. the second
      form is useful to avoid allocations, i.e. for usage inside
      INTERNAL_EVENT_GC tracepoints.
    * gc.c (gc_stat): add GC.stat(:key) to return single value instead of hash
    * gc.c (gc_stat_internal): helper method to retrieve single or all stat values
    * test/ruby/test_gc.rb (class TestGc): test for new behavior
    * NEWS: note about this new api

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/gc.c
    trunk/include/ruby/intern.h
    trunk/test/ruby/test_gc.rb
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 44004)
+++ include/ruby/intern.h	(revision 44005)
@@ -486,6 +486,7 @@ DEPRECATED(void rb_gc_set_params(void)); https://github.com/ruby/ruby/blob/trunk/include/ruby/intern.h#L486
 VALUE rb_define_finalizer(VALUE, VALUE);
 VALUE rb_undefine_finalizer(VALUE);
 size_t rb_gc_count(void);
+size_t rb_gc_stat(VALUE);
 /* hash.c */
 void st_foreach_safe(struct st_table *, int (*)(ANYARGS), st_data_t);
 VALUE rb_check_hash_type(VALUE);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 44004)
+++ ChangeLog	(revision 44005)
@@ -1,3 +1,16 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Dec  5 16:11:04 2013  Aman Gupta <ruby@t...>
+
+	* include/ruby/intern.h: add rb_gc_stat() for access to GC.stat
+	  variables from c-api
+	* gc.c (rb_gc_stat): new c-api method. accepts either VALUE hash like
+	  GC.stat, or VALUE symbol key and returns size_t directly. the second
+	  form is useful to avoid allocations, i.e. for usage inside
+	  INTERNAL_EVENT_GC tracepoints.
+	* gc.c (gc_stat): add GC.stat(:key) to return single value instead of hash
+	* gc.c (gc_stat_internal): helper method to retrieve single or all stat values
+	* test/ruby/test_gc.rb (class TestGc): test for new behavior
+	* NEWS: note about this new api
+
 Thu Dec  5 14:40:41 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* hash.c (rb_hash): revert r43981 and bail out to the outermost frame
Index: gc.c
===================================================================
--- gc.c	(revision 44004)
+++ gc.c	(revision 44005)
@@ -5056,49 +5056,9 @@ gc_count(VALUE self) https://github.com/ruby/ruby/blob/trunk/gc.c#L5056
     return SIZET2NUM(rb_gc_count());
 }
 
-/*
- *  call-seq:
- *     GC.stat -> Hash
- *
- *  Returns a Hash containing information about the GC.
- *
- *  The hash includes information about internal statistics about GC such as:
- *
- *	{
- *          :count=>2,
- *          :heap_used=>9,
- *          :heap_length=>11,
- *          :heap_increment=>2,
- *          :heap_live_slot=>6836,
- *          :heap_free_slot=>519,
- *          :heap_final_slot=>0,
- *          :heap_swept_slot=>818,
- *          :total_allocated_object=>7674,
- *          :total_freed_object=>838,
- *          :malloc_increase=>181034,
- *          :malloc_limit=>16777216,
- *          :minor_gc_count=>2,
- *          :major_gc_count=>0,
- *          :remembered_shady_object=>55,
- *          :remembered_shady_object_limit=>0,
- *          :old_object=>2422,
- *          :old_object_limit=>0,
- *          :oldmalloc_increase=>277386,
- *          :oldmalloc_limit=>16777216
- *	}
- *
- *  The contents of the hash are implementation specific and may be changed in
- *  the future.
- *
- *  This method is only expected to work on C Ruby.
- *
- */
-
 static VALUE
-gc_stat(int argc, VALUE *argv, VALUE self)
+gc_stat_internal(VALUE hash_or_sym, size_t *out)
 {
-    rb_objspace_t *objspace = &rb_objspace;
-    VALUE hash;
     static VALUE sym_count;
     static VALUE sym_heap_used, sym_heap_length, sym_heap_increment;
     static VALUE sym_heap_live_slot, sym_heap_free_slot, sym_heap_final_slot, sym_heap_swept_slot;
@@ -5120,6 +5080,16 @@ gc_stat(int argc, VALUE *argv, VALUE sel https://github.com/ruby/ruby/blob/trunk/gc.c#L5080
 #endif /* RGENGC_PROFILE */
 #endif /* USE_RGENGC */
 
+    rb_objspace_t *objspace = &rb_objspace;
+    VALUE hash = Qnil, key = Qnil;
+
+    if (RB_TYPE_P(hash_or_sym, T_HASH))
+	hash = hash_or_sym;
+    else if (SYMBOL_P(hash_or_sym) && out)
+	key = hash_or_sym;
+    else
+	rb_raise(rb_eArgError, "non-hash or symbol argument");
+
     if (sym_count == 0) {
 #define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
 	S(count);
@@ -5161,17 +5131,12 @@ gc_stat(int argc, VALUE *argv, VALUE sel https://github.com/ruby/ruby/blob/trunk/gc.c#L5131
 #undef S
     }
 
-    if (rb_scan_args(argc, argv, "01", &hash) == 1) {
-	if (!RB_TYPE_P(hash, T_HASH)) {
-	    rb_raise(rb_eTypeError, "non-hash given");
-	}
-    }
+#define SET(name, attr) \
+    if (key == sym_##name) \
+	return (*out = attr, Qnil); \
+    else if (hash != Qnil) \
+	rb_hash_aset(hash, sym_##name, SIZET2NUM(attr));
 
-    if (hash == Qnil) {
-        hash = rb_hash_new();
-    }
-
-#define SET(name, attr) rb_hash_aset(hash, sym_##name, SIZET2NUM(attr))
     SET(count, objspace->profile.count);
 
     /* implementation dependent counters */
@@ -5211,8 +5176,15 @@ gc_stat(int argc, VALUE *argv, VALUE sel https://github.com/ruby/ruby/blob/trunk/gc.c#L5176
 #endif
     SET(remembered_normal_object_count, objspace->profile.remembered_normal_object_count);
     SET(remembered_shady_object_count, objspace->profile.remembered_shady_object_count);
-#if RGENGC_PROFILE >= 2
-    {
+#endif /* RGENGC_PROFILE */
+#endif /* USE_RGENGC */
+#undef SET
+
+    if (key != Qnil) /* matched key should return above */
+	rb_raise(rb_eArgError, "unknown key: %s", RSTRING_PTR(rb_id2str(SYM2ID(key))));
+
+#if defined(RGENGC_PROFILE) && RGENGC_PROFILE >= 2
+    if (hash != Qnil) {
 	gc_count_add_each_types(hash, "generated_normal_object_count_types", objspace->profile.generated_normal_object_count_types);
 	gc_count_add_each_types(hash, "generated_shady_object_count_types", objspace->profile.generated_shady_object_count_types);
 	gc_count_add_each_types(hash, "shade_operation_count_types", objspace->profile.shade_operation_count_types);
@@ -5224,13 +5196,86 @@ gc_stat(int argc, VALUE *argv, VALUE sel https://github.com/ruby/ruby/blob/trunk/gc.c#L5196
 	gc_count_add_each_types(hash, "remembered_shady_object_count_types", objspace->profile.remembered_shady_object_count_types);
     }
 #endif
-#endif /* RGENGC_PROFILE */
-#endif /* USE_RGENGC */
-#undef SET
+
     return hash;
 }
 
 /*
+ *  call-seq:
+ *     GC.stat -> Hash
+ *     GC.stat(hash) -> hash
+ *     GC.stat(:key) -> Numeric
+ *
+ *  Returns a Hash containing information about the GC.
+ *
+ *  The hash includes information about internal statistics about GC such as:
+ *
+ *	{
+ *          :count=>2,
+ *          :heap_used=>9,
+ *          :heap_length=>11,
+ *          :heap_increment=>2,
+ *          :heap_live_slot=>6836,
+ *          :heap_free_slot=>519,
+ *          :heap_final_slot=>0,
+ *          :heap_swept_slot=>818,
+ *          :total_allocated_object=>7674,
+ *          :total_freed_object=>838,
+ *          :malloc_increase=>181034,
+ *          :malloc_limit=>16777216,
+ *          :minor_gc_count=>2,
+ *          :major_gc_count=>0,
+ *          :remembered_shady_object=>55,
+ *          :remembered_shady_object_limit=>0,
+ *          :old_object=>2422,
+ *          :old_object_limit=>0,
+ *          :oldmalloc_increase=>277386,
+ *          :oldmalloc_limit=>16777216
+ *	}
+ *
+ *  The contents of the hash are implementation specific and may be changed in
+ *  the future.
+ *
+ *  This method is only expected to work on C Ruby.
+ *
+ */
+
+static VALUE
+gc_stat(int argc, VALUE *argv, VALUE self)
+{
+    VALUE arg = Qnil;
+
+    if (rb_scan_args(argc, argv, "01", &arg) == 1) {
+	if (SYMBOL_P(arg)) {
+	    size_t value = 0;
+	    gc_stat_internal(arg, &value);
+	    return SIZET2NUM(value);
+	} else if (!RB_TYPE_P(arg, T_HASH)) {
+	    rb_raise(rb_eTypeError, "non-hash given");
+	}
+    }
+
+    if (arg == Qnil) {
+        arg = rb_hash_new();
+    }
+    gc_stat_internal(arg, 0);
+    return arg;
+}
+
+size_t
+rb_gc_stat(VALUE key)
+{
+    if (SYMBOL_P(key)) {
+	size_t value = 0;
+	gc_stat_internal(key, &value);
+	return value;
+    } else {
+	gc_stat_internal(key, 0);
+	return 0;
+    }
+}
+
+/*
  *  call-seq:
  *    GC.stress	    -> fixnum, true or false
  *
Index: NEWS
===================================================================
--- NEWS	(revision 44004)
+++ NEWS	(revision 44005)
@@ -319,6 +319,9 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L319
 
 * rb_gc_count() added. This returns the number of times GC occurred.
 
+* rb_gc_stat() added. This allows access to specific GC.stat() values from C
+  without any allocation overhead.
+
 * rb_postponed_job_register() added. Takes a function callback which is invoked
   when the VM is in a consistent state, i.e. to perform work from a C signal
   handler.
@@ -330,6 +333,7 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L333
   * RUBY_INTERNAL_EVENT_NEWOBJ
   * RUBY_INTERNAL_EVENT_FREEOBJ
   * RUBY_INTERNAL_EVENT_GC_START
-  * RUBY_INTERNAL_EVENT_GC_END
+  * RUBY_INTERNAL_EVENT_GC_END_MARK
+  * RUBY_INTERNAL_EVENT_GC_END_SWEEP
   * Note that you *can not* specify "internal events" with normal events
     (such as RUBY_EVENT_CALL, RUBY_EVENT_RETURN) simultaneously.
Index: test/ruby/test_gc.rb
===================================================================
--- test/ruby/test_gc.rb	(revision 44004)
+++ test/ruby/test_gc.rb	(revision 44005)
@@ -79,6 +79,12 @@ class TestGc < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_gc.rb#L79
     assert_equal(count[:FREE], stat[:heap_free_slot])
   end
 
+  def test_stat_single
+    stat = GC.stat
+    assert_equal stat[:count], GC.stat(:count)
+    assert_raise(ArgumentError){ GC.stat(:invalid) }
+  end
+
   def test_gc_reason
     GC.start
     GC.stat[:heap_free_slot].times{ "a" + "b" }

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

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