[前][次][番号順一覧][スレッド一覧]

ruby-changes:12052

From: ko1 <ko1@a...>
Date: Wed, 17 Jun 2009 08:57:07 +0900 (JST)
Subject: [ruby-changes:12052] Ruby:r23719 (trunk): * ext/objspace: added. objspace library extends some methods to

ko1	2009-06-17 08:56:48 +0900 (Wed, 17 Jun 2009)

  New Revision: 23719

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=23719

  Log:
    * ext/objspace: added.  objspace library extends some methods to
      ObjectSpace module.

  Added directories:
    trunk/ext/objspace/
  Added files:
    trunk/ext/objspace/extconf.rb
    trunk/ext/objspace/objspace.c
  Modified files:
    trunk/ChangeLog

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 23718)
+++ ChangeLog	(revision 23719)
@@ -1,3 +1,8 @@
+Wed Jun 17 08:10:38 2009  Koichi Sasada  <ko1@a...>
+
+	* ext/objspace: added.  objspace library extends some methods to
+	  ObjectSpace module.
+
 Wed Jun 17 08:14:01 2009  Tadayoshi Funaba  <tadf@d...>
 
 	* complex.c (nucomp_coerce): accepts Complex instances.
Index: ext/objspace/objspace.c
===================================================================
--- ext/objspace/objspace.c	(revision 0)
+++ ext/objspace/objspace.c	(revision 23719)
@@ -0,0 +1,556 @@
+/**********************************************************************
+
+  objspace.c - ObjectSpace extender for MRI.
+
+  $Author$
+  created at: Wed Jun 17 07:39:17 2009
+
+  NOTE: This extension library is not expected to exist except C Ruby.
+
+  All the files in this distribution are covered under the Ruby's
+  license (see the file COPYING).
+
+**********************************************************************/
+
+/* objspace library extends ObjectSpace module and add several
+ * methods to get internal statistic information about
+ * object/memory management.
+ * 
+ * Generally, you *SHOULD NOT*use this library if you do not know
+ * about the MRI implementation.  Mainly, this library is for (memory)
+ * profiler developers and MRI developers who need to know how MRI
+ * memory usage.
+ *
+ */
+
+#include <ruby/ruby.h>
+#include <ruby/st.h>
+#include <ruby/io.h>
+#include <ruby/re.h>
+#include <../../node.h>
+
+size_t rb_str_memsize(VALUE);
+size_t rb_ary_memsize(VALUE);
+size_t st_memsize(st_table *);
+size_t rb_io_memsize(rb_io_t *);
+size_t onig_memsize(regex_t *);
+size_t rb_geneic_ivar_memsize(VALUE);
+size_t rb_objspace_data_type_memsize(VALUE obj);
+
+void rb_objspace_each_objects(
+    int (*callback)(void *start, void *end, size_t stride, void *data),
+    void *data);
+
+static size_t
+memsize_of(VALUE obj)
+{
+    size_t size = 0;
+
+    if (SPECIAL_CONST_P(obj)) {
+	return 0;
+    }
+
+    if (FL_TEST(obj, FL_EXIVAR)) {
+	size += rb_geneic_ivar_memsize(obj);
+    }
+
+    switch (BUILTIN_TYPE(obj)) {
+      case T_OBJECT:
+	if (!(RBASIC(obj)->flags & ROBJECT_EMBED) &&
+	    ROBJECT(obj)->as.heap.ivptr) {
+	    size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE);
+	}
+	break;
+      case T_MODULE:
+      case T_CLASS:
+	size += st_memsize(RCLASS_M_TBL(obj));
+	if (RCLASS_IV_TBL(obj)) {
+	    size += st_memsize(RCLASS_IV_TBL(obj));
+	}
+	if (RCLASS_IV_INDEX_TBL(obj)) {
+	    size += st_memsize(RCLASS_IV_INDEX_TBL(obj));
+	}
+	if (RCLASS(obj)->ptr->iv_tbl) {
+	    size += st_memsize(RCLASS(obj)->ptr->iv_tbl);
+	}
+	size += sizeof(rb_classext_t);
+	break;
+      case T_STRING:
+	size += rb_str_memsize(obj);
+	break;
+      case T_ARRAY:
+	size += rb_ary_memsize(obj);
+	break;
+      case T_HASH:
+	if (RHASH(obj)->ntbl) {
+	    size += st_memsize(RHASH(obj)->ntbl);
+	}
+	break;
+      case T_REGEXP:
+	if (RREGEXP(obj)->ptr) {
+	    size += onig_memsize(RREGEXP(obj)->ptr);
+	}
+	break;
+      case T_DATA:
+	size += rb_objspace_data_type_memsize(obj);
+	break;
+      case T_MATCH:
+	if (RMATCH(obj)->rmatch) {
+            struct rmatch *rm = RMATCH(obj)->rmatch;
+	    size += sizeof(struct re_registers); /* TODO: onig_region_memsize(&rm->regs); */
+	    size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
+	    size += sizeof(struct rmatch);
+	}
+	break;
+      case T_FILE:
+	if (RFILE(obj)->fptr) {
+	    size += rb_io_memsize(RFILE(obj)->fptr);
+	}
+	break;
+      case T_RATIONAL:
+      case T_COMPLEX:
+	break;
+      case T_ICLASS:
+	/* iClass shares table with the module */
+	break;
+
+      case T_FLOAT:
+	break;
+
+      case T_BIGNUM:
+	if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
+	    size += RBIGNUM_LEN(obj) * sizeof(BDIGIT);
+	}
+	break;
+      case T_NODE:
+	switch (nd_type(obj)) {
+	  case NODE_SCOPE:
+	    if (RNODE(obj)->u1.tbl) {
+		/* TODO: xfree(RANY(obj)->as.node.u1.tbl); */
+	    }
+	    break;
+	  case NODE_ALLOCA:
+	    /* TODO: xfree(RANY(obj)->as.node.u1.node); */
+	    ;
+	}
+	break;			/* no need to free iv_tbl */
+
+      case T_STRUCT:
+	if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
+	    RSTRUCT(obj)->as.heap.ptr) {
+	    size += sizeof(VALUE) * RSTRUCT_LEN(obj);
+	}
+	break;
+
+      default:
+	rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
+	       BUILTIN_TYPE(obj), (void*)obj);
+    }
+
+    return size;
+}
+
+/*
+ *  call-seq:
+ *    ObjectSpace.memsize_of(obj) -> Integer
+ *
+ *  Return consuming memory size of obj.
+ *
+ *  Note that this information is incomplete.  You need to deal with
+ *  this information as only a *HINT*.  Especaially, the size of
+ *  T_DATA may not right size.
+ *
+ *  This method is not expected to work except C Ruby.
+ */
+
+static VALUE
+memsize_of_m(VALUE self, VALUE obj)
+{
+    return SIZET2NUM(memsize_of(obj));
+}
+
+static int
+set_zero_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+    VALUE k = (VALUE)key;
+    VALUE hash = (VALUE)arg;
+    rb_hash_aset(hash, k, INT2FIX(0));
+    return ST_CONTINUE;
+}
+
+static int
+cos_i(void *vstart, void *vend, size_t stride, void *data)
+{
+    size_t *counts = (size_t *)data;
+    VALUE v = (VALUE)vstart;
+
+    for (;v != (VALUE)vend; v += stride) {
+	if (RBASIC(v)->flags) {
+	    counts[BUILTIN_TYPE(v)] += memsize_of(v);
+	}
+    }
+    return 0;
+}
+
+/*
+ *  call-seq:
+ *    ObjectSpace.count_objects_size([result_hash]) -> hash
+ *
+ *  Counts objects size (in bytes) for each type.
+ *
+ *  Note that this information is incomplete.  You need to deal with
+ *  this information as only a *HINT*.  Especaially, total size of
+ *  T_DATA may not right size.
+ *
+ *  It returns a hash as:
+ *    {:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...}
+ * 
+ *  If the optional argument, result_hash, is given,
+ *  it is overwritten and returned.
+ *  This is intended to avoid probe effect.
+ *
+ *  The contents of the returned hash is implementation defined.
+ *  It may be changed in future.
+ *
+ *  This method is not expected to work except C Ruby.
+ */
+
+static VALUE
+count_objects_size(int argc, VALUE *argv, VALUE os)
+{
+    size_t counts[T_MASK+1];
+    size_t total = 0;
+    size_t i;
+    VALUE hash;
+
+    if (rb_scan_args(argc, argv, "01", &hash) == 1) {
+        if (TYPE(hash) != T_HASH)
+            rb_raise(rb_eTypeError, "non-hash given");
+    }
+
+    for (i = 0; i <= T_MASK; i++) {
+	counts[i] = 0;
+    }
+
+    rb_objspace_each_objects(cos_i, &counts[0]);
+
+    if (hash == Qnil) {
+        hash = rb_hash_new();
+    }
+    else if (!RHASH_EMPTY_P(hash)) {
+        st_foreach(RHASH_TBL(hash), set_zero_i, hash);
+    }
+
+    for (i = 0; i <= T_MASK; i++) {
+	if (counts[i]) {
+	    VALUE type;
+	    switch (i) {
+#define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
+		COUNT_TYPE(T_NONE);
+		COUNT_TYPE(T_OBJECT);
+		COUNT_TYPE(T_CLASS);
+		COUNT_TYPE(T_MODULE);
+		COUNT_TYPE(T_FLOAT);
+		COUNT_TYPE(T_STRING);
+		COUNT_TYPE(T_REGEXP);
+		COUNT_TYPE(T_ARRAY);
+		COUNT_TYPE(T_HASH);
+		COUNT_TYPE(T_STRUCT);
+		COUNT_TYPE(T_BIGNUM);
+		COUNT_TYPE(T_FILE);
+		COUNT_TYPE(T_DATA);
+		COUNT_TYPE(T_MATCH);
+		COUNT_TYPE(T_COMPLEX);
+		COUNT_TYPE(T_RATIONAL);
+		COUNT_TYPE(T_NIL);
+		COUNT_TYPE(T_TRUE);
+		COUNT_TYPE(T_FALSE);
+		COUNT_TYPE(T_SYMBOL);
+		COUNT_TYPE(T_FIXNUM);
+		COUNT_TYPE(T_UNDEF);
+		COUNT_TYPE(T_NODE);
+		COUNT_TYPE(T_ICLASS);
+		COUNT_TYPE(T_ZOMBIE);
+#undef COUNT_TYPE
+	      default: type = INT2NUM(i); break;
+	    }
+	    total += counts[i];
+	    rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
+	}
+    }
+    rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
+    return hash;
+}
+
+static int
+cn_i(void *vstart, void *vend, size_t stride, void *n)
+{
+    size_t *nodes = (size_t *)n;
+    VALUE v = (VALUE)vstart;
+
+    for (; v != (VALUE)vend; v += stride) {
+	if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) {
+	    size_t s = nd_type((NODE *)v);
+	    nodes[s]++;
+	}
+    }
+
+    return 0;
+}
+
+/*
+ *  call-seq:
+ *     ObjectSpace.count_nodes([result_hash]) -> hash
+ *
+ *  Counts nodes for each node type.
+ *
+ *  This method is not for ordinary Ruby programmers, but for MRI developers
+ *  who have interest in MRI performance and memory usage.
+ *
+ *  It returns a hash as:
+ *  {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
+ *
+ *  If the optional argument, result_hash, is given,
+ *  it is overwritten and returned.
+ *  This is intended to avoid probe effect.
+ *
+ *  The contents of the returned hash is implementation defined.
+ *  It may be changed in future.
+ *
+ *  This method is not expected to work except C Ruby.
+ */
+
+static VALUE
+count_nodes(int argc, VALUE *argv, VALUE os)
+{
+    size_t nodes[NODE_LAST+1];
+    size_t i;
+    VALUE hash;
+
+    if (rb_scan_args(argc, argv, "01", &hash) == 1) {
+        if (TYPE(hash) != T_HASH)
+            rb_raise(rb_eTypeError, "non-hash given");
+    }
+
+    for (i = 0; i <= NODE_LAST; i++) {
+	nodes[i] = 0;
+    }
+
+    rb_objspace_each_objects(cn_i, &nodes[0]);
+
+    if (hash == Qnil) {
+        hash = rb_hash_new();
+    }
+    else if (!RHASH_EMPTY_P(hash)) {
+        st_foreach(RHASH_TBL(hash), set_zero_i, hash);
+    }
+
+    for (i=0; i<NODE_LAST; i++) {
+	if (nodes[i] != 0) {
+	    VALUE node;
+	    switch (i) {
+#define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break;
+		COUNT_NODE(NODE_METHOD);
+		COUNT_NODE(NODE_FBODY);
+		COUNT_NODE(NODE_CFUNC);
+		COUNT_NODE(NODE_SCOPE);
+		COUNT_NODE(NODE_BLOCK);
+		COUNT_NODE(NODE_IF);
+		COUNT_NODE(NODE_CASE);
+		COUNT_NODE(NODE_WHEN);
+		COUNT_NODE(NODE_OPT_N);
+		COUNT_NODE(NODE_WHILE);
+		COUNT_NODE(NODE_UNTIL);
+		COUNT_NODE(NODE_ITER);
+		COUNT_NODE(NODE_FOR);
+		COUNT_NODE(NODE_BREAK);
+		COUNT_NODE(NODE_NEXT);
+		COUNT_NODE(NODE_REDO);
+		COUNT_NODE(NODE_RETRY);
+		COUNT_NODE(NODE_BEGIN);
+		COUNT_NODE(NODE_RESCUE);
+		COUNT_NODE(NODE_RESBODY);
+		COUNT_NODE(NODE_ENSURE);
+		COUNT_NODE(NODE_AND);
+		COUNT_NODE(NODE_OR);
+		COUNT_NODE(NODE_MASGN);
+		COUNT_NODE(NODE_LASGN);
+		COUNT_NODE(NODE_DASGN);
+		COUNT_NODE(NODE_DASGN_CURR);
+		COUNT_NODE(NODE_GASGN);
+		COUNT_NODE(NODE_IASGN);
+		COUNT_NODE(NODE_IASGN2);
+		COUNT_NODE(NODE_CDECL);
+		COUNT_NODE(NODE_CVASGN);
+		COUNT_NODE(NODE_CVDECL);
+		COUNT_NODE(NODE_OP_ASGN1);
+		COUNT_NODE(NODE_OP_ASGN2);
+		COUNT_NODE(NODE_OP_ASGN_AND);
+		COUNT_NODE(NODE_OP_ASGN_OR);
+		COUNT_NODE(NODE_CALL);
+		COUNT_NODE(NODE_FCALL);
+		COUNT_NODE(NODE_VCALL);
+		COUNT_NODE(NODE_SUPER);
+		COUNT_NODE(NODE_ZSUPER);
+		COUNT_NODE(NODE_ARRAY);
+		COUNT_NODE(NODE_ZARRAY);
+		COUNT_NODE(NODE_VALUES);
+		COUNT_NODE(NODE_HASH);
+		COUNT_NODE(NODE_RETURN);
+		COUNT_NODE(NODE_YIELD);
+		COUNT_NODE(NODE_LVAR);
+		COUNT_NODE(NODE_DVAR);
+		COUNT_NODE(NODE_GVAR);
+		COUNT_NODE(NODE_IVAR);
+		COUNT_NODE(NODE_CONST);
+		COUNT_NODE(NODE_CVAR);
+		COUNT_NODE(NODE_NTH_REF);
+		COUNT_NODE(NODE_BACK_REF);
+		COUNT_NODE(NODE_MATCH);
+		COUNT_NODE(NODE_MATCH2);
+		COUNT_NODE(NODE_MATCH3);
+		COUNT_NODE(NODE_LIT);
+		COUNT_NODE(NODE_STR);
+		COUNT_NODE(NODE_DSTR);
+		COUNT_NODE(NODE_XSTR);
+		COUNT_NODE(NODE_DXSTR);
+		COUNT_NODE(NODE_EVSTR);
+		COUNT_NODE(NODE_DREGX);
+		COUNT_NODE(NODE_DREGX_ONCE);
+		COUNT_NODE(NODE_ARGS);
+		COUNT_NODE(NODE_ARGS_AUX);
+		COUNT_NODE(NODE_OPT_ARG);
+		COUNT_NODE(NODE_POSTARG);
+		COUNT_NODE(NODE_ARGSCAT);
+		COUNT_NODE(NODE_ARGSPUSH);
+		COUNT_NODE(NODE_SPLAT);
+		COUNT_NODE(NODE_TO_ARY);
+		COUNT_NODE(NODE_BLOCK_ARG);
+		COUNT_NODE(NODE_BLOCK_PASS);
+		COUNT_NODE(NODE_DEFN);
+		COUNT_NODE(NODE_DEFS);
+		COUNT_NODE(NODE_ALIAS);
+		COUNT_NODE(NODE_VALIAS);
+		COUNT_NODE(NODE_UNDEF);
+		COUNT_NODE(NODE_CLASS);
+		COUNT_NODE(NODE_MODULE);
+		COUNT_NODE(NODE_SCLASS);
+		COUNT_NODE(NODE_COLON2);
+		COUNT_NODE(NODE_COLON3);
+		COUNT_NODE(NODE_DOT2);
+		COUNT_NODE(NODE_DOT3);
+		COUNT_NODE(NODE_FLIP2);
+		COUNT_NODE(NODE_FLIP3);
+		COUNT_NODE(NODE_ATTRSET);
+		COUNT_NODE(NODE_SELF);
+		COUNT_NODE(NODE_NIL);
+		COUNT_NODE(NODE_TRUE);
+		COUNT_NODE(NODE_FALSE);
+		COUNT_NODE(NODE_ERRINFO);
+		COUNT_NODE(NODE_DEFINED);
+		COUNT_NODE(NODE_POSTEXE);
+		COUNT_NODE(NODE_ALLOCA);
+		COUNT_NODE(NODE_BMETHOD);
+		COUNT_NODE(NODE_MEMO);
+		COUNT_NODE(NODE_IFUNC);
+		COUNT_NODE(NODE_DSYM);
+		COUNT_NODE(NODE_ATTRASGN);
+		COUNT_NODE(NODE_PRELUDE);
+		COUNT_NODE(NODE_LAMBDA);
+		COUNT_NODE(NODE_OPTBLOCK);
+#undef COUNT_NODE
+	      default: node = INT2FIX(nodes[i]);
+	    }
+	    rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
+	}
+    }
+    return hash;
+}
+
+static int
+cto_i(void *vstart, void *vend, size_t stride, void *data)
+{
+    VALUE hash = (VALUE)data;
+    VALUE v = (VALUE)vstart;
+
+    for (; v != (VALUE)vend; v += stride) {
+	if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_DATA) {
+	    VALUE counter = rb_hash_aref(hash, RBASIC(v)->klass);
+	    if (NIL_P(counter)) {
+		counter = INT2FIX(1);
+	    }
+	    else {
+		counter = INT2FIX(FIX2INT(counter) + 1);
+	    }
+	    rb_hash_aset(hash, RBASIC(v)->klass, counter);
+	}
+    }
+
+    return 0;
+}
+
+/*
+ *  call-seq:
+ *     ObjectSpace.count_tdata_objects([result_hash]) -> hash
+ *
+ *  Counts nodes for each node type.
+ *
+ *  This method is not for ordinary Ruby programmers, but for MRI developers
+ *  who interest on MRI performance.
+ *
+ *  It returns a hash as:
+ *  {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
+ *
+ *  If the optional argument, result_hash, is given,
+ *  it is overwritten and returned.
+ *  This is intended to avoid probe effect.
+ *
+ *  The contents of the returned hash is implementation defined.
+ *  It may be changed in future.
+ *
+ *  This method is not expected to work except C Ruby.
+ *
+ */
+
+static VALUE
+count_tdata_objects(int argc, VALUE *argv, VALUE self)
+{
+    VALUE hash;
+
+    if (rb_scan_args(argc, argv, "01", &hash) == 1) {
+        if (TYPE(hash) != T_HASH)
+            rb_raise(rb_eTypeError, "non-hash given");
+    }
+
+    if (hash == Qnil) {
+        hash = rb_hash_new();
+    }
+    else if (!RHASH_EMPTY_P(hash)) {
+        st_foreach(RHASH_TBL(hash), set_zero_i, hash);
+    }
+
+    rb_objspace_each_objects(cto_i, (void *)hash);
+
+    return hash;
+}
+
+/* objspace library extends ObjectSpace module and add several
+ * methods to get internal statistic information about
+ * object/memory management.
+ * 
+ * Generally, you *SHOULD NOT*use this library if you do not know
+ * about the MRI implementation.  Mainly, this library is for (memory)
+ * profiler developers and MRI developers who need to know how MRI
+ * memory usage.
+ */
+
+void
+Init_objspace(void)
+{
+    VALUE rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
+
+    rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
+    rb_define_module_function(rb_mObjSpace, "memsize_of", memsize_of_m, 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);
+}

Property changes on: ext/objspace/objspace.c
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: ext/objspace/extconf.rb
===================================================================
--- ext/objspace/extconf.rb	(revision 0)
+++ ext/objspace/extconf.rb	(revision 23719)
@@ -0,0 +1,2 @@
+
+create_makefile('objspace')

Property changes on: ext/objspace/extconf.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF


Property changes on: ext/objspace
___________________________________________________________________
Name: svn:ignore
   + extconf.h Makefile



--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]