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 #include "gc.h"
00032 #include "regint.h"
00033 #include "internal.h"
00034
00035 size_t rb_str_memsize(VALUE);
00036 size_t rb_ary_memsize(VALUE);
00037 size_t rb_io_memsize(const rb_io_t *);
00038 size_t rb_generic_ivar_memsize(VALUE);
00039 size_t rb_objspace_data_type_memsize(VALUE obj);
00040
00041 static size_t
00042 memsize_of(VALUE obj)
00043 {
00044 size_t size = 0;
00045
00046 if (SPECIAL_CONST_P(obj)) {
00047 return 0;
00048 }
00049
00050 if (FL_TEST(obj, FL_EXIVAR)) {
00051 size += rb_generic_ivar_memsize(obj);
00052 }
00053
00054 switch (BUILTIN_TYPE(obj)) {
00055 case T_OBJECT:
00056 if (!(RBASIC(obj)->flags & ROBJECT_EMBED) &&
00057 ROBJECT(obj)->as.heap.ivptr) {
00058 size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE);
00059 }
00060 break;
00061 case T_MODULE:
00062 case T_CLASS:
00063 size += st_memsize(RCLASS_M_TBL(obj));
00064 if (RCLASS_IV_TBL(obj)) {
00065 size += st_memsize(RCLASS_IV_TBL(obj));
00066 }
00067 if (RCLASS_IV_INDEX_TBL(obj)) {
00068 size += st_memsize(RCLASS_IV_INDEX_TBL(obj));
00069 }
00070 if (RCLASS(obj)->ptr->iv_tbl) {
00071 size += st_memsize(RCLASS(obj)->ptr->iv_tbl);
00072 }
00073 if (RCLASS(obj)->ptr->const_tbl) {
00074 size += st_memsize(RCLASS(obj)->ptr->const_tbl);
00075 }
00076 size += sizeof(rb_classext_t);
00077 break;
00078 case T_STRING:
00079 size += rb_str_memsize(obj);
00080 break;
00081 case T_ARRAY:
00082 size += rb_ary_memsize(obj);
00083 break;
00084 case T_HASH:
00085 if (RHASH(obj)->ntbl) {
00086 size += st_memsize(RHASH(obj)->ntbl);
00087 }
00088 break;
00089 case T_REGEXP:
00090 if (RREGEXP(obj)->ptr) {
00091 size += onig_memsize(RREGEXP(obj)->ptr);
00092 }
00093 break;
00094 case T_DATA:
00095 size += rb_objspace_data_type_memsize(obj);
00096 break;
00097 case T_MATCH:
00098 if (RMATCH(obj)->rmatch) {
00099 struct rmatch *rm = RMATCH(obj)->rmatch;
00100 size += sizeof(struct re_registers);
00101 size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
00102 size += sizeof(struct rmatch);
00103 }
00104 break;
00105 case T_FILE:
00106 if (RFILE(obj)->fptr) {
00107 size += rb_io_memsize(RFILE(obj)->fptr);
00108 }
00109 break;
00110 case T_RATIONAL:
00111 case T_COMPLEX:
00112 break;
00113 case T_ICLASS:
00114
00115 break;
00116
00117 case T_FLOAT:
00118 break;
00119
00120 case T_BIGNUM:
00121 if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
00122 size += RBIGNUM_LEN(obj) * sizeof(BDIGIT);
00123 }
00124 break;
00125 case T_NODE:
00126 switch (nd_type(obj)) {
00127 case NODE_SCOPE:
00128 if (RNODE(obj)->u1.tbl) {
00129
00130 }
00131 break;
00132 case NODE_ALLOCA:
00133
00134 ;
00135 }
00136 break;
00137
00138 case T_STRUCT:
00139 if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
00140 RSTRUCT(obj)->as.heap.ptr) {
00141 size += sizeof(VALUE) * RSTRUCT_LEN(obj);
00142 }
00143 break;
00144
00145 case T_ZOMBIE:
00146 break;
00147
00148 default:
00149 rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
00150 BUILTIN_TYPE(obj), (void*)obj);
00151 }
00152
00153 return size;
00154 }
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 static VALUE
00170 memsize_of_m(VALUE self, VALUE obj)
00171 {
00172 return SIZET2NUM(memsize_of(obj));
00173 }
00174
00175 struct total_data {
00176 size_t total;
00177 VALUE klass;
00178 };
00179
00180 static int
00181 total_i(void *vstart, void *vend, size_t stride, void *ptr)
00182 {
00183 VALUE v;
00184 struct total_data *data = (struct total_data *)ptr;
00185
00186 for (v = (VALUE)vstart; v != (VALUE)vend; v += stride) {
00187 if (RBASIC(v)->flags) {
00188 switch (BUILTIN_TYPE(v)) {
00189 case T_NONE:
00190 case T_ICLASS:
00191 case T_NODE:
00192 case T_ZOMBIE:
00193 continue;
00194 case T_CLASS:
00195 if (FL_TEST(v, FL_SINGLETON))
00196 continue;
00197 default:
00198 if (data->klass == 0 || rb_obj_is_kind_of(v, data->klass)) {
00199 data->total += memsize_of(v);
00200 }
00201 }
00202 }
00203 }
00204
00205 return 0;
00206 }
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 static VALUE
00236 memsize_of_all_m(int argc, VALUE *argv, VALUE self)
00237 {
00238 struct total_data data = {0, 0};
00239
00240 if (argc > 0) {
00241 rb_scan_args(argc, argv, "01", &data.klass);
00242 }
00243
00244 rb_objspace_each_objects(total_i, &data);
00245 return SIZET2NUM(data.total);
00246 }
00247
00248 static int
00249 set_zero_i(st_data_t key, st_data_t val, st_data_t arg)
00250 {
00251 VALUE k = (VALUE)key;
00252 VALUE hash = (VALUE)arg;
00253 rb_hash_aset(hash, k, INT2FIX(0));
00254 return ST_CONTINUE;
00255 }
00256
00257 static int
00258 cos_i(void *vstart, void *vend, size_t stride, void *data)
00259 {
00260 size_t *counts = (size_t *)data;
00261 VALUE v = (VALUE)vstart;
00262
00263 for (;v != (VALUE)vend; v += stride) {
00264 if (RBASIC(v)->flags) {
00265 counts[BUILTIN_TYPE(v)] += memsize_of(v);
00266 }
00267 }
00268 return 0;
00269 }
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 static VALUE
00295 count_objects_size(int argc, VALUE *argv, VALUE os)
00296 {
00297 size_t counts[T_MASK+1];
00298 size_t total = 0;
00299 size_t i;
00300 VALUE hash;
00301
00302 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00303 if (TYPE(hash) != T_HASH)
00304 rb_raise(rb_eTypeError, "non-hash given");
00305 }
00306
00307 for (i = 0; i <= T_MASK; i++) {
00308 counts[i] = 0;
00309 }
00310
00311 rb_objspace_each_objects(cos_i, &counts[0]);
00312
00313 if (hash == Qnil) {
00314 hash = rb_hash_new();
00315 }
00316 else if (!RHASH_EMPTY_P(hash)) {
00317 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00318 }
00319
00320 for (i = 0; i <= T_MASK; i++) {
00321 if (counts[i]) {
00322 VALUE type;
00323 switch (i) {
00324 #define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
00325 COUNT_TYPE(T_NONE);
00326 COUNT_TYPE(T_OBJECT);
00327 COUNT_TYPE(T_CLASS);
00328 COUNT_TYPE(T_MODULE);
00329 COUNT_TYPE(T_FLOAT);
00330 COUNT_TYPE(T_STRING);
00331 COUNT_TYPE(T_REGEXP);
00332 COUNT_TYPE(T_ARRAY);
00333 COUNT_TYPE(T_HASH);
00334 COUNT_TYPE(T_STRUCT);
00335 COUNT_TYPE(T_BIGNUM);
00336 COUNT_TYPE(T_FILE);
00337 COUNT_TYPE(T_DATA);
00338 COUNT_TYPE(T_MATCH);
00339 COUNT_TYPE(T_COMPLEX);
00340 COUNT_TYPE(T_RATIONAL);
00341 COUNT_TYPE(T_NIL);
00342 COUNT_TYPE(T_TRUE);
00343 COUNT_TYPE(T_FALSE);
00344 COUNT_TYPE(T_SYMBOL);
00345 COUNT_TYPE(T_FIXNUM);
00346 COUNT_TYPE(T_UNDEF);
00347 COUNT_TYPE(T_NODE);
00348 COUNT_TYPE(T_ICLASS);
00349 COUNT_TYPE(T_ZOMBIE);
00350 #undef COUNT_TYPE
00351 default: type = INT2NUM(i); break;
00352 }
00353 total += counts[i];
00354 rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
00355 }
00356 }
00357 rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
00358 return hash;
00359 }
00360
00361 static int
00362 cn_i(void *vstart, void *vend, size_t stride, void *n)
00363 {
00364 size_t *nodes = (size_t *)n;
00365 VALUE v = (VALUE)vstart;
00366
00367 for (; v != (VALUE)vend; v += stride) {
00368 if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) {
00369 size_t s = nd_type((NODE *)v);
00370 nodes[s]++;
00371 }
00372 }
00373
00374 return 0;
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 static VALUE
00400 count_nodes(int argc, VALUE *argv, VALUE os)
00401 {
00402 size_t nodes[NODE_LAST+1];
00403 size_t i;
00404 VALUE hash;
00405
00406 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00407 if (TYPE(hash) != T_HASH)
00408 rb_raise(rb_eTypeError, "non-hash given");
00409 }
00410
00411 for (i = 0; i <= NODE_LAST; i++) {
00412 nodes[i] = 0;
00413 }
00414
00415 rb_objspace_each_objects(cn_i, &nodes[0]);
00416
00417 if (hash == Qnil) {
00418 hash = rb_hash_new();
00419 }
00420 else if (!RHASH_EMPTY_P(hash)) {
00421 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00422 }
00423
00424 for (i=0; i<NODE_LAST; i++) {
00425 if (nodes[i] != 0) {
00426 VALUE node;
00427 switch (i) {
00428 #define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break;
00429 COUNT_NODE(NODE_SCOPE);
00430 COUNT_NODE(NODE_BLOCK);
00431 COUNT_NODE(NODE_IF);
00432 COUNT_NODE(NODE_CASE);
00433 COUNT_NODE(NODE_WHEN);
00434 COUNT_NODE(NODE_OPT_N);
00435 COUNT_NODE(NODE_WHILE);
00436 COUNT_NODE(NODE_UNTIL);
00437 COUNT_NODE(NODE_ITER);
00438 COUNT_NODE(NODE_FOR);
00439 COUNT_NODE(NODE_BREAK);
00440 COUNT_NODE(NODE_NEXT);
00441 COUNT_NODE(NODE_REDO);
00442 COUNT_NODE(NODE_RETRY);
00443 COUNT_NODE(NODE_BEGIN);
00444 COUNT_NODE(NODE_RESCUE);
00445 COUNT_NODE(NODE_RESBODY);
00446 COUNT_NODE(NODE_ENSURE);
00447 COUNT_NODE(NODE_AND);
00448 COUNT_NODE(NODE_OR);
00449 COUNT_NODE(NODE_MASGN);
00450 COUNT_NODE(NODE_LASGN);
00451 COUNT_NODE(NODE_DASGN);
00452 COUNT_NODE(NODE_DASGN_CURR);
00453 COUNT_NODE(NODE_GASGN);
00454 COUNT_NODE(NODE_IASGN);
00455 COUNT_NODE(NODE_IASGN2);
00456 COUNT_NODE(NODE_CDECL);
00457 COUNT_NODE(NODE_CVASGN);
00458 COUNT_NODE(NODE_CVDECL);
00459 COUNT_NODE(NODE_OP_ASGN1);
00460 COUNT_NODE(NODE_OP_ASGN2);
00461 COUNT_NODE(NODE_OP_ASGN_AND);
00462 COUNT_NODE(NODE_OP_ASGN_OR);
00463 COUNT_NODE(NODE_CALL);
00464 COUNT_NODE(NODE_FCALL);
00465 COUNT_NODE(NODE_VCALL);
00466 COUNT_NODE(NODE_SUPER);
00467 COUNT_NODE(NODE_ZSUPER);
00468 COUNT_NODE(NODE_ARRAY);
00469 COUNT_NODE(NODE_ZARRAY);
00470 COUNT_NODE(NODE_VALUES);
00471 COUNT_NODE(NODE_HASH);
00472 COUNT_NODE(NODE_RETURN);
00473 COUNT_NODE(NODE_YIELD);
00474 COUNT_NODE(NODE_LVAR);
00475 COUNT_NODE(NODE_DVAR);
00476 COUNT_NODE(NODE_GVAR);
00477 COUNT_NODE(NODE_IVAR);
00478 COUNT_NODE(NODE_CONST);
00479 COUNT_NODE(NODE_CVAR);
00480 COUNT_NODE(NODE_NTH_REF);
00481 COUNT_NODE(NODE_BACK_REF);
00482 COUNT_NODE(NODE_MATCH);
00483 COUNT_NODE(NODE_MATCH2);
00484 COUNT_NODE(NODE_MATCH3);
00485 COUNT_NODE(NODE_LIT);
00486 COUNT_NODE(NODE_STR);
00487 COUNT_NODE(NODE_DSTR);
00488 COUNT_NODE(NODE_XSTR);
00489 COUNT_NODE(NODE_DXSTR);
00490 COUNT_NODE(NODE_EVSTR);
00491 COUNT_NODE(NODE_DREGX);
00492 COUNT_NODE(NODE_DREGX_ONCE);
00493 COUNT_NODE(NODE_ARGS);
00494 COUNT_NODE(NODE_ARGS_AUX);
00495 COUNT_NODE(NODE_OPT_ARG);
00496 COUNT_NODE(NODE_POSTARG);
00497 COUNT_NODE(NODE_ARGSCAT);
00498 COUNT_NODE(NODE_ARGSPUSH);
00499 COUNT_NODE(NODE_SPLAT);
00500 COUNT_NODE(NODE_TO_ARY);
00501 COUNT_NODE(NODE_BLOCK_ARG);
00502 COUNT_NODE(NODE_BLOCK_PASS);
00503 COUNT_NODE(NODE_DEFN);
00504 COUNT_NODE(NODE_DEFS);
00505 COUNT_NODE(NODE_ALIAS);
00506 COUNT_NODE(NODE_VALIAS);
00507 COUNT_NODE(NODE_UNDEF);
00508 COUNT_NODE(NODE_CLASS);
00509 COUNT_NODE(NODE_MODULE);
00510 COUNT_NODE(NODE_SCLASS);
00511 COUNT_NODE(NODE_COLON2);
00512 COUNT_NODE(NODE_COLON3);
00513 COUNT_NODE(NODE_DOT2);
00514 COUNT_NODE(NODE_DOT3);
00515 COUNT_NODE(NODE_FLIP2);
00516 COUNT_NODE(NODE_FLIP3);
00517 COUNT_NODE(NODE_SELF);
00518 COUNT_NODE(NODE_NIL);
00519 COUNT_NODE(NODE_TRUE);
00520 COUNT_NODE(NODE_FALSE);
00521 COUNT_NODE(NODE_ERRINFO);
00522 COUNT_NODE(NODE_DEFINED);
00523 COUNT_NODE(NODE_POSTEXE);
00524 COUNT_NODE(NODE_ALLOCA);
00525 COUNT_NODE(NODE_BMETHOD);
00526 COUNT_NODE(NODE_MEMO);
00527 COUNT_NODE(NODE_IFUNC);
00528 COUNT_NODE(NODE_DSYM);
00529 COUNT_NODE(NODE_ATTRASGN);
00530 COUNT_NODE(NODE_PRELUDE);
00531 COUNT_NODE(NODE_LAMBDA);
00532 COUNT_NODE(NODE_OPTBLOCK);
00533 #undef COUNT_NODE
00534 default: node = INT2FIX(i);
00535 }
00536 rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
00537 }
00538 }
00539 return hash;
00540 }
00541
00542 static int
00543 cto_i(void *vstart, void *vend, size_t stride, void *data)
00544 {
00545 VALUE hash = (VALUE)data;
00546 VALUE v = (VALUE)vstart;
00547
00548 for (; v != (VALUE)vend; v += stride) {
00549 if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_DATA) {
00550 VALUE counter;
00551 VALUE key = RBASIC(v)->klass;
00552
00553 if (key == 0) {
00554 const char *name = rb_objspace_data_type_name(v);
00555 if (name == 0) name = "unknown";
00556 key = ID2SYM(rb_intern(name));
00557 }
00558
00559 counter = rb_hash_aref(hash, key);
00560 if (NIL_P(counter)) {
00561 counter = INT2FIX(1);
00562 }
00563 else {
00564 counter = INT2FIX(FIX2INT(counter) + 1);
00565 }
00566
00567 rb_hash_aset(hash, key, counter);
00568 }
00569 }
00570
00571 return 0;
00572 }
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606 static VALUE
00607 count_tdata_objects(int argc, VALUE *argv, VALUE self)
00608 {
00609 VALUE hash;
00610
00611 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00612 if (TYPE(hash) != T_HASH)
00613 rb_raise(rb_eTypeError, "non-hash given");
00614 }
00615
00616 if (hash == Qnil) {
00617 hash = rb_hash_new();
00618 }
00619 else if (!RHASH_EMPTY_P(hash)) {
00620 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00621 }
00622
00623 rb_objspace_each_objects(cto_i, (void *)hash);
00624
00625 return hash;
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 void
00639 Init_objspace(void)
00640 {
00641 VALUE rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
00642
00643 rb_define_module_function(rb_mObjSpace, "memsize_of", memsize_of_m, 1);
00644 rb_define_module_function(rb_mObjSpace, "memsize_of_all",
00645 memsize_of_all_m, -1);
00646
00647 rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
00648 rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
00649 rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
00650 }
00651