1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44005 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
tmm1 2013-12-05 07:45:13 +00:00
parent 97ac1f6767
commit 241c1a5459
5 changed files with 126 additions and 57 deletions

View file

@ -1,3 +1,16 @@
Thu Dec 5 16:11:04 2013 Aman Gupta <ruby@tmm1.net>
* 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@ruby-lang.org>
* hash.c (rb_hash): revert r43981 and bail out to the outermost frame

6
NEWS
View file

@ -319,6 +319,9 @@ with all sufficient information, see the ChangeLog file.
* 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 ChangeLog file.
* 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.

157
gc.c
View file

@ -5056,49 +5056,9 @@ gc_count(VALUE self)
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 self)
#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 self)
#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 self)
#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,12 +5196,85 @@ gc_stat(int argc, VALUE *argv, VALUE self)
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

View file

@ -486,6 +486,7 @@ DEPRECATED(void rb_gc_set_params(void));
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);

View file

@ -79,6 +79,12 @@ class TestGc < Test::Unit::TestCase
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" }