ruby-changes:39573
From: ko1 <ko1@a...>
Date: Fri, 21 Aug 2015 20:30:31 +0900 (JST)
Subject: [ruby-changes:39573] ko1:r51654 (trunk): * ext/objspace/objspace.c: add a new method ObjectSpace.count_symbols.
ko1 2015-08-21 20:30:24 +0900 (Fri, 21 Aug 2015) New Revision: 51654 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51654 Log: * 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. Modified files: trunk/ChangeLog trunk/NEWS trunk/ext/objspace/objspace.c trunk/symbol.c trunk/symbol.h trunk/test/objspace/test_objspace.rb Index: symbol.c =================================================================== --- symbol.c (revision 51653) +++ symbol.c (revision 51654) @@ -864,6 +864,12 @@ rb_sym_all_symbols(void) https://github.com/ruby/ruby/blob/trunk/symbol.c#L864 return ary; } +size_t +rb_sym_immortal_count(void) +{ + return (size_t)global_symbols.last_id; +} + int rb_is_const_id(ID id) { Index: symbol.h =================================================================== --- symbol.h (revision 51653) +++ symbol.h (revision 51654) @@ -100,4 +100,9 @@ is_global_name_punct(const int c) https://github.com/ruby/ruby/blob/trunk/symbol.h#L100 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 Index: ChangeLog =================================================================== --- ChangeLog (revision 51653) +++ ChangeLog (revision 51654) @@ -1,3 +1,16 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Aug 21 19:58:48 2015 Koichi Sasada <ko1@a...> + + * 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@r...> * win32/Makefile.sub ($(LIBRUBY_SO)): needs additional libraries Index: ext/objspace/objspace.c =================================================================== --- ext/objspace/objspace.c (revision 51653) +++ ext/objspace/objspace.c (revision 51654) @@ -18,6 +18,7 @@ https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace.c#L18 #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 https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace.c#L250 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) https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace.c#L966 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); Index: NEWS =================================================================== --- NEWS (revision 51653) +++ NEWS (revision 51654) @@ -106,6 +106,7 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L106 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. Index: test/objspace/test_objspace.rb =================================================================== --- test/objspace/test_objspace.rb (revision 51653) +++ test/objspace/test_objspace.rb (revision 51654) @@ -351,4 +351,15 @@ class TestObjSpace < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/test/objspace/test_objspace.rb#L351 } 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/