allocation_tracer 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +34 -0
- data/ext/allocation_tracer/allocation_tracer.c +213 -72
- data/lib/allocation_tracer/version.rb +1 -1
- data/spec/allocation_tracer_spec.rb +39 -0
- metadata +2 -3
- data/lib/allocation_tracer/allocation_tracer.so +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: e21df296d813762ba6a5b3393ae95cbc09fa2560
         | 
| 4 | 
            +
              data.tar.gz: 089e3fcaa7df385f58c91a3762d1c1f714cbb50a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a9f98fcbbd4a1e7cac48aaab69e10e9857b63050ffb8ec7e9d8ef9800d9668cfb2715ec2414ed277276edaf3ca53527f1606ec589656b71ea972d33d4a3d8765
         | 
| 7 | 
            +
              data.tar.gz: 7d34cd7d37a60411664a82b94edb9b832cbe00a351c5b9b4da33adce9ee354b98f3f79d99ab594b6253675c1ffe4c6e3a3487052f4e7f7ba9ad586e823ff2f7d
         | 
    
        data/README.md
    CHANGED
    
    | @@ -151,6 +151,40 @@ test.rb 7       50000   41650   0       5 | |
| 151 151 |  | 
| 152 152 | 
             
            (tab separated colums)
         | 
| 153 153 |  | 
| 154 | 
            +
            ### Lifetime table
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            You can collect lifetime statistics with 
         | 
| 157 | 
            +
            ObjectSpace::AllocationTracer.lifetime_table method.
         | 
| 158 | 
            +
             | 
| 159 | 
            +
            ```ruby
         | 
| 160 | 
            +
            require 'pp'
         | 
| 161 | 
            +
            require 'allocation_tracer'
         | 
| 162 | 
            +
             | 
| 163 | 
            +
            ObjectSpace::AllocationTracer.lifetime_table_setup true
         | 
| 164 | 
            +
            result = ObjectSpace::AllocationTracer.trace do
         | 
| 165 | 
            +
              100000.times{
         | 
| 166 | 
            +
                Object.new
         | 
| 167 | 
            +
                ''
         | 
| 168 | 
            +
              }
         | 
| 169 | 
            +
            end
         | 
| 170 | 
            +
            pp ObjectSpace::AllocationTracer.lifetime_table
         | 
| 171 | 
            +
            ```
         | 
| 172 | 
            +
             | 
| 173 | 
            +
            will show
         | 
| 174 | 
            +
             | 
| 175 | 
            +
            ```
         | 
| 176 | 
            +
            {:T_OBJECT=>[3434, 96563, 0, 0, 1, 0, 0, 2],
         | 
| 177 | 
            +
             :T_STRING=>[3435, 96556, 2, 1, 1, 1, 1, 1, 2]}
         | 
| 178 | 
            +
            ```
         | 
| 179 | 
            +
             | 
| 180 | 
            +
            This output means that the age of 3434 T_OBJECT objects are 0, 96563 
         | 
| 181 | 
            +
            objects are 1 and 2 objects are 7. Also the age of 3435 T_STRING 
         | 
| 182 | 
            +
            objects are 0, 96556 are 1 and so on.
         | 
| 183 | 
            +
             | 
| 184 | 
            +
            Note that these number includes living objects and dead objects.  For 
         | 
| 185 | 
            +
            dead object, age means lifetime. For living objects, age means current 
         | 
| 186 | 
            +
            age.
         | 
| 187 | 
            +
             | 
| 154 188 | 
             
            ## Contributing
         | 
| 155 189 |  | 
| 156 190 | 
             
            1. Fork it ( http://github.com/<my-github-username>/allocation_tracer/fork )
         | 
| @@ -13,6 +13,19 @@ size_t rb_obj_memsize_of(VALUE obj); /* in gc.c */ | |
| 13 13 |  | 
| 14 14 | 
             
            static VALUE rb_mAllocationTracer;
         | 
| 15 15 |  | 
| 16 | 
            +
            struct traceobj_arg {
         | 
| 17 | 
            +
                int running;
         | 
| 18 | 
            +
                int keys, vals;
         | 
| 19 | 
            +
                st_table *object_table;     /* obj (VALUE)      -> allocation_info */
         | 
| 20 | 
            +
                st_table *str_table;        /* cstr             -> refcount */
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                st_table *aggregate_table;  /* user defined key -> [count, total_age, max_age, min_age] */
         | 
| 23 | 
            +
                struct allocation_info *freed_allocation_info;
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                /* */
         | 
| 26 | 
            +
                size_t **lifetime_table;
         | 
| 27 | 
            +
            };
         | 
| 28 | 
            +
             | 
| 16 29 | 
             
            struct allocation_info {
         | 
| 17 30 | 
             
                struct allocation_info *next;
         | 
| 18 31 |  | 
| @@ -44,15 +57,6 @@ struct allocation_info { | |
| 44 57 | 
             
            #define VAL_MAX_AGE   (1<<5)
         | 
| 45 58 | 
             
            #define VAL_MEMSIZE   (1<<6)
         | 
| 46 59 |  | 
| 47 | 
            -
            struct traceobj_arg {
         | 
| 48 | 
            -
                int running;
         | 
| 49 | 
            -
                int keys, vals;
         | 
| 50 | 
            -
                st_table *aggregate_table;  /* user defined key -> [count, total_age, max_age, min_age] */
         | 
| 51 | 
            -
                st_table *object_table;     /* obj (VALUE)      -> allocation_info */
         | 
| 52 | 
            -
                st_table *str_table;        /* cstr             -> refcount */
         | 
| 53 | 
            -
                struct allocation_info *freed_allocation_info;
         | 
| 54 | 
            -
            };
         | 
| 55 | 
            -
             | 
| 56 60 | 
             
            static char *
         | 
| 57 61 | 
             
            keep_unique_str(st_table *tbl, const char *str)
         | 
| 58 62 | 
             
            {
         | 
| @@ -145,6 +149,7 @@ get_traceobj_arg(void) | |
| 145 149 | 
             
            	tmp_trace_arg->object_table = st_init_numtable();
         | 
| 146 150 | 
             
            	tmp_trace_arg->str_table = st_init_strtable();
         | 
| 147 151 | 
             
            	tmp_trace_arg->freed_allocation_info = NULL;
         | 
| 152 | 
            +
            	tmp_trace_arg->lifetime_table = NULL;
         | 
| 148 153 | 
             
                }
         | 
| 149 154 | 
             
                return tmp_trace_arg;
         | 
| 150 155 | 
             
            }
         | 
| @@ -182,6 +187,17 @@ clear_traceobj_arg(void) | |
| 182 187 | 
             
                st_clear(arg->object_table);
         | 
| 183 188 | 
             
                st_foreach(arg->str_table, free_keys_i, 0);
         | 
| 184 189 | 
             
                st_clear(arg->str_table);
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                if (arg->lifetime_table) {
         | 
| 192 | 
            +
            	int i;
         | 
| 193 | 
            +
             | 
| 194 | 
            +
            	for (i=0; i<T_MASK; i++) {
         | 
| 195 | 
            +
            	    if (arg->lifetime_table[i] != NULL) {
         | 
| 196 | 
            +
            		free(arg->lifetime_table[i]);
         | 
| 197 | 
            +
            		arg->lifetime_table[i] = NULL;
         | 
| 198 | 
            +
            	    }
         | 
| 199 | 
            +
            	}
         | 
| 200 | 
            +
                }
         | 
| 185 201 | 
             
            }
         | 
| 186 202 |  | 
| 187 203 | 
             
            static struct allocation_info *
         | 
| @@ -261,7 +277,7 @@ aggregate_each_info(struct traceobj_arg *arg, struct allocation_info *info, size | |
| 261 277 | 
             
                key = (st_data_t)&key_data;
         | 
| 262 278 |  | 
| 263 279 | 
             
                if (st_lookup(arg->aggregate_table, key, &val) == 0) {
         | 
| 264 | 
            -
            	struct memcmp_key_data *key_buff = ruby_xmalloc(sizeof( | 
| 280 | 
            +
            	struct memcmp_key_data *key_buff = ruby_xmalloc(sizeof(struct memcmp_key_data));
         | 
| 265 281 | 
             
            	key_buff->n = key_data.n;
         | 
| 266 282 |  | 
| 267 283 | 
             
            	for (i=0; i<key_data.n; i++) {
         | 
| @@ -315,6 +331,34 @@ move_to_freed_list(struct traceobj_arg *arg, struct allocation_info *info) | |
| 315 331 | 
             
                arg->freed_allocation_info = info;
         | 
| 316 332 | 
             
            }
         | 
| 317 333 |  | 
| 334 | 
            +
            static void
         | 
| 335 | 
            +
            add_lifetime_table(size_t **lines, int type, struct allocation_info *info)
         | 
| 336 | 
            +
            {
         | 
| 337 | 
            +
                size_t age = rb_gc_count() - info->generation;
         | 
| 338 | 
            +
                size_t *line = lines[type];
         | 
| 339 | 
            +
                size_t len, i;
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                if (line == NULL) {
         | 
| 342 | 
            +
            	len = age + 1;
         | 
| 343 | 
            +
            	line = lines[type] = malloc(sizeof(size_t) * (1 + len));
         | 
| 344 | 
            +
            	line[0] = len;
         | 
| 345 | 
            +
            	for (i=0; i<len; i++) line[i+1] = 0;
         | 
| 346 | 
            +
                }
         | 
| 347 | 
            +
                else {
         | 
| 348 | 
            +
            	len = line[0];
         | 
| 349 | 
            +
             | 
| 350 | 
            +
            	if (len < age + 1) {
         | 
| 351 | 
            +
            	    size_t old_len = len;
         | 
| 352 | 
            +
            	    len = age + 1;
         | 
| 353 | 
            +
            	    line = lines[type] = realloc(line, sizeof(size_t) * (1 + len));
         | 
| 354 | 
            +
            	    for (i=old_len; i<len; i++) line[i+1] = 0;
         | 
| 355 | 
            +
            	    line[0] = len;
         | 
| 356 | 
            +
            	}
         | 
| 357 | 
            +
                }
         | 
| 358 | 
            +
             | 
| 359 | 
            +
                line[age + 1]++;
         | 
| 360 | 
            +
            }
         | 
| 361 | 
            +
             | 
| 318 362 | 
             
            static void
         | 
| 319 363 | 
             
            freeobj_i(VALUE tpval, void *data)
         | 
| 320 364 | 
             
            {
         | 
| @@ -331,6 +375,20 @@ freeobj_i(VALUE tpval, void *data) | |
| 331 375 | 
             
            	if (arg->freed_allocation_info == NULL) {
         | 
| 332 376 | 
             
            	    rb_postponed_job_register_one(0, aggregate_freed_info, arg);
         | 
| 333 377 | 
             
            	}
         | 
| 378 | 
            +
             | 
| 379 | 
            +
            	if (arg->lifetime_table) {
         | 
| 380 | 
            +
            	    add_lifetime_table(arg->lifetime_table, BUILTIN_TYPE(obj), info);
         | 
| 381 | 
            +
            	}
         | 
| 382 | 
            +
                }
         | 
| 383 | 
            +
            }
         | 
| 384 | 
            +
             | 
| 385 | 
            +
            static void
         | 
| 386 | 
            +
            check_tracer_running(void)
         | 
| 387 | 
            +
            {
         | 
| 388 | 
            +
                struct traceobj_arg * arg = get_traceobj_arg();
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                if (!arg->running) {
         | 
| 391 | 
            +
            	rb_raise(rb_eRuntimeError, "not started yet");
         | 
| 334 392 | 
             
                }
         | 
| 335 393 | 
             
            }
         | 
| 336 394 |  | 
| @@ -339,6 +397,8 @@ enable_newobj_hook(void) | |
| 339 397 | 
             
            {
         | 
| 340 398 | 
             
                VALUE newobj_hook;
         | 
| 341 399 |  | 
| 400 | 
            +
                check_tracer_running();
         | 
| 401 | 
            +
             | 
| 342 402 | 
             
                if ((newobj_hook = rb_ivar_get(rb_mAllocationTracer, rb_intern("newobj_hook"))) == Qnil) {
         | 
| 343 403 | 
             
            	rb_raise(rb_eRuntimeError, "not started.");
         | 
| 344 404 | 
             
                }
         | 
| @@ -354,6 +414,8 @@ disable_newobj_hook(void) | |
| 354 414 | 
             
            {
         | 
| 355 415 | 
             
                VALUE newobj_hook;
         | 
| 356 416 |  | 
| 417 | 
            +
                check_tracer_running();
         | 
| 418 | 
            +
             | 
| 357 419 | 
             
                if ((newobj_hook = rb_ivar_get(rb_mAllocationTracer, rb_intern("newobj_hook"))) == Qnil) {
         | 
| 358 420 | 
             
            	rb_raise(rb_eRuntimeError, "not started.");
         | 
| 359 421 | 
             
                }
         | 
| @@ -364,16 +426,6 @@ disable_newobj_hook(void) | |
| 364 426 | 
             
                rb_tracepoint_disable(newobj_hook);
         | 
| 365 427 | 
             
            }
         | 
| 366 428 |  | 
| 367 | 
            -
            static void
         | 
| 368 | 
            -
            check_tracer_running(void)
         | 
| 369 | 
            -
            {
         | 
| 370 | 
            -
                struct traceobj_arg * arg = get_traceobj_arg();
         | 
| 371 | 
            -
             | 
| 372 | 
            -
                if (!arg->running) {
         | 
| 373 | 
            -
            	rb_raise(rb_eRuntimeError, "not started yet");
         | 
| 374 | 
            -
                }
         | 
| 375 | 
            -
            }
         | 
| 376 | 
            -
             | 
| 377 429 | 
             
            static void
         | 
| 378 430 | 
             
            start_alloc_hooks(VALUE mod)
         | 
| 379 431 | 
             
            {
         | 
| @@ -412,39 +464,49 @@ stop_alloc_hooks(VALUE self) | |
| 412 464 | 
             
                return Qnil;
         | 
| 413 465 | 
             
            }
         | 
| 414 466 |  | 
| 415 | 
            -
            static  | 
| 416 | 
            -
             | 
| 417 | 
            -
            {
         | 
| 418 | 
            -
                 | 
| 419 | 
            -
             | 
| 420 | 
            -
             | 
| 421 | 
            -
            	 | 
| 422 | 
            -
            	 | 
| 423 | 
            -
             | 
| 424 | 
            -
             | 
| 425 | 
            -
             | 
| 426 | 
            -
             | 
| 427 | 
            -
             | 
| 428 | 
            -
             | 
| 429 | 
            -
             | 
| 430 | 
            -
             | 
| 431 | 
            -
             | 
| 432 | 
            -
             | 
| 433 | 
            -
             | 
| 434 | 
            -
             | 
| 435 | 
            -
             | 
| 436 | 
            -
             | 
| 437 | 
            -
             | 
| 438 | 
            -
             | 
| 439 | 
            -
             | 
| 440 | 
            -
             | 
| 441 | 
            -
             | 
| 442 | 
            -
             | 
| 443 | 
            -
             | 
| 444 | 
            -
             | 
| 467 | 
            +
            static VALUE
         | 
| 468 | 
            +
            type_sym(int type)
         | 
| 469 | 
            +
            {
         | 
| 470 | 
            +
                static VALUE syms[T_MASK];
         | 
| 471 | 
            +
             | 
| 472 | 
            +
                if (syms[0] == 0) {
         | 
| 473 | 
            +
            	int i;
         | 
| 474 | 
            +
            	for (i=0; i<T_MASK; i++) {
         | 
| 475 | 
            +
            	    switch (i) {
         | 
| 476 | 
            +
            #define TYPE_NAME(t) case (t): syms[i] = ID2SYM(rb_intern(#t)); break;
         | 
| 477 | 
            +
            		TYPE_NAME(T_NONE);
         | 
| 478 | 
            +
            		TYPE_NAME(T_OBJECT);
         | 
| 479 | 
            +
            		TYPE_NAME(T_CLASS);
         | 
| 480 | 
            +
            		TYPE_NAME(T_MODULE);
         | 
| 481 | 
            +
            		TYPE_NAME(T_FLOAT);
         | 
| 482 | 
            +
            		TYPE_NAME(T_STRING);
         | 
| 483 | 
            +
            		TYPE_NAME(T_REGEXP);
         | 
| 484 | 
            +
            		TYPE_NAME(T_ARRAY);
         | 
| 485 | 
            +
            		TYPE_NAME(T_HASH);
         | 
| 486 | 
            +
            		TYPE_NAME(T_STRUCT);
         | 
| 487 | 
            +
            		TYPE_NAME(T_BIGNUM);
         | 
| 488 | 
            +
            		TYPE_NAME(T_FILE);
         | 
| 489 | 
            +
            		TYPE_NAME(T_MATCH);
         | 
| 490 | 
            +
            		TYPE_NAME(T_COMPLEX);
         | 
| 491 | 
            +
            		TYPE_NAME(T_RATIONAL);
         | 
| 492 | 
            +
            		TYPE_NAME(T_NIL);
         | 
| 493 | 
            +
            		TYPE_NAME(T_TRUE);
         | 
| 494 | 
            +
            		TYPE_NAME(T_FALSE);
         | 
| 495 | 
            +
            		TYPE_NAME(T_SYMBOL);
         | 
| 496 | 
            +
            		TYPE_NAME(T_FIXNUM);
         | 
| 497 | 
            +
            		TYPE_NAME(T_UNDEF);
         | 
| 498 | 
            +
            		TYPE_NAME(T_NODE);
         | 
| 499 | 
            +
            		TYPE_NAME(T_ICLASS);
         | 
| 500 | 
            +
            		TYPE_NAME(T_ZOMBIE);
         | 
| 501 | 
            +
            		TYPE_NAME(T_DATA);
         | 
| 502 | 
            +
            	      default:
         | 
| 503 | 
            +
            		syms[i] = ID2SYM(rb_intern("unknown"));
         | 
| 445 504 | 
             
            #undef TYPE_NAME
         | 
| 505 | 
            +
            	    }
         | 
| 506 | 
            +
            	}
         | 
| 446 507 | 
             
                }
         | 
| 447 | 
            -
             | 
| 508 | 
            +
             | 
| 509 | 
            +
                return syms[type];
         | 
| 448 510 | 
             
            }
         | 
| 449 511 |  | 
| 450 512 | 
             
            struct arg_and_result {
         | 
| @@ -467,14 +529,6 @@ aggregate_result_i(st_data_t key, st_data_t val, void *data) | |
| 467 529 | 
             
            			  INT2FIX(val_buff[4]), INT2FIX(val_buff[5]));
         | 
| 468 530 | 
             
                VALUE k = rb_ary_new();
         | 
| 469 531 | 
             
                int i = 0;
         | 
| 470 | 
            -
                static VALUE type_symbols[T_MASK] = {0};
         | 
| 471 | 
            -
             | 
| 472 | 
            -
                if (type_symbols[0] == 0) {
         | 
| 473 | 
            -
            	int i;
         | 
| 474 | 
            -
            	for (i=0; i<T_MASK; i++) {
         | 
| 475 | 
            -
            	    type_symbols[i] = ID2SYM(rb_intern(type_name(i)));
         | 
| 476 | 
            -
            	}
         | 
| 477 | 
            -
                }
         | 
| 478 532 |  | 
| 479 533 | 
             
                i = 0;
         | 
| 480 534 | 
             
                if (arg->keys & KEY_PATH) {
         | 
| @@ -493,7 +547,7 @@ aggregate_result_i(st_data_t key, st_data_t val, void *data) | |
| 493 547 | 
             
                if (arg->keys & KEY_TYPE) {
         | 
| 494 548 | 
             
            	int sym_index = key_buff->data[i++];
         | 
| 495 549 | 
             
            	assert(T_MASK > sym_index);
         | 
| 496 | 
            -
            	rb_ary_push(k,  | 
| 550 | 
            +
            	rb_ary_push(k, type_sym(sym_index));
         | 
| 497 551 | 
             
                }
         | 
| 498 552 | 
             
                if (arg->keys & KEY_CLASS) {
         | 
| 499 553 | 
             
            	VALUE klass = key_buff->data[i++];
         | 
| @@ -532,6 +586,32 @@ aggregate_live_object_i(st_data_t key, st_data_t val, void *data) | |
| 532 586 | 
             
                return ST_CONTINUE;
         | 
| 533 587 | 
             
            }
         | 
| 534 588 |  | 
| 589 | 
            +
            static int
         | 
| 590 | 
            +
            lifetime_table_for_live_objects_i(st_data_t key, st_data_t val, st_data_t data)
         | 
| 591 | 
            +
            {
         | 
| 592 | 
            +
                struct allocation_info *info = (struct allocation_info *)val;
         | 
| 593 | 
            +
                VALUE h = (VALUE)data;
         | 
| 594 | 
            +
                int type = info->flags & T_MASK;
         | 
| 595 | 
            +
                VALUE sym = type_sym(type);
         | 
| 596 | 
            +
                size_t age = rb_gc_count() - info->generation;
         | 
| 597 | 
            +
                VALUE line;
         | 
| 598 | 
            +
                size_t count, i;
         | 
| 599 | 
            +
             | 
| 600 | 
            +
                if ((line = rb_hash_aref(h, sym)) == Qnil) {
         | 
| 601 | 
            +
            	line = rb_ary_new();
         | 
| 602 | 
            +
            	rb_hash_aset(h, sym, line);
         | 
| 603 | 
            +
                }
         | 
| 604 | 
            +
             | 
| 605 | 
            +
                for (i=RARRAY_LEN(line); i<age+1; i++) {
         | 
| 606 | 
            +
            	rb_ary_push(line, INT2FIX(0));
         | 
| 607 | 
            +
                }
         | 
| 608 | 
            +
             | 
| 609 | 
            +
                count = NUM2SIZET(RARRAY_AREF(line, age));
         | 
| 610 | 
            +
                RARRAY_ASET(line, age, SIZET2NUM(count + 1));
         | 
| 611 | 
            +
             | 
| 612 | 
            +
                return ST_CONTINUE;
         | 
| 613 | 
            +
            }
         | 
| 614 | 
            +
             | 
| 535 615 | 
             
            static VALUE
         | 
| 536 616 | 
             
            aggregate_result(struct traceobj_arg *arg)
         | 
| 537 617 | 
             
            {
         | 
| @@ -560,15 +640,33 @@ aggregate_result(struct traceobj_arg *arg) | |
| 560 640 |  | 
| 561 641 | 
             
            	arg->aggregate_table = dead_object_aggregate_table;
         | 
| 562 642 | 
             
                }
         | 
| 563 | 
            -
                return aar.result;
         | 
| 564 | 
            -
            }
         | 
| 565 643 |  | 
| 566 | 
            -
             | 
| 567 | 
            -
             | 
| 568 | 
            -
             | 
| 569 | 
            -
             | 
| 570 | 
            -
             | 
| 571 | 
            -
             | 
| 644 | 
            +
                /* lifetime table */
         | 
| 645 | 
            +
                if (arg->lifetime_table) {
         | 
| 646 | 
            +
            	VALUE h = rb_hash_new();
         | 
| 647 | 
            +
            	int i;
         | 
| 648 | 
            +
             | 
| 649 | 
            +
            	for (i=0; i<T_MASK; i++) {
         | 
| 650 | 
            +
            	    size_t *line = arg->lifetime_table[i];
         | 
| 651 | 
            +
             | 
| 652 | 
            +
            	    if (line) {
         | 
| 653 | 
            +
            		size_t len = line[0], j;
         | 
| 654 | 
            +
            		VALUE ary = rb_ary_new();
         | 
| 655 | 
            +
            		VALUE sym = type_sym(i);
         | 
| 656 | 
            +
             | 
| 657 | 
            +
            		for (j=0; j<len; j++) {
         | 
| 658 | 
            +
            		    rb_ary_push(ary, SIZET2NUM(line[j+1]));
         | 
| 659 | 
            +
            		}
         | 
| 660 | 
            +
             | 
| 661 | 
            +
            		rb_hash_aset(h, sym, ary);
         | 
| 662 | 
            +
            	    }
         | 
| 663 | 
            +
            	}
         | 
| 664 | 
            +
             | 
| 665 | 
            +
            	st_foreach(arg->object_table, lifetime_table_for_live_objects_i, (st_data_t)h);
         | 
| 666 | 
            +
            	rb_ivar_set(rb_mAllocationTracer, rb_intern("lifetime_table"), h);
         | 
| 667 | 
            +
                }
         | 
| 668 | 
            +
             | 
| 669 | 
            +
                return aar.result;
         | 
| 572 670 | 
             
            }
         | 
| 573 671 |  | 
| 574 672 | 
             
            static VALUE
         | 
| @@ -577,8 +675,6 @@ allocation_tracer_result(VALUE self) | |
| 577 675 | 
             
                VALUE result;
         | 
| 578 676 | 
             
                struct traceobj_arg *arg = get_traceobj_arg();
         | 
| 579 677 |  | 
| 580 | 
            -
                check_tracer_running();
         | 
| 581 | 
            -
             | 
| 582 678 | 
             
                disable_newobj_hook();
         | 
| 583 679 | 
             
                result = aggregate_result(arg);
         | 
| 584 680 | 
             
                enable_newobj_hook();
         | 
| @@ -620,10 +716,20 @@ allocation_tracer_trace(VALUE self) | |
| 620 716 | 
             
                return Qnil;
         | 
| 621 717 | 
             
            }
         | 
| 622 718 |  | 
| 719 | 
            +
            static VALUE
         | 
| 720 | 
            +
            allocation_tracer_stop(VALUE self)
         | 
| 721 | 
            +
            {
         | 
| 722 | 
            +
                VALUE result;
         | 
| 723 | 
            +
             | 
| 724 | 
            +
                disable_newobj_hook();
         | 
| 725 | 
            +
                result = aggregate_result(get_traceobj_arg());
         | 
| 726 | 
            +
                stop_alloc_hooks(self);
         | 
| 727 | 
            +
                return result;
         | 
| 728 | 
            +
            }
         | 
| 729 | 
            +
             | 
| 623 730 | 
             
            static VALUE
         | 
| 624 731 | 
             
            allocation_tracer_pause(VALUE self)
         | 
| 625 732 | 
             
            {
         | 
| 626 | 
            -
                check_tracer_running();
         | 
| 627 733 | 
             
                disable_newobj_hook();
         | 
| 628 734 | 
             
                return Qnil;
         | 
| 629 735 | 
             
            }
         | 
| @@ -631,7 +737,6 @@ allocation_tracer_pause(VALUE self) | |
| 631 737 | 
             
            static VALUE
         | 
| 632 738 | 
             
            allocation_tracer_resume(VALUE self)
         | 
| 633 739 | 
             
            {
         | 
| 634 | 
            -
                check_tracer_running();
         | 
| 635 740 | 
             
                enable_newobj_hook();
         | 
| 636 741 | 
             
                return Qnil;
         | 
| 637 742 | 
             
            }
         | 
| @@ -689,6 +794,39 @@ allocation_tracer_header(VALUE self) | |
| 689 794 | 
             
                return ary;
         | 
| 690 795 | 
             
            }
         | 
| 691 796 |  | 
| 797 | 
            +
            static VALUE
         | 
| 798 | 
            +
            allocation_tracer_lifetime_table_setup(VALUE self, VALUE set)
         | 
| 799 | 
            +
            {
         | 
| 800 | 
            +
                struct traceobj_arg * arg = get_traceobj_arg();
         | 
| 801 | 
            +
             | 
| 802 | 
            +
                if (arg->running) {
         | 
| 803 | 
            +
            	rb_raise(rb_eRuntimeError, "can't change configuration during running");
         | 
| 804 | 
            +
                }
         | 
| 805 | 
            +
             | 
| 806 | 
            +
                if (RTEST(set)) {
         | 
| 807 | 
            +
            	if (arg->lifetime_table == NULL) {
         | 
| 808 | 
            +
            	    arg->lifetime_table = (size_t **)calloc(sizeof(size_t **), T_MASK);
         | 
| 809 | 
            +
            	    
         | 
| 810 | 
            +
            	}
         | 
| 811 | 
            +
                }
         | 
| 812 | 
            +
                else {
         | 
| 813 | 
            +
            	if (arg->lifetime_table != NULL) {
         | 
| 814 | 
            +
            	    free(arg->lifetime_table);
         | 
| 815 | 
            +
            	    arg->lifetime_table = NULL;
         | 
| 816 | 
            +
            	}
         | 
| 817 | 
            +
                }
         | 
| 818 | 
            +
             | 
| 819 | 
            +
                return Qnil;
         | 
| 820 | 
            +
            }
         | 
| 821 | 
            +
             | 
| 822 | 
            +
            static VALUE
         | 
| 823 | 
            +
            allocation_tracer_lifetime_table(VALUE self)
         | 
| 824 | 
            +
            {
         | 
| 825 | 
            +
                VALUE result = rb_ivar_get(rb_mAllocationTracer, rb_intern("lifetime_table"));
         | 
| 826 | 
            +
                rb_ivar_set(rb_mAllocationTracer, rb_intern("lifetime_table"), Qnil);
         | 
| 827 | 
            +
                return result;
         | 
| 828 | 
            +
            }
         | 
| 829 | 
            +
             | 
| 692 830 | 
             
            void
         | 
| 693 831 | 
             
            Init_allocation_tracer(void)
         | 
| 694 832 | 
             
            {
         | 
| @@ -706,4 +844,7 @@ Init_allocation_tracer(void) | |
| 706 844 | 
             
                rb_define_module_function(mod, "clear", allocation_tracer_clear, 0);
         | 
| 707 845 | 
             
                rb_define_module_function(mod, "setup", allocation_tracer_setup, -1);
         | 
| 708 846 | 
             
                rb_define_module_function(mod, "header", allocation_tracer_header, 0);
         | 
| 847 | 
            +
             | 
| 848 | 
            +
                rb_define_module_function(mod, "lifetime_table_setup", allocation_tracer_lifetime_table_setup, 1);
         | 
| 849 | 
            +
                rb_define_module_function(mod, "lifetime_table", allocation_tracer_lifetime_table, 0);
         | 
| 709 850 | 
             
            }
         | 
| @@ -164,4 +164,43 @@ describe ObjectSpace::AllocationTracer do | |
| 164 164 | 
             
                  end
         | 
| 165 165 | 
             
                end
         | 
| 166 166 | 
             
              end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
              describe 'collect lifetime_table' do
         | 
| 169 | 
            +
                before do
         | 
| 170 | 
            +
                  ObjectSpace::AllocationTracer.lifetime_table_setup true
         | 
| 171 | 
            +
                end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                after do
         | 
| 174 | 
            +
                  ObjectSpace::AllocationTracer.lifetime_table_setup false
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                it 'should make lifetime table' do
         | 
| 178 | 
            +
                  ObjectSpace::AllocationTracer.trace do
         | 
| 179 | 
            +
                    100000.times{
         | 
| 180 | 
            +
                      Object.new
         | 
| 181 | 
            +
                      ''
         | 
| 182 | 
            +
                    }
         | 
| 183 | 
            +
                  end
         | 
| 184 | 
            +
                  table = ObjectSpace::AllocationTracer.lifetime_table
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                  expect(table[:T_OBJECT].inject(&:+)).to be >= 10_000
         | 
| 187 | 
            +
                  expect(table[:T_STRING].inject(&:+)).to be >= 10_000
         | 
| 188 | 
            +
                  expect(table[:T_NONE]).to be nil
         | 
| 189 | 
            +
                end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                it 'should nil when ObjectSpace::AllocationTracer.lifetime_table_setup is nil' do
         | 
| 192 | 
            +
                  ObjectSpace::AllocationTracer.lifetime_table_setup false
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                  ObjectSpace::AllocationTracer.trace do
         | 
| 195 | 
            +
                    100000.times{
         | 
| 196 | 
            +
                      Object.new
         | 
| 197 | 
            +
                      ''
         | 
| 198 | 
            +
                    }
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                  table = ObjectSpace::AllocationTracer.lifetime_table
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                  expect(table).to be nil
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
              end
         | 
| 167 206 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: allocation_tracer
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Koichi Sasada
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2014-04- | 
| 11 | 
            +
            date: 2014-04-23 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -84,7 +84,6 @@ files: | |
| 84 84 | 
             
            - ext/allocation_tracer/allocation_tracer.c
         | 
| 85 85 | 
             
            - ext/allocation_tracer/extconf.rb
         | 
| 86 86 | 
             
            - lib/allocation_tracer.rb
         | 
| 87 | 
            -
            - lib/allocation_tracer/allocation_tracer.so
         | 
| 88 87 | 
             
            - lib/allocation_tracer/trace.rb
         | 
| 89 88 | 
             
            - lib/allocation_tracer/version.rb
         | 
| 90 89 | 
             
            - spec/allocation_tracer_spec.rb
         | 
| Binary file |