diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-08-21 11:30:24 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-08-21 11:30:24 +0000 |
commit | 885d781abcfce71458b705d227cb719b8d045214 (patch) | |
tree | 83582e2545ff4ad7e3c37770bf0dae3bbce94e61 | |
parent | 18d8ba2594fda072bb8308f096bbe30c52b92d3c (diff) |
* ext/objspace/objspace.c: add a new method ObjectSpace.count_symbols.
[Feature #11158]
* symbol.c (rb_sym_immortal_count): added to count immortal symbols.
* symbol.h: ditto.
* test/objspace/test_objspace.rb: add a test for this method.
* NEWS: describe about this method.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51654 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | ext/objspace/objspace.c | 80 | ||||
-rw-r--r-- | symbol.c | 6 | ||||
-rw-r--r-- | symbol.h | 5 | ||||
-rw-r--r-- | test/objspace/test_objspace.rb | 11 |
6 files changed, 116 insertions, 0 deletions
@@ -1,3 +1,16 @@ +Fri Aug 21 19:58:48 2015 Koichi Sasada <ko1@atdot.net> + + * ext/objspace/objspace.c: add a new method ObjectSpace.count_symbols. + [Feature #11158] + + * symbol.c (rb_sym_immortal_count): added to count immortal symbols. + + * symbol.h: ditto. + + * test/objspace/test_objspace.rb: add a test for this method. + + * NEWS: describe about this method. + Fri Aug 21 19:48:17 2015 Nobuyoshi Nakada <nobu@ruby-lang.org> * win32/Makefile.sub ($(LIBRUBY_SO)): needs additional libraries @@ -106,6 +106,7 @@ with all sufficient information, see the ChangeLog file. GC overhead * ObjectSpace (objspace) + * ObjectSpace.count_symbols is added. * ObjectSpace.count_imemo_objects is added. * ObjectSpace.internal_class_of is added. * ObjectSpace.internal_super_of is added. diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c index 08d41b8365..eff9d0c7f8 100644 --- a/ext/objspace/objspace.c +++ b/ext/objspace/objspace.c @@ -18,6 +18,7 @@ #include <ruby/re.h> #include "node.h" #include "gc.h" +#include "symbol.h" /* * call-seq: @@ -249,6 +250,84 @@ count_objects_size(int argc, VALUE *argv, VALUE os) return hash; } +struct dynamic_symbol_counts { + size_t mortal; + size_t immortal; +}; + +static int +cs_i(void *vstart, void *vend, size_t stride, void *n) +{ + struct dynamic_symbol_counts *counts = (struct dynamic_symbol_counts *)n; + VALUE v = (VALUE)vstart; + + for (; v != (VALUE)vend; v += stride) { + if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_SYMBOL) { + ID id = RSYMBOL(v)->id; + if ((id & ~ID_SCOPE_MASK) == 0) { + counts->mortal++; + } + else { + counts->immortal++; + } + } + } + + return 0; +} + +size_t rb_sym_immortal_count(void); + +/* + * call-seq: + * ObjectSpace.count_symbols([result_hash]) -> hash + * + * Counts symbols for each Symbol type. + * + * This method is only for MRI developers interested in performance and memory + * usage of Ruby programs. + * + * If the optional argument, result_hash, is given, it is overwritten and + * returned. This is intended to avoid probe effect. + * + * Note: + * The contents of the returned hash is implementation defined. + * It may be changed in future. + * + * This method is only expected to work with C Ruby. + * + * On this version of MRI, they have 3 types of Symbols (and 1 total counts). + * + * * mortal_dynamic_symbol: GC target symbols (collected by GC) + * * immortal_dynamic_symbol: Immortal symbols promoted from dynamic symbols (do not collected by GC) + * * immortal_static_symbol: Immortal symbols (do not collected by GC) + * * immortal_symbol: total immortal symbols (immortal_dynamic_symbol+immortal_static_symbol) + */ + +static VALUE +count_symbols(int argc, VALUE *argv, VALUE os) +{ + struct dynamic_symbol_counts dynamic_counts = {0, 0}; + VALUE hash = setup_hash(argc, argv); + + size_t immortal_symbols = rb_sym_immortal_count(); + rb_objspace_each_objects(cs_i, &dynamic_counts); + + if (hash == Qnil) { + hash = rb_hash_new(); + } + else if (!RHASH_EMPTY_P(hash)) { + st_foreach(RHASH_TBL(hash), set_zero_i, hash); + } + + rb_hash_aset(hash, ID2SYM(rb_intern("mortal_dynamic_symbol")), SIZET2NUM(dynamic_counts.mortal)); + rb_hash_aset(hash, ID2SYM(rb_intern("immortal_dynamic_symbol")), SIZET2NUM(dynamic_counts.immortal)); + rb_hash_aset(hash, ID2SYM(rb_intern("immortal_static_symbol")), SIZET2NUM(immortal_symbols - dynamic_counts.immortal)); + rb_hash_aset(hash, ID2SYM(rb_intern("immortal_symbol")), SIZET2NUM(immortal_symbols)); + + return hash; +} + static int cn_i(void *vstart, void *vend, size_t stride, void *n) { @@ -887,6 +966,7 @@ Init_objspace(void) rb_define_module_function(rb_mObjSpace, "memsize_of_all", memsize_of_all_m, -1); rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1); + rb_define_module_function(rb_mObjSpace, "count_symbols", count_symbols, -1); rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1); rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1); rb_define_module_function(rb_mObjSpace, "count_imemo_objects", count_imemo_objects, -1); @@ -864,6 +864,12 @@ rb_sym_all_symbols(void) return ary; } +size_t +rb_sym_immortal_count(void) +{ + return (size_t)global_symbols.last_id; +} + int rb_is_const_id(ID id) { @@ -100,4 +100,9 @@ is_global_name_punct(const int c) ID rb_intern_cstr_without_pindown(const char *, long, rb_encoding *); +RUBY_SYMBOL_EXPORT_BEGIN + +size_t rb_sym_immortal_count(void); + +RUBY_SYMBOL_EXPORT_END #endif diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb index 3036b879bb..2acc35469f 100644 --- a/test/objspace/test_objspace.rb +++ b/test/objspace/test_objspace.rb @@ -351,4 +351,15 @@ class TestObjSpace < Test::Unit::TestCase } assert_operator i, :>, 0 end + + def test_count_symbols + syms = (1..128).map{|i| ("xyzzy#{i}" * 128).to_sym} + c = Class.new{define_method(syms[-1]){}} + + h = ObjectSpace.count_symbols + assert_operator h[:mortal_dynamic_symbol], :>=, 128, h.inspect + assert_operator h[:immortal_dynamic_symbol], :>=, 1, h.inspect + assert_operator h[:immortal_static_symbol], :>=, Object.methods.size, h.inspect + assert_equal h[:immortal_symbol], h[:immortal_dynamic_symbol] + h[:immortal_static_symbol], h.inspect + end end |