mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Implemented ObjectSpace.count_objects to count the number of allocated objects for each type
This commit is contained in:
@@ -29,6 +29,8 @@ mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_valu
|
||||
mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key);
|
||||
mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash);
|
||||
mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
|
||||
mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self);
|
||||
mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash);
|
||||
|
||||
/* RHASH_TBL allocates st_table if not available. */
|
||||
#define RHASH(obj) ((struct RHash*)((obj).value.p))
|
||||
|
||||
@@ -1141,6 +1141,103 @@ gc_generational_mode_set(mrb_state *mrb, mrb_value self)
|
||||
return mrb_bool_value(enable);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ObjectSpace.count_objects([result_hash]) -> hash
|
||||
*
|
||||
* Counts objects for each type.
|
||||
*
|
||||
* It returns a hash, such as:
|
||||
* {
|
||||
* :TOTAL=>10000,
|
||||
* :FREE=>3011,
|
||||
* :MRB_TT_OBJECT=>6,
|
||||
* :MRB_TT_CLASS=>404,
|
||||
* # ...
|
||||
* }
|
||||
*
|
||||
* If the optional argument +result_hash+ is given,
|
||||
* it is overwritten and returned. This is intended to avoid probe effect.
|
||||
*
|
||||
*/
|
||||
|
||||
mrb_value os_count_objects(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
size_t counts[MRB_TT_MAXDEFINE+1];
|
||||
size_t freed = 0;
|
||||
size_t total = 0;
|
||||
size_t i;
|
||||
mrb_value hash;
|
||||
struct heap_page* page = mrb->heaps;
|
||||
|
||||
if (mrb_get_args(mrb, "|H", &hash) == 0) {
|
||||
hash = mrb_hash_new(mrb);
|
||||
}
|
||||
|
||||
if (!mrb_test(mrb_hash_empty_p(mrb, hash))) {
|
||||
mrb_hash_clear(mrb, hash);
|
||||
}
|
||||
|
||||
for (i = 0; i <= MRB_TT_MAXDEFINE; i++) {
|
||||
counts[i] = 0;
|
||||
}
|
||||
|
||||
while (page != NULL) {
|
||||
RVALUE *p, *pend;
|
||||
|
||||
p = page->objects;
|
||||
pend = p + MRB_HEAP_PAGE_SIZE;
|
||||
for (;p < pend; p++) {
|
||||
if (p->as.basic.flags) {
|
||||
counts[mrb_type(p->as.basic)]++;
|
||||
}
|
||||
else {
|
||||
freed++;
|
||||
}
|
||||
}
|
||||
total += MRB_HEAP_PAGE_SIZE;
|
||||
page = page->next;
|
||||
}
|
||||
|
||||
mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_cstr(mrb, "TOTAL")), mrb_fixnum_value(total));
|
||||
mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_cstr(mrb, "FREE")), mrb_fixnum_value(freed));
|
||||
|
||||
for (i = 0; i < MRB_TT_MAXDEFINE; i++) {
|
||||
mrb_value type;
|
||||
switch (i) {
|
||||
#define COUNT_TYPE(t) case (t): type = mrb_symbol_value(mrb_intern_cstr(mrb, #t)); break;
|
||||
COUNT_TYPE(MRB_TT_FALSE);
|
||||
COUNT_TYPE(MRB_TT_FREE);
|
||||
COUNT_TYPE(MRB_TT_TRUE);
|
||||
COUNT_TYPE(MRB_TT_FIXNUM);
|
||||
COUNT_TYPE(MRB_TT_SYMBOL);
|
||||
COUNT_TYPE(MRB_TT_UNDEF);
|
||||
COUNT_TYPE(MRB_TT_FLOAT);
|
||||
COUNT_TYPE(MRB_TT_VOIDP);
|
||||
COUNT_TYPE(MRB_TT_OBJECT);
|
||||
COUNT_TYPE(MRB_TT_CLASS);
|
||||
COUNT_TYPE(MRB_TT_MODULE);
|
||||
COUNT_TYPE(MRB_TT_ICLASS);
|
||||
COUNT_TYPE(MRB_TT_SCLASS);
|
||||
COUNT_TYPE(MRB_TT_PROC);
|
||||
COUNT_TYPE(MRB_TT_ARRAY);
|
||||
COUNT_TYPE(MRB_TT_HASH);
|
||||
COUNT_TYPE(MRB_TT_STRING);
|
||||
COUNT_TYPE(MRB_TT_RANGE);
|
||||
COUNT_TYPE(MRB_TT_EXCEPTION);
|
||||
COUNT_TYPE(MRB_TT_FILE);
|
||||
COUNT_TYPE(MRB_TT_ENV);
|
||||
COUNT_TYPE(MRB_TT_DATA);
|
||||
#undef COUNT_TYPE
|
||||
default: type = mrb_fixnum_value(i); break;
|
||||
}
|
||||
if (counts[i])
|
||||
mrb_hash_set(mrb, hash, type, mrb_fixnum_value(counts[i]));
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
#ifdef GC_TEST
|
||||
#ifdef GC_DEBUG
|
||||
static mrb_value gc_test(mrb_state *, mrb_value);
|
||||
@@ -1151,6 +1248,8 @@ void
|
||||
mrb_init_gc(mrb_state *mrb)
|
||||
{
|
||||
struct RClass *gc;
|
||||
struct RClass *os;
|
||||
|
||||
gc = mrb_define_module(mrb, "GC");
|
||||
|
||||
mrb_define_class_method(mrb, gc, "start", gc_start, MRB_ARGS_NONE());
|
||||
@@ -1167,6 +1266,9 @@ mrb_init_gc(mrb_state *mrb)
|
||||
mrb_define_class_method(mrb, gc, "test", gc_test, MRB_ARGS_NONE());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
os = mrb_define_module(mrb, "ObjectSpace");
|
||||
mrb_define_class_method(mrb, os, "count_objects", os_count_objects, MRB_ARGS_ANY());
|
||||
}
|
||||
|
||||
#ifdef GC_TEST
|
||||
|
||||
+2
-2
@@ -651,7 +651,7 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
|
||||
*
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_value
|
||||
mrb_hash_clear(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
khash_t(ht) *h = RHASH_TBL(hash);
|
||||
@@ -768,7 +768,7 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self)
|
||||
* {}.empty? #=> true
|
||||
*
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_value
|
||||
mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
khash_t(ht) *h = RHASH_TBL(self);
|
||||
|
||||
@@ -86,6 +86,19 @@ def assert_true(ret, msg = nil, diff = nil)
|
||||
ret
|
||||
end
|
||||
|
||||
def assert_false(ret, msg = nil, diff = nil)
|
||||
if $mrbtest_assert
|
||||
$mrbtest_assert_idx += 1
|
||||
if ret
|
||||
msg = "Expected #{ret.inspect} to be false" unless msg
|
||||
diff = assertion_diff(false, ret) unless diff
|
||||
|
||||
$mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
|
||||
end
|
||||
end
|
||||
!ret
|
||||
end
|
||||
|
||||
def assert_equal(exp, act, msg = nil)
|
||||
msg = "Expected to be equal" unless msg
|
||||
diff = assertion_diff(exp, act)
|
||||
@@ -135,6 +148,14 @@ def assert_raise(*exp)
|
||||
ret
|
||||
end
|
||||
|
||||
##
|
||||
# Fails unless +obj+ is a kind of +cls+.
|
||||
def assert_kind_of(cls, obj, msg = nil)
|
||||
msg = "Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}" unless msg
|
||||
diff = assertion_diff(cls, obj.class)
|
||||
assert_true(obj.kind_of?(cls), msg, diff)
|
||||
end
|
||||
|
||||
##
|
||||
# Report the test result and print all assertions
|
||||
# which were reported broken.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
assert('ObjectSpace.count_objects') do
|
||||
h = {}
|
||||
ObjectSpace.count_objects(h)
|
||||
assert_kind_of(Hash, h)
|
||||
assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
|
||||
assert_true(h.values.all? {|x| x.is_a?(Integer) })
|
||||
|
||||
h = ObjectSpace.count_objects
|
||||
assert_kind_of(Hash, h)
|
||||
assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
|
||||
assert_true(h.values.all? {|x| x.is_a?(Integer) })
|
||||
|
||||
assert_raise(TypeError) { ObjectSpace.count_objects(1) }
|
||||
|
||||
h0 = {:MRB_TT_FOO=>1000}
|
||||
h = ObjectSpace.count_objects(h0)
|
||||
assert_false(h0.has_key?(:MRB_TT_FOO))
|
||||
end
|
||||
Reference in New Issue
Block a user