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/