From 338c8538c92a1f3c4117fb920855a610cfaefc25 Mon Sep 17 00:00:00 2001 From: Rory OConnell <19547+RoryO@users.noreply.github.com> Date: Thu, 9 Jul 2020 18:52:31 -0700 Subject: Initial ObjectSpace.memsize_of implementation --- mrbgems/mruby-objectspace/test/objectspace.rb | 76 +++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'mrbgems/mruby-objectspace/test/objectspace.rb') diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb index 9c44c2157..d26fd5a9e 100644 --- a/mrbgems/mruby-objectspace/test/objectspace.rb +++ b/mrbgems/mruby-objectspace/test/objectspace.rb @@ -1,3 +1,4 @@ +# coding: utf-8 assert('ObjectSpace.count_objects') do h = {} f = Fiber.new {} if Object.const_defined?(:Fiber) @@ -58,3 +59,78 @@ end assert 'Check class pointer of ObjectSpace.each_object.' do assert_nothing_raised { ObjectSpace.each_object { |obj| !obj } } end + +assert 'ObjectSpace.memsize_of' do + # immediate literals + int_size = ObjectSpace.memsize_of 1 + assert_equal int_size, 0, 'int zero' + + sym_size = ObjectSpace.memsize_of :foo + assert_equal sym_size, 0, 'sym zero' + + assert_equal ObjectSpace.memsize_of(true), int_size + assert_equal ObjectSpace.memsize_of(false), int_size + + float_size = if Object.const_defined? :Float + ObjectSpace.memsize_of 1.0 + else + nil + end + + # need some way of asking if floats are boxed + assert_equal float_size, 0 if float_size + + assert_not_equal ObjectSpace.memsize_of('a'), 0, 'memsize of str' + + if __ENCODING__ == "UTF-8" + assert_not_equal ObjectSpace.memsize_of("こんにちは世界"), 0, 'memsize of utf8 str' + end + + assert_not_equal ObjectSpace.memsize_of(0..1), 0, 'range not zero' + + # class defs + class_obj_size = ObjectSpace.memsize_of Class + assert_not_equal class_obj_size, 0, 'Class obj not zero' + + empty_class_def_size = ObjectSpace.memsize_of Class.new + + # need access to struct iv_tbl + # assert_not_equal empty_class_def_size, 0, 'Class def not zero' + + class_without_methods = Class.new do + @a = 1 + @b = 2 + end + class_total_size = empty_class_def_size + (int_size * 2) + assert_equal ObjectSpace.memsize_of(class_without_methods), class_total_size, 'class without methods size' + + module_without_methods = Module.new do + @a = 1 + @b = 2 + end + module_total_size = empty_class_def_size + (int_size * 2) + assert_equal ObjectSpace.memsize_of(module_without_methods), module_total_size, 'module without methods size' + + proc_size = ObjectSpace.memsize_of Proc.new { x = 1; x } + assert_not_equal proc_size, 0 + + class_with_methods = Class.new do + def foo + a = 0 + a + 1 + end + end + + m_size = ObjectSpace.memsize_of class_with_methods.instance_method(:foo) + assert_not_equal m_size, 0, 'method size not zero' + + # collections + assert_equal ObjectSpace.memsize_of([]), 0, 'empty array size zero' + assert_not_equal ObjectSpace.memsize_of(Array.new(16)), 0, 'array size non zero' + + # fiber + assert_not_equal ObjectSpace.memsize_of(Fiber.new {}), 0, 'fiber non zero' + + skip 'No hash table support yet' + assert_equal ObjectSpace.memsize_of({}), 0, 'empty hash size zero' +end -- cgit v1.2.3 From 5759256ff8b7edbaeefa50b37404453afdd86a0b Mon Sep 17 00:00:00 2001 From: Rory OConnell <19547+RoryO@users.noreply.github.com> Date: Mon, 13 Jul 2020 16:00:49 -0700 Subject: Update tests for new calculations --- mrbgems/mruby-objectspace/test/objectspace.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'mrbgems/mruby-objectspace/test/objectspace.rb') diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb index d26fd5a9e..60626e6bf 100644 --- a/mrbgems/mruby-objectspace/test/objectspace.rb +++ b/mrbgems/mruby-objectspace/test/objectspace.rb @@ -93,9 +93,7 @@ assert 'ObjectSpace.memsize_of' do assert_not_equal class_obj_size, 0, 'Class obj not zero' empty_class_def_size = ObjectSpace.memsize_of Class.new - - # need access to struct iv_tbl - # assert_not_equal empty_class_def_size, 0, 'Class def not zero' + assert_not_equal empty_class_def_size, 0, 'Class def not zero' class_without_methods = Class.new do @a = 1 @@ -125,12 +123,15 @@ assert 'ObjectSpace.memsize_of' do assert_not_equal m_size, 0, 'method size not zero' # collections - assert_equal ObjectSpace.memsize_of([]), 0, 'empty array size zero' - assert_not_equal ObjectSpace.memsize_of(Array.new(16)), 0, 'array size non zero' + assert_not_equal ObjectSpace.memsize_of([]), 0, 'empty array size not zero' + assert_not_equal ObjectSpace.memsize_of(Array.new(16)), 0, 'array size not zero' # fiber - assert_not_equal ObjectSpace.memsize_of(Fiber.new {}), 0, 'fiber non zero' + assert_not_equal ObjectSpace.memsize_of(Fiber.new {}), 0, 'fiber not zero' + + #hash + assert_not_equal ObjectSpace.memsize_of({}), 0, 'empty hash size not zero' + + # recursion - skip 'No hash table support yet' - assert_equal ObjectSpace.memsize_of({}), 0, 'empty hash size zero' end -- cgit v1.2.3 From 4d32c671a70cd066010cf502ab13ab8f78357d0e Mon Sep 17 00:00:00 2001 From: Rory O'Connell <19547+RoryO@users.noreply.github.com> Date: Tue, 14 Jul 2020 23:30:35 -0700 Subject: Finishing out memsize_of recursion --- mrbgems/mruby-objectspace/src/mruby_objectspace.c | 39 +++++++----- mrbgems/mruby-objectspace/test/objectspace.rb | 73 ++++++++++++++++++++++- 2 files changed, 93 insertions(+), 19 deletions(-) (limited to 'mrbgems/mruby-objectspace/test/objectspace.rb') diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c index d5ffa83f1..7088e166f 100644 --- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c +++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -176,27 +176,28 @@ os_each_object(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(d.count); } -static void os_memsize_of_object(mrb_state*,mrb_value,mrb_bool,mrb_int*); +static void os_memsize_of_object(mrb_state*,mrb_value,mrb_value,mrb_int*); + +struct os_memsize_cb_data { + mrb_int *t; + mrb_value recurse; +}; static int os_memsize_ivar_cb(mrb_state *mrb, mrb_sym _name, mrb_value obj, void *data) { - mrb_int *cb_data = (mrb_int *)data; - mrb_int recurse = *(&cb_data[0]); - mrb_int* total = &cb_data[1]; - - os_memsize_of_object(mrb, obj, (mrb_bool)(recurse), total); + struct os_memsize_cb_data *cb_data = (struct os_memsize_cb_data *)(data); + os_memsize_of_object(mrb, obj, cb_data->recurse, cb_data->t); return 0; } static void -os_memsize_of_ivars(mrb_state* mrb, mrb_value obj, mrb_bool recurse, mrb_int *t) +os_memsize_of_ivars(mrb_state* mrb, mrb_value obj, mrb_value recurse, mrb_int *t) { (*t) += mrb_obj_iv_tbl_memsize(mrb, obj); - if(recurse) { - mrb_int r = (mrb_int)recurse; - mrb_int *cb_data[2] = { &r, t }; - mrb_iv_foreach(mrb, obj, os_memsize_ivar_cb, cb_data); + if(!mrb_nil_p(recurse)) { + struct os_memsize_cb_data cb_data = {t, recurse}; + mrb_iv_foreach(mrb, obj, os_memsize_ivar_cb, &cb_data); } } @@ -239,8 +240,14 @@ os_memsize_of_methods(mrb_state* mrb, mrb_value obj, mrb_int* t) } static void -os_memsize_of_object(mrb_state* mrb, mrb_value obj, mrb_bool recurse, mrb_int* t) +os_memsize_of_object(mrb_state* mrb, mrb_value obj, mrb_value recurse, mrb_int* t) { + if(!mrb_nil_p(recurse)) { + const mrb_value obj_id = mrb_fixnum_value(mrb_obj_id(obj)); + if(mrb_hash_key_p(mrb, recurse, obj_id)) return; + mrb_hash_set(mrb, recurse, obj_id, mrb_true_value()); + } + switch(obj.tt) { case MRB_TT_STRING: (*t) += RSTRING_LEN(obj); @@ -264,7 +271,7 @@ os_memsize_of_object(mrb_state* mrb, mrb_value obj, mrb_bool recurse, mrb_int* t case MRB_TT_HASH: { (*t) += mrb_objspace_page_slot_size() + os_memsize_of_hash_table(obj); - if(recurse) { + if(!mrb_nil_p(recurse)) { os_memsize_of_object(mrb, mrb_hash_keys(mrb, obj), recurse, t); os_memsize_of_object(mrb, mrb_hash_values(mrb, obj), recurse, t); } @@ -278,7 +285,7 @@ os_memsize_of_object(mrb_state* mrb, mrb_value obj, mrb_bool recurse, mrb_int* t (*t) += mrb_objspace_page_slot_size(); if(len > MRB_ARY_EMBED_LEN_MAX) (*t) += sizeof(mrb_value *) * len; - if(recurse) { + if(!mrb_nil_p(recurse)) { for(i = 0; i < len; i++) { os_memsize_of_object(mrb, ARY_PTR(mrb_ary_ptr(obj))[i], recurse, t); } @@ -388,13 +395,13 @@ os_memsize_of(mrb_state *mrb, mrb_value self) { mrb_int total; mrb_value obj; - mrb_bool recurse; + mrb_value recurse; const char *kw_names[1] = { "recurse" }; mrb_value kw_values[1]; const mrb_kwargs kwargs = { 1, kw_values, kw_names, 0, NULL }; mrb_get_args(mrb, "o:", &obj, &kwargs); - recurse = mrb_obj_eq(mrb, kw_values[0], mrb_true_value()) ? TRUE : FALSE; + recurse = mrb_obj_eq(mrb, kw_values[0], mrb_true_value())? mrb_hash_new(mrb) : mrb_nil_value(); total = 0; os_memsize_of_object(mrb, obj, recurse, &total); diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb index 60626e6bf..610cdfbfa 100644 --- a/mrbgems/mruby-objectspace/test/objectspace.rb +++ b/mrbgems/mruby-objectspace/test/objectspace.rb @@ -123,15 +123,82 @@ assert 'ObjectSpace.memsize_of' do assert_not_equal m_size, 0, 'method size not zero' # collections - assert_not_equal ObjectSpace.memsize_of([]), 0, 'empty array size not zero' - assert_not_equal ObjectSpace.memsize_of(Array.new(16)), 0, 'array size not zero' + empty_array_size = ObjectSpace.memsize_of [] + assert_not_equal empty_array_size, 0, 'empty array size not zero' + assert_operator empty_array_size, :<, ObjectSpace.memsize_of(Array.new(16)), 'large array size greater than embed' # fiber - assert_not_equal ObjectSpace.memsize_of(Fiber.new {}), 0, 'fiber not zero' + empty_fiber_size = ObjectSpace.memsize_of(Fiber.new {}) + assert_not_equal empty_fiber_size, 0, 'empty fiber not zero' + assert_operator empty_fiber_size, :<, ObjectSpace.memsize_of(Fiber.new { yield; 1 }), 'Fiber code size growth' #hash assert_not_equal ObjectSpace.memsize_of({}), 0, 'empty hash size not zero' # recursion + foo_str = 'foo' * 10 + bar_str = 'bar' * 10 + caz_str = 'caz' * 10 + fbc_ary = [foo_str, bar_str, caz_str] + assert_operator ObjectSpace.memsize_of(fbc_ary), + :<, + ObjectSpace.memsize_of(fbc_ary, recurse: true), + 'basic array recursion' + + big_ary = [ 'a' * 10, + [ 'b' * 10, + [ 'c' * 10, + [ 'd' * 10, + [ 'e' * 10, + [ 'f' * 10, + ['g' * 10] + ] * 10, + ] * 10, + ] * 10, + ] * 10, + ] * 10, + ] * 10 + assert_operator ObjectSpace.memsize_of(big_ary), + :<, + ObjectSpace.memsize_of(big_ary, recurse: true), + 'large array recursion' + + assert_nothing_raised 'infinite array recursion' do + ObjectSpace.memsize_of(fbc_ary.push(fbc_ary)) + end + + basic_hsh = {a: [foo_str, bar_str], b: caz_str, 'c' => {}} + assert_operator ObjectSpace.memsize_of(basic_hsh), + :<, + ObjectSpace.memsize_of(basic_hsh, recurse: true), + 'hash recursion with basic keys' + + weird_keys = {big_ary => foo_str} + assert_operator ObjectSpace.memsize_of(weird_keys), + :<, + ObjectSpace.memsize_of(weird_keys, recurse: true), + 'hash recursion with collection as key' + + basic_hsh.store('d', basic_hsh) + assert_nothing_raised 'hash value recursion' do + ObjectSpace.memsize_of basic_hsh, recurse: true + end + + foo_klass = Class.new do + def bar= b + @bar = b + end + end + fk_one = foo_klass.new + fk_one.bar = fbc_ary + assert_operator ObjectSpace.memsize_of(fk_one), + :<, + ObjectSpace.memsize_of(fk_one, recurse: true), + 'basic ivar recursion' + + fk_one.bar = fk_one + assert_nothing_raised 'ivar infinite recursion' do + ObjectSpace.memsize_of(fk_one, recurse: true) + end end -- cgit v1.2.3