00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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);
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
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
00129 }
00130 break;
00131 case NODE_ALLOCA:
00132
00133 ;
00134 }
00135 break;
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 default:
00145 rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
00146 BUILTIN_TYPE(obj), (void*)obj);
00147 }
00148
00149 return size;
00150 }
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 static VALUE
00166 memsize_of_m(VALUE self, VALUE obj)
00167 {
00168 return SIZET2NUM(memsize_of(obj));
00169 }
00170
00171 static int
00172 set_zero_i(st_data_t key, st_data_t val, st_data_t arg)
00173 {
00174 VALUE k = (VALUE)key;
00175 VALUE hash = (VALUE)arg;
00176 rb_hash_aset(hash, k, INT2FIX(0));
00177 return ST_CONTINUE;
00178 }
00179
00180 static int
00181 cos_i(void *vstart, void *vend, size_t stride, void *data)
00182 {
00183 size_t *counts = (size_t *)data;
00184 VALUE v = (VALUE)vstart;
00185
00186 for (;v != (VALUE)vend; v += stride) {
00187 if (RBASIC(v)->flags) {
00188 counts[BUILTIN_TYPE(v)] += memsize_of(v);
00189 }
00190 }
00191 return 0;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 static VALUE
00218 count_objects_size(int argc, VALUE *argv, VALUE os)
00219 {
00220 size_t counts[T_MASK+1];
00221 size_t total = 0;
00222 size_t i;
00223 VALUE hash;
00224
00225 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00226 if (TYPE(hash) != T_HASH)
00227 rb_raise(rb_eTypeError, "non-hash given");
00228 }
00229
00230 for (i = 0; i <= T_MASK; i++) {
00231 counts[i] = 0;
00232 }
00233
00234 rb_objspace_each_objects(cos_i, &counts[0]);
00235
00236 if (hash == Qnil) {
00237 hash = rb_hash_new();
00238 }
00239 else if (!RHASH_EMPTY_P(hash)) {
00240 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00241 }
00242
00243 for (i = 0; i <= T_MASK; i++) {
00244 if (counts[i]) {
00245 VALUE type;
00246 switch (i) {
00247 #define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
00248 COUNT_TYPE(T_NONE);
00249 COUNT_TYPE(T_OBJECT);
00250 COUNT_TYPE(T_CLASS);
00251 COUNT_TYPE(T_MODULE);
00252 COUNT_TYPE(T_FLOAT);
00253 COUNT_TYPE(T_STRING);
00254 COUNT_TYPE(T_REGEXP);
00255 COUNT_TYPE(T_ARRAY);
00256 COUNT_TYPE(T_HASH);
00257 COUNT_TYPE(T_STRUCT);
00258 COUNT_TYPE(T_BIGNUM);
00259 COUNT_TYPE(T_FILE);
00260 COUNT_TYPE(T_DATA);
00261 COUNT_TYPE(T_MATCH);
00262 COUNT_TYPE(T_COMPLEX);
00263 COUNT_TYPE(T_RATIONAL);
00264 COUNT_TYPE(T_NIL);
00265 COUNT_TYPE(T_TRUE);
00266 COUNT_TYPE(T_FALSE);
00267 COUNT_TYPE(T_SYMBOL);
00268 COUNT_TYPE(T_FIXNUM);
00269 COUNT_TYPE(T_UNDEF);
00270 COUNT_TYPE(T_NODE);
00271 COUNT_TYPE(T_ICLASS);
00272 COUNT_TYPE(T_ZOMBIE);
00273 #undef COUNT_TYPE
00274 default: type = INT2NUM(i); break;
00275 }
00276 total += counts[i];
00277 rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
00278 }
00279 }
00280 rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
00281 return hash;
00282 }
00283
00284 static int
00285 cn_i(void *vstart, void *vend, size_t stride, void *n)
00286 {
00287 size_t *nodes = (size_t *)n;
00288 VALUE v = (VALUE)vstart;
00289
00290 for (; v != (VALUE)vend; v += stride) {
00291 if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) {
00292 size_t s = nd_type((NODE *)v);
00293 nodes[s]++;
00294 }
00295 }
00296
00297 return 0;
00298 }
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 static VALUE
00323 count_nodes(int argc, VALUE *argv, VALUE os)
00324 {
00325 size_t nodes[NODE_LAST+1];
00326 size_t i;
00327 VALUE hash;
00328
00329 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00330 if (TYPE(hash) != T_HASH)
00331 rb_raise(rb_eTypeError, "non-hash given");
00332 }
00333
00334 for (i = 0; i <= NODE_LAST; i++) {
00335 nodes[i] = 0;
00336 }
00337
00338 rb_objspace_each_objects(cn_i, &nodes[0]);
00339
00340 if (hash == Qnil) {
00341 hash = rb_hash_new();
00342 }
00343 else if (!RHASH_EMPTY_P(hash)) {
00344 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00345 }
00346
00347 for (i=0; i<NODE_LAST; i++) {
00348 if (nodes[i] != 0) {
00349 VALUE node;
00350 switch (i) {
00351 #define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break;
00352 COUNT_NODE(NODE_SCOPE);
00353 COUNT_NODE(NODE_BLOCK);
00354 COUNT_NODE(NODE_IF);
00355 COUNT_NODE(NODE_CASE);
00356 COUNT_NODE(NODE_WHEN);
00357 COUNT_NODE(NODE_OPT_N);
00358 COUNT_NODE(NODE_WHILE);
00359 COUNT_NODE(NODE_UNTIL);
00360 COUNT_NODE(NODE_ITER);
00361 COUNT_NODE(NODE_FOR);
00362 COUNT_NODE(NODE_BREAK);
00363 COUNT_NODE(NODE_NEXT);
00364 COUNT_NODE(NODE_REDO);
00365 COUNT_NODE(NODE_RETRY);
00366 COUNT_NODE(NODE_BEGIN);
00367 COUNT_NODE(NODE_RESCUE);
00368 COUNT_NODE(NODE_RESBODY);
00369 COUNT_NODE(NODE_ENSURE);
00370 COUNT_NODE(NODE_AND);
00371 COUNT_NODE(NODE_OR);
00372 COUNT_NODE(NODE_MASGN);
00373 COUNT_NODE(NODE_LASGN);
00374 COUNT_NODE(NODE_DASGN);
00375 COUNT_NODE(NODE_DASGN_CURR);
00376 COUNT_NODE(NODE_GASGN);
00377 COUNT_NODE(NODE_IASGN);
00378 COUNT_NODE(NODE_IASGN2);
00379 COUNT_NODE(NODE_CDECL);
00380 COUNT_NODE(NODE_CVASGN);
00381 COUNT_NODE(NODE_CVDECL);
00382 COUNT_NODE(NODE_OP_ASGN1);
00383 COUNT_NODE(NODE_OP_ASGN2);
00384 COUNT_NODE(NODE_OP_ASGN_AND);
00385 COUNT_NODE(NODE_OP_ASGN_OR);
00386 COUNT_NODE(NODE_CALL);
00387 COUNT_NODE(NODE_FCALL);
00388 COUNT_NODE(NODE_VCALL);
00389 COUNT_NODE(NODE_SUPER);
00390 COUNT_NODE(NODE_ZSUPER);
00391 COUNT_NODE(NODE_ARRAY);
00392 COUNT_NODE(NODE_ZARRAY);
00393 COUNT_NODE(NODE_VALUES);
00394 COUNT_NODE(NODE_HASH);
00395 COUNT_NODE(NODE_RETURN);
00396 COUNT_NODE(NODE_YIELD);
00397 COUNT_NODE(NODE_LVAR);
00398 COUNT_NODE(NODE_DVAR);
00399 COUNT_NODE(NODE_GVAR);
00400 COUNT_NODE(NODE_IVAR);
00401 COUNT_NODE(NODE_CONST);
00402 COUNT_NODE(NODE_CVAR);
00403 COUNT_NODE(NODE_NTH_REF);
00404 COUNT_NODE(NODE_BACK_REF);
00405 COUNT_NODE(NODE_MATCH);
00406 COUNT_NODE(NODE_MATCH2);
00407 COUNT_NODE(NODE_MATCH3);
00408 COUNT_NODE(NODE_LIT);
00409 COUNT_NODE(NODE_STR);
00410 COUNT_NODE(NODE_DSTR);
00411 COUNT_NODE(NODE_XSTR);
00412 COUNT_NODE(NODE_DXSTR);
00413 COUNT_NODE(NODE_EVSTR);
00414 COUNT_NODE(NODE_DREGX);
00415 COUNT_NODE(NODE_DREGX_ONCE);
00416 COUNT_NODE(NODE_ARGS);
00417 COUNT_NODE(NODE_ARGS_AUX);
00418 COUNT_NODE(NODE_OPT_ARG);
00419 COUNT_NODE(NODE_POSTARG);
00420 COUNT_NODE(NODE_ARGSCAT);
00421 COUNT_NODE(NODE_ARGSPUSH);
00422 COUNT_NODE(NODE_SPLAT);
00423 COUNT_NODE(NODE_TO_ARY);
00424 COUNT_NODE(NODE_BLOCK_ARG);
00425 COUNT_NODE(NODE_BLOCK_PASS);
00426 COUNT_NODE(NODE_DEFN);
00427 COUNT_NODE(NODE_DEFS);
00428 COUNT_NODE(NODE_ALIAS);
00429 COUNT_NODE(NODE_VALIAS);
00430 COUNT_NODE(NODE_UNDEF);
00431 COUNT_NODE(NODE_CLASS);
00432 COUNT_NODE(NODE_MODULE);
00433 COUNT_NODE(NODE_SCLASS);
00434 COUNT_NODE(NODE_COLON2);
00435 COUNT_NODE(NODE_COLON3);
00436 COUNT_NODE(NODE_DOT2);
00437 COUNT_NODE(NODE_DOT3);
00438 COUNT_NODE(NODE_FLIP2);
00439 COUNT_NODE(NODE_FLIP3);
00440 COUNT_NODE(NODE_SELF);
00441 COUNT_NODE(NODE_NIL);
00442 COUNT_NODE(NODE_TRUE);
00443 COUNT_NODE(NODE_FALSE);
00444 COUNT_NODE(NODE_ERRINFO);
00445 COUNT_NODE(NODE_DEFINED);
00446 COUNT_NODE(NODE_POSTEXE);
00447 COUNT_NODE(NODE_ALLOCA);
00448 COUNT_NODE(NODE_BMETHOD);
00449 COUNT_NODE(NODE_MEMO);
00450 COUNT_NODE(NODE_IFUNC);
00451 COUNT_NODE(NODE_DSYM);
00452 COUNT_NODE(NODE_ATTRASGN);
00453 COUNT_NODE(NODE_PRELUDE);
00454 COUNT_NODE(NODE_LAMBDA);
00455 COUNT_NODE(NODE_OPTBLOCK);
00456 #undef COUNT_NODE
00457 default: node = INT2FIX(nodes[i]);
00458 }
00459 rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
00460 }
00461 }
00462 return hash;
00463 }
00464
00465 static int
00466 cto_i(void *vstart, void *vend, size_t stride, void *data)
00467 {
00468 VALUE hash = (VALUE)data;
00469 VALUE v = (VALUE)vstart;
00470
00471 for (; v != (VALUE)vend; v += stride) {
00472 if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_DATA) {
00473 VALUE counter = rb_hash_aref(hash, RBASIC(v)->klass);
00474 if (NIL_P(counter)) {
00475 counter = INT2FIX(1);
00476 }
00477 else {
00478 counter = INT2FIX(FIX2INT(counter) + 1);
00479 }
00480 rb_hash_aset(hash, RBASIC(v)->klass, counter);
00481 }
00482 }
00483
00484 return 0;
00485 }
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 static VALUE
00511 count_tdata_objects(int argc, VALUE *argv, VALUE self)
00512 {
00513 VALUE hash;
00514
00515 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00516 if (TYPE(hash) != T_HASH)
00517 rb_raise(rb_eTypeError, "non-hash given");
00518 }
00519
00520 if (hash == Qnil) {
00521 hash = rb_hash_new();
00522 }
00523 else if (!RHASH_EMPTY_P(hash)) {
00524 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00525 }
00526
00527 rb_objspace_each_objects(cto_i, (void *)hash);
00528
00529 return hash;
00530 }
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542 void
00543 Init_objspace(void)
00544 {
00545 VALUE rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
00546
00547 rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
00548 rb_define_module_function(rb_mObjSpace, "memsize_of", memsize_of_m, 1);
00549 rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
00550 rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
00551 }
00552