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:
parent
97ac1f6767
commit
241c1a5459
5 changed files with 126 additions and 57 deletions
13
ChangeLog
13
ChangeLog
|
@ -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
6
NEWS
|
@ -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
157
gc.c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" }
|
||||
|
|
Loading…
Reference in a new issue