Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/objspace/objspace.c

Go to the documentation of this file.

    00001 /**********************************************************************
    00002
    00003   objspace.c - ObjectSpace extender for MRI.
    00004
    00005   $Author: yugui $
    00006   created at: Wed Jun 17 07:39:17 2009
    00007
    00008   NOTE: This extension library is not expected to exist except C Ruby.
    00009
    00010   All the files in this distribution are covered under the Ruby's
    00011   license (see the file COPYING).
    00012
    00013 **********************************************************************/
    00014
    00015 /* objspace library extends ObjectSpace module and add several
    00016  * methods to get internal statistic information about
    00017  * object/memory management.
    00018  *
    00019  * Generally, you *SHOULD NOT*use this library if you do not know
    00020  * about the MRI implementation.  Mainly, this library is for (memory)
    00021  * profiler developers and MRI developers who need to know how MRI
    00022  * memory usage.
    00023  *
    00024  */
    00025
    00026 #include <ruby/ruby.h>
    00027 #include <ruby/st.h>
    00028 #include <ruby/io.h>
    00029 #include <ruby/re.h>
    00030 #include <../../node.h>
    00031
    00032 size_t rb_str_memsize(VALUE);
    00033 size_t rb_ary_memsize(VALUE);
    00034 size_t rb_io_memsize(rb_io_t *);
    00035 size_t onig_memsize(regex_t *);
    00036 size_t rb_generic_ivar_memsize(VALUE);
    00037 size_t rb_objspace_data_type_memsize(VALUE obj);
    00038
    00039 void rb_objspace_each_objects(
    00040     int (*callback)(void *start, void *end, size_t stride, void *data),
    00041     void *data);
    00042
    00043 static size_t
    00044 memsize_of(VALUE obj)
    00045 {
    00046     size_t size = 0;
    00047
    00048     if (SPECIAL_CONST_P(obj)) {
    00049         return 0;
    00050     }
    00051
    00052     if (FL_TEST(obj, FL_EXIVAR)) {
    00053         size += rb_generic_ivar_memsize(obj);
    00054     }
    00055
    00056     switch (BUILTIN_TYPE(obj)) {
    00057       case T_OBJECT:
    00058         if (!(RBASIC(obj)->flags & ROBJECT_EMBED) &&
    00059             ROBJECT(obj)->as.heap.ivptr) {
    00060             size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE);
    00061         }
    00062         break;
    00063       case T_MODULE:
    00064       case T_CLASS:
    00065         size += st_memsize(RCLASS_M_TBL(obj));
    00066         if (RCLASS_IV_TBL(obj)) {
    00067             size += st_memsize(RCLASS_IV_TBL(obj));
    00068         }
    00069         if (RCLASS_IV_INDEX_TBL(obj)) {
    00070             size += st_memsize(RCLASS_IV_INDEX_TBL(obj));
    00071         }
    00072         if (RCLASS(obj)->ptr->iv_tbl) {
    00073             size += st_memsize(RCLASS(obj)->ptr->iv_tbl);
    00074         }
    00075         size += sizeof(rb_classext_t);
    00076         break;
    00077       case T_STRING:
    00078         size += rb_str_memsize(obj);
    00079         break;
    00080       case T_ARRAY:
    00081         size += rb_ary_memsize(obj);
    00082         break;
    00083       case T_HASH:
    00084         if (RHASH(obj)->ntbl) {
    00085             size += st_memsize(RHASH(obj)->ntbl);
    00086         }
    00087         break;
    00088       case T_REGEXP:
    00089         if (RREGEXP(obj)->ptr) {
    00090             size += onig_memsize(RREGEXP(obj)->ptr);
    00091         }
    00092         break;
    00093       case T_DATA:
    00094         size += rb_objspace_data_type_memsize(obj);
    00095         break;
    00096       case T_MATCH:
    00097         if (RMATCH(obj)->rmatch) {
    00098             struct rmatch *rm = RMATCH(obj)->rmatch;
    00099             size += sizeof(struct re_registers); /* TODO: onig_region_memsize(&rm->regs); */
    00100             size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
    00101             size += sizeof(struct rmatch);
    00102         }
    00103         break;
    00104       case T_FILE:
    00105         if (RFILE(obj)->fptr) {
    00106             size += rb_io_memsize(RFILE(obj)->fptr);
    00107         }
    00108         break;
    00109       case T_RATIONAL:
    00110       case T_COMPLEX:
    00111         break;
    00112       case T_ICLASS:
    00113         /* iClass shares table with the module */
    00114         break;
    00115
    00116       case T_FLOAT:
    00117         break;
    00118
    00119       case T_BIGNUM:
    00120         if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
    00121             size += RBIGNUM_LEN(obj) * sizeof(BDIGIT);
    00122         }
    00123         break;
    00124       case T_NODE:
    00125         switch (nd_type(obj)) {
    00126           case NODE_SCOPE:
    00127             if (RNODE(obj)->u1.tbl) {
    00128                 /* TODO: xfree(RANY(obj)->as.node.u1.tbl); */
    00129             }
    00130             break;
    00131           case NODE_ALLOCA:
    00132             /* TODO: xfree(RANY(obj)->as.node.u1.node); */
    00133             ;
    00134         }
    00135         break;                  /* no need to free iv_tbl */
    00136
    00137       case T_STRUCT:
    00138         if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
    00139             RSTRUCT(obj)->as.heap.ptr) {
    00140             size += sizeof(VALUE) * RSTRUCT_LEN(obj);
    00141         }
    00142         break;
    00143
    00144       case T_ZOMBIE:
    00145         break;
    00146
    00147       default:
    00148         rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
    00149                BUILTIN_TYPE(obj), (void*)obj);
    00150     }
    00151
    00152     return size;
    00153 }
    00154
    00155 /*
    00156  *  call-seq:
    00157  *    ObjectSpace.memsize_of(obj) -> Integer
    00158  *
    00159  *  Return consuming memory size of obj.
    00160  *
    00161  *  Note that this information is incomplete.  You need to deal with
    00162  *  this information as only a *HINT*.  Especaially, the size of
    00163  *  T_DATA may not right size.
    00164  *
    00165  *  This method is not expected to work except C Ruby.
    00166  */
    00167
    00168 static VALUE
    00169 memsize_of_m(VALUE self, VALUE obj)
    00170 {
    00171     return SIZET2NUM(memsize_of(obj));
    00172 }
    00173
    00174 static int
    00175 set_zero_i(st_data_t key, st_data_t val, st_data_t arg)
    00176 {
    00177     VALUE k = (VALUE)key;
    00178     VALUE hash = (VALUE)arg;
    00179     rb_hash_aset(hash, k, INT2FIX(0));
    00180     return ST_CONTINUE;
    00181 }
    00182
    00183 static int
    00184 cos_i(void *vstart, void *vend, size_t stride, void *data)
    00185 {
    00186     size_t *counts = (size_t *)data;
    00187     VALUE v = (VALUE)vstart;
    00188
    00189     for (;v != (VALUE)vend; v += stride) {
    00190         if (RBASIC(v)->flags) {
    00191             counts[BUILTIN_TYPE(v)] += memsize_of(v);
    00192         }
    00193     }
    00194     return 0;
    00195 }
    00196
    00197 /*
    00198  *  call-seq:
    00199  *    ObjectSpace.count_objects_size([result_hash]) -> hash
    00200  *
    00201  *  Counts objects size (in bytes) for each type.
    00202  *
    00203  *  Note that this information is incomplete.  You need to deal with
    00204  *  this information as only a *HINT*.  Especaially, total size of
    00205  *  T_DATA may not right size.
    00206  *
    00207  *  It returns a hash as:
    00208  *    {:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...}
    00209  *
    00210  *  If the optional argument, result_hash, is given,
    00211  *  it is overwritten and returned.
    00212  *  This is intended to avoid probe effect.
    00213  *
    00214  *  The contents of the returned hash is implementation defined.
    00215  *  It may be changed in future.
    00216  *
    00217  *  This method is not expected to work except C Ruby.
    00218  */
    00219
    00220 static VALUE
    00221 count_objects_size(int argc, VALUE *argv, VALUE os)
    00222 {
    00223     size_t counts[T_MASK+1];
    00224     size_t total = 0;
    00225     size_t i;
    00226     VALUE hash;
    00227
    00228     if (rb_scan_args(argc, argv, "01", &hash) == 1) {
    00229         if (TYPE(hash) != T_HASH)
    00230             rb_raise(rb_eTypeError, "non-hash given");
    00231     }
    00232
    00233     for (i = 0; i <= T_MASK; i++) {
    00234         counts[i] = 0;
    00235     }
    00236
    00237     rb_objspace_each_objects(cos_i, &counts[0]);
    00238
    00239     if (hash == Qnil) {
    00240         hash = rb_hash_new();
    00241     }
    00242     else if (!RHASH_EMPTY_P(hash)) {
    00243         st_foreach(RHASH_TBL(hash), set_zero_i, hash);
    00244     }
    00245
    00246     for (i = 0; i <= T_MASK; i++) {
    00247         if (counts[i]) {
    00248             VALUE type;
    00249             switch (i) {
    00250 #define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
    00251                 COUNT_TYPE(T_NONE);
    00252                 COUNT_TYPE(T_OBJECT);
    00253                 COUNT_TYPE(T_CLASS);
    00254                 COUNT_TYPE(T_MODULE);
    00255                 COUNT_TYPE(T_FLOAT);
    00256                 COUNT_TYPE(T_STRING);
    00257                 COUNT_TYPE(T_REGEXP);
    00258                 COUNT_TYPE(T_ARRAY);
    00259                 COUNT_TYPE(T_HASH);
    00260                 COUNT_TYPE(T_STRUCT);
    00261                 COUNT_TYPE(T_BIGNUM);
    00262                 COUNT_TYPE(T_FILE);
    00263                 COUNT_TYPE(T_DATA);
    00264                 COUNT_TYPE(T_MATCH);
    00265                 COUNT_TYPE(T_COMPLEX);
    00266                 COUNT_TYPE(T_RATIONAL);
    00267                 COUNT_TYPE(T_NIL);
    00268                 COUNT_TYPE(T_TRUE);
    00269                 COUNT_TYPE(T_FALSE);
    00270                 COUNT_TYPE(T_SYMBOL);
    00271                 COUNT_TYPE(T_FIXNUM);
    00272                 COUNT_TYPE(T_UNDEF);
    00273                 COUNT_TYPE(T_NODE);
    00274                 COUNT_TYPE(T_ICLASS);
    00275                 COUNT_TYPE(T_ZOMBIE);
    00276 #undef COUNT_TYPE
    00277               default: type = INT2NUM(i); break;
    00278             }
    00279             total += counts[i];
    00280             rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
    00281         }
    00282     }
    00283     rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
    00284     return hash;
    00285 }
    00286
    00287 static int
    00288 cn_i(void *vstart, void *vend, size_t stride, void *n)
    00289 {
    00290     size_t *nodes = (size_t *)n;
    00291     VALUE v = (VALUE)vstart;
    00292
    00293     for (; v != (VALUE)vend; v += stride) {
    00294         if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) {
    00295             size_t s = nd_type((NODE *)v);
    00296             nodes[s]++;
    00297         }
    00298     }
    00299
    00300     return 0;
    00301 }
    00302
    00303 /*
    00304  *  call-seq:
    00305  *     ObjectSpace.count_nodes([result_hash]) -> hash
    00306  *
    00307  *  Counts nodes for each node type.
    00308  *
    00309  *  This method is not for ordinary Ruby programmers, but for MRI developers
    00310  *  who have interest in MRI performance and memory usage.
    00311  *
    00312  *  It returns a hash as:
    00313  *  {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
    00314  *
    00315  *  If the optional argument, result_hash, is given,
    00316  *  it is overwritten and returned.
    00317  *  This is intended to avoid probe effect.
    00318  *
    00319  *  The contents of the returned hash is implementation defined.
    00320  *  It may be changed in future.
    00321  *
    00322  *  This method is not expected to work except C Ruby.
    00323  */
    00324
    00325 static VALUE
    00326 count_nodes(int argc, VALUE *argv, VALUE os)
    00327 {
    00328     size_t nodes[NODE_LAST+1];
    00329     size_t i;
    00330     VALUE hash;
    00331
    00332     if (rb_scan_args(argc, argv, "01", &hash) == 1) {
    00333         if (TYPE(hash) != T_HASH)
    00334             rb_raise(rb_eTypeError, "non-hash given");
    00335     }
    00336
    00337     for (i = 0; i <= NODE_LAST; i++) {
    00338         nodes[i] = 0;
    00339     }
    00340
    00341     rb_objspace_each_objects(cn_i, &nodes[0]);
    00342
    00343     if (hash == Qnil) {
    00344         hash = rb_hash_new();
    00345     }
    00346     else if (!RHASH_EMPTY_P(hash)) {
    00347         st_foreach(RHASH_TBL(hash), set_zero_i, hash);
    00348     }
    00349
    00350     for (i=0; i<NODE_LAST; i++) {
    00351         if (nodes[i] != 0) {
    00352             VALUE node;
    00353             switch (i) {
    00354 #define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break;
    00355                 COUNT_NODE(NODE_SCOPE);
    00356                 COUNT_NODE(NODE_BLOCK);
    00357                 COUNT_NODE(NODE_IF);
    00358                 COUNT_NODE(NODE_CASE);
    00359                 COUNT_NODE(NODE_WHEN);
    00360                 COUNT_NODE(NODE_OPT_N);
    00361                 COUNT_NODE(NODE_WHILE);
    00362                 COUNT_NODE(NODE_UNTIL);
    00363                 COUNT_NODE(NODE_ITER);
    00364                 COUNT_NODE(NODE_FOR);
    00365                 COUNT_NODE(NODE_BREAK);
    00366                 COUNT_NODE(NODE_NEXT);
    00367                 COUNT_NODE(NODE_REDO);
    00368                 COUNT_NODE(NODE_RETRY);
    00369                 COUNT_NODE(NODE_BEGIN);
    00370                 COUNT_NODE(NODE_RESCUE);
    00371                 COUNT_NODE(NODE_RESBODY);
    00372                 COUNT_NODE(NODE_ENSURE);
    00373                 COUNT_NODE(NODE_AND);
    00374                 COUNT_NODE(NODE_OR);
    00375                 COUNT_NODE(NODE_MASGN);
    00376                 COUNT_NODE(NODE_LASGN);
    00377                 COUNT_NODE(NODE_DASGN);
    00378                 COUNT_NODE(NODE_DASGN_CURR);
    00379                 COUNT_NODE(NODE_GASGN);
    00380                 COUNT_NODE(NODE_IASGN);
    00381                 COUNT_NODE(NODE_IASGN2);
    00382                 COUNT_NODE(NODE_CDECL);
    00383                 COUNT_NODE(NODE_CVASGN);
    00384                 COUNT_NODE(NODE_CVDECL);
    00385                 COUNT_NODE(NODE_OP_ASGN1);
    00386                 COUNT_NODE(NODE_OP_ASGN2);
    00387                 COUNT_NODE(NODE_OP_ASGN_AND);
    00388                 COUNT_NODE(NODE_OP_ASGN_OR);
    00389                 COUNT_NODE(NODE_CALL);
    00390                 COUNT_NODE(NODE_FCALL);
    00391                 COUNT_NODE(NODE_VCALL);
    00392                 COUNT_NODE(NODE_SUPER);
    00393                 COUNT_NODE(NODE_ZSUPER);
    00394                 COUNT_NODE(NODE_ARRAY);
    00395                 COUNT_NODE(NODE_ZARRAY);
    00396                 COUNT_NODE(NODE_VALUES);
    00397                 COUNT_NODE(NODE_HASH);
    00398                 COUNT_NODE(NODE_RETURN);
    00399                 COUNT_NODE(NODE_YIELD);
    00400                 COUNT_NODE(NODE_LVAR);
    00401                 COUNT_NODE(NODE_DVAR);
    00402                 COUNT_NODE(NODE_GVAR);
    00403                 COUNT_NODE(NODE_IVAR);
    00404                 COUNT_NODE(NODE_CONST);
    00405                 COUNT_NODE(NODE_CVAR);
    00406                 COUNT_NODE(NODE_NTH_REF);
    00407                 COUNT_NODE(NODE_BACK_REF);
    00408                 COUNT_NODE(NODE_MATCH);
    00409                 COUNT_NODE(NODE_MATCH2);
    00410                 COUNT_NODE(NODE_MATCH3);
    00411                 COUNT_NODE(NODE_LIT);
    00412                 COUNT_NODE(NODE_STR);
    00413                 COUNT_NODE(NODE_DSTR);
    00414                 COUNT_NODE(NODE_XSTR);
    00415                 COUNT_NODE(NODE_DXSTR);
    00416                 COUNT_NODE(NODE_EVSTR);
    00417                 COUNT_NODE(NODE_DREGX);
    00418                 COUNT_NODE(NODE_DREGX_ONCE);
    00419                 COUNT_NODE(NODE_ARGS);
    00420                 COUNT_NODE(NODE_ARGS_AUX);
    00421                 COUNT_NODE(NODE_OPT_ARG);
    00422                 COUNT_NODE(NODE_POSTARG);
    00423                 COUNT_NODE(NODE_ARGSCAT);
    00424                 COUNT_NODE(NODE_ARGSPUSH);
    00425                 COUNT_NODE(NODE_SPLAT);
    00426                 COUNT_NODE(NODE_TO_ARY);
    00427                 COUNT_NODE(NODE_BLOCK_ARG);
    00428                 COUNT_NODE(NODE_BLOCK_PASS);
    00429                 COUNT_NODE(NODE_DEFN);
    00430                 COUNT_NODE(NODE_DEFS);
    00431                 COUNT_NODE(NODE_ALIAS);
    00432                 COUNT_NODE(NODE_VALIAS);
    00433                 COUNT_NODE(NODE_UNDEF);
    00434                 COUNT_NODE(NODE_CLASS);
    00435                 COUNT_NODE(NODE_MODULE);
    00436                 COUNT_NODE(NODE_SCLASS);
    00437                 COUNT_NODE(NODE_COLON2);
    00438                 COUNT_NODE(NODE_COLON3);
    00439                 COUNT_NODE(NODE_DOT2);
    00440                 COUNT_NODE(NODE_DOT3);
    00441                 COUNT_NODE(NODE_FLIP2);
    00442                 COUNT_NODE(NODE_FLIP3);
    00443                 COUNT_NODE(NODE_SELF);
    00444                 COUNT_NODE(NODE_NIL);
    00445                 COUNT_NODE(NODE_TRUE);
    00446                 COUNT_NODE(NODE_FALSE);
    00447                 COUNT_NODE(NODE_ERRINFO);
    00448                 COUNT_NODE(NODE_DEFINED);
    00449                 COUNT_NODE(NODE_POSTEXE);
    00450                 COUNT_NODE(NODE_ALLOCA);
    00451                 COUNT_NODE(NODE_BMETHOD);
    00452                 COUNT_NODE(NODE_MEMO);
    00453                 COUNT_NODE(NODE_IFUNC);
    00454                 COUNT_NODE(NODE_DSYM);
    00455                 COUNT_NODE(NODE_ATTRASGN);
    00456                 COUNT_NODE(NODE_PRELUDE);
    00457                 COUNT_NODE(NODE_LAMBDA);
    00458                 COUNT_NODE(NODE_OPTBLOCK);
    00459 #undef COUNT_NODE
    00460               default: node = INT2FIX(nodes[i]);
    00461             }
    00462             rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
    00463         }
    00464     }
    00465     return hash;
    00466 }
    00467
    00468 static int
    00469 cto_i(void *vstart, void *vend, size_t stride, void *data)
    00470 {
    00471     VALUE hash = (VALUE)data;
    00472     VALUE v = (VALUE)vstart;
    00473
    00474     for (; v != (VALUE)vend; v += stride) {
    00475         if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_DATA) {
    00476             VALUE counter = rb_hash_aref(hash, RBASIC(v)->klass);
    00477             if (NIL_P(counter)) {
    00478                 counter = INT2FIX(1);
    00479             }
    00480             else {
    00481                 counter = INT2FIX(FIX2INT(counter) + 1);
    00482             }
    00483             rb_hash_aset(hash, RBASIC(v)->klass, counter);
    00484         }
    00485     }
    00486
    00487     return 0;
    00488 }
    00489
    00490 /*
    00491  *  call-seq:
    00492  *     ObjectSpace.count_tdata_objects([result_hash]) -> hash
    00493  *
    00494  *  Counts nodes for each node type.
    00495  *
    00496  *  This method is not for ordinary Ruby programmers, but for MRI developers
    00497  *  who interest on MRI performance.
    00498  *
    00499  *  It returns a hash as:
    00500  *  {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
    00501  *
    00502  *  If the optional argument, result_hash, is given,
    00503  *  it is overwritten and returned.
    00504  *  This is intended to avoid probe effect.
    00505  *
    00506  *  The contents of the returned hash is implementation defined.
    00507  *  It may be changed in future.
    00508  *
    00509  *  This method is not expected to work except C Ruby.
    00510  *
    00511  */
    00512
    00513 static VALUE
    00514 count_tdata_objects(int argc, VALUE *argv, VALUE self)
    00515 {
    00516     VALUE hash;
    00517
    00518     if (rb_scan_args(argc, argv, "01", &hash) == 1) {
    00519         if (TYPE(hash) != T_HASH)
    00520             rb_raise(rb_eTypeError, "non-hash given");
    00521     }
    00522
    00523     if (hash == Qnil) {
    00524         hash = rb_hash_new();
    00525     }
    00526     else if (!RHASH_EMPTY_P(hash)) {
    00527         st_foreach(RHASH_TBL(hash), set_zero_i, hash);
    00528     }
    00529
    00530     rb_objspace_each_objects(cto_i, (void *)hash);
    00531
    00532     return hash;
    00533 }
    00534
    00535 /* objspace library extends ObjectSpace module and add several
    00536  * methods to get internal statistic information about
    00537  * object/memory management.
    00538  *
    00539  * Generally, you *SHOULD NOT*use this library if you do not know
    00540  * about the MRI implementation.  Mainly, this library is for (memory)
    00541  * profiler developers and MRI developers who need to know how MRI
    00542  * memory usage.
    00543  */
    00544
    00545 void
    00546 Init_objspace(void)
    00547 {
    00548     VALUE rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
    00549
    00550     rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
    00551     rb_define_module_function(rb_mObjSpace, "memsize_of", memsize_of_m, 1);
    00552     rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
    00553     rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
    00554 }
    00555