summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-08-21 11:30:24 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-08-21 11:30:24 +0000
commit885d781abcfce71458b705d227cb719b8d045214 (patch)
tree83582e2545ff4ad7e3c37770bf0dae3bbce94e61
parent18d8ba2594fda072bb8308f096bbe30c52b92d3c (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--ChangeLog13
-rw-r--r--NEWS1
-rw-r--r--ext/objspace/objspace.c80
-rw-r--r--symbol.c6
-rw-r--r--symbol.h5
-rw-r--r--test/objspace/test_objspace.rb11
6 files changed, 116 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 6f6b87cf29..41292ba604 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index 7bdf9b8bd8..1803ed99a8 100644
--- a/NEWS
+++ b/NEWS
@@ -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);
diff --git a/symbol.c b/symbol.c
index 0167fd8dcb..cd67c53663 100644
--- a/symbol.c
+++ b/symbol.c
@@ -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)
{
diff --git a/symbol.h b/symbol.h
index 001d6de1f8..7d95491ee6 100644
--- a/symbol.h
+++ b/symbol.h
@@ -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