railsbench 0.9.2 → 0.9.8
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.
- data/CHANGELOG +1808 -451
- data/GCPATCH +73 -0
- data/INSTALL +5 -0
- data/Manifest.txt +23 -13
- data/PROBLEMS +0 -0
- data/README +23 -7
- data/Rakefile +1 -2
- data/bin/railsbench +7 -1
- data/config/benchmarking.rb +0 -0
- data/config/benchmarks.rb +3 -2
- data/config/benchmarks.yml +0 -0
- data/images/empty.png +0 -0
- data/images/minus.png +0 -0
- data/images/plus.png +0 -0
- data/install.rb +1 -1
- data/latest_changes.txt +18 -0
- data/lib/benchmark.rb +0 -0
- data/lib/railsbench/benchmark.rb +576 -0
- data/lib/railsbench/benchmark_specs.rb +63 -63
- data/lib/railsbench/gc_info.rb +38 -3
- data/lib/railsbench/perf_info.rb +1 -1
- data/lib/railsbench/perf_utils.rb +202 -179
- data/lib/railsbench/railsbenchmark.rb +213 -55
- data/lib/railsbench/version.rb +9 -9
- data/lib/railsbench/write_headers_only.rb +15 -15
- data/postinstall.rb +0 -0
- data/ruby185gc.patch +56 -29
- data/ruby186gc.patch +564 -0
- data/ruby19gc.patch +2425 -0
- data/script/convert_raw_data_files +49 -49
- data/script/generate_benchmarks +14 -4
- data/script/perf_bench +12 -8
- data/script/perf_comp +1 -1
- data/script/perf_comp_gc +9 -1
- data/script/perf_diff +2 -2
- data/script/perf_diff_gc +2 -2
- data/script/perf_html +1 -1
- data/script/perf_plot +192 -75
- data/script/perf_plot_gc +213 -74
- data/script/perf_prof +29 -10
- data/script/perf_run +2 -2
- data/script/perf_run_gc +2 -2
- data/script/perf_table +2 -2
- data/script/perf_tex +1 -1
- data/script/perf_times +6 -6
- data/script/perf_times_gc +14 -2
- data/script/run_urls +16 -10
- data/setup.rb +0 -0
- data/test/railsbench_test.rb +0 -0
- data/test/test_helper.rb +2 -0
- metadata +77 -55
| @@ -1,15 +1,15 @@ | |
| 1 | 
            -
            class ActionController::CgiResponse
         | 
| 2 | 
            -
              # on windows it is sometimes necessary to turn off writing output
         | 
| 3 | 
            -
              # to avoid out of memory errors running under the console
         | 
| 4 | 
            -
              def out(output = $stdout)
         | 
| 5 | 
            -
                convert_content_type!(@headers)
         | 
| 6 | 
            -
                output.binmode      if output.respond_to?(:binmode)
         | 
| 7 | 
            -
                output.sync = false if output.respond_to?(:sync=)
         | 
| 8 | 
            -
                begin
         | 
| 9 | 
            -
                  output.write(@cgi.header(@headers))
         | 
| 10 | 
            -
                  output.flush if output.respond_to?(:flush)
         | 
| 11 | 
            -
                rescue Errno::EPIPE => e
         | 
| 12 | 
            -
                  # lost connection to the FCGI process -- ignore the output, then
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
              end
         | 
| 15 | 
            -
            end
         | 
| 1 | 
            +
            class ActionController::CgiResponse
         | 
| 2 | 
            +
              # on windows it is sometimes necessary to turn off writing output
         | 
| 3 | 
            +
              # to avoid out of memory errors running under the console
         | 
| 4 | 
            +
              def out(output = $stdout)
         | 
| 5 | 
            +
                convert_content_type!(@headers)
         | 
| 6 | 
            +
                output.binmode      if output.respond_to?(:binmode)
         | 
| 7 | 
            +
                output.sync = false if output.respond_to?(:sync=)
         | 
| 8 | 
            +
                begin
         | 
| 9 | 
            +
                  output.write(@cgi.header(@headers))
         | 
| 10 | 
            +
                  output.flush if output.respond_to?(:flush)
         | 
| 11 | 
            +
                rescue Errno::EPIPE => e
         | 
| 12 | 
            +
                  # lost connection to the FCGI process -- ignore the output, then
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
    
        data/postinstall.rb
    CHANGED
    
    | 
            File without changes
         | 
    
        data/ruby185gc.patch
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            --- gc.c.orig	2006- | 
| 2 | 
            -
            +++ gc.c	 | 
| 1 | 
            +
            --- gc.c.orig	2006-08-25 10:12:46.000000000 +0200
         | 
| 2 | 
            +
            +++ gc.c	2007-05-06 10:55:19.000000000 +0200
         | 
| 3 3 | 
             
            @@ -22,8 +22,16 @@
         | 
| 4 4 | 
             
             #include <setjmp.h>
         | 
| 5 5 | 
             
             #include <sys/types.h>
         | 
| @@ -17,7 +17,7 @@ | |
| 17 17 | 
             
             #endif
         | 
| 18 18 |  | 
| 19 19 | 
             
             #ifdef HAVE_SYS_RESOURCE_H
         | 
| 20 | 
            -
            @@ - | 
| 20 | 
            +
            @@ -54,7 +62,6 @@
         | 
| 21 21 | 
             
             #if !defined(setjmp) && defined(HAVE__SETJMP)
         | 
| 22 22 | 
             
             #define setjmp(env) _setjmp(env)
         | 
| 23 23 | 
             
             #endif
         | 
| @@ -25,7 +25,7 @@ | |
| 25 25 | 
             
             /* Make alloca work the best possible way.  */
         | 
| 26 26 | 
             
             #ifdef __GNUC__
         | 
| 27 27 | 
             
             # ifndef atarist
         | 
| 28 | 
            -
            @@ - | 
| 28 | 
            +
            @@ -173,8 +180,17 @@
         | 
| 29 29 | 
             
             	RUBY_CRITICAL(free(x));
         | 
| 30 30 | 
             
             }
         | 
| 31 31 |  | 
| @@ -43,7 +43,7 @@ | |
| 43 43 | 
             
             static int during_gc;
         | 
| 44 44 | 
             
             static int need_call_final = 0;
         | 
| 45 45 | 
             
             static st_table *finalizer_table = 0;
         | 
| 46 | 
            -
            @@ - | 
| 46 | 
            +
            @@ -209,7 +225,7 @@
         | 
| 47 47 | 
             
              *  Disables garbage collection, returning <code>true</code> if garbage
         | 
| 48 48 | 
             
              *  collection was already disabled.
         | 
| 49 49 | 
             
              *
         | 
| @@ -52,7 +52,7 @@ | |
| 52 52 | 
             
              *     GC.disable   #=> true
         | 
| 53 53 | 
             
              *
         | 
| 54 54 | 
             
              */
         | 
| 55 | 
            -
            @@ - | 
| 55 | 
            +
            @@ -223,6 +239,104 @@
         | 
| 56 56 | 
             
                 return old;
         | 
| 57 57 | 
             
             }
         | 
| 58 58 |  | 
| @@ -157,7 +157,7 @@ | |
| 157 157 | 
             
             VALUE rb_mGC;
         | 
| 158 158 |  | 
| 159 159 | 
             
             static struct gc_list {
         | 
| 160 | 
            -
            @@ - | 
| 160 | 
            +
            @@ -314,7 +428,7 @@
         | 
| 161 161 | 
             
             static RVALUE *freelist = 0;
         | 
| 162 162 | 
             
             static RVALUE *deferred_final_list = 0;
         | 
| 163 163 |  | 
| @@ -166,7 +166,7 @@ | |
| 166 166 | 
             
             static struct heaps_slot {
         | 
| 167 167 | 
             
                 void *membase;
         | 
| 168 168 | 
             
                 RVALUE *slot;
         | 
| 169 | 
            -
            @@ - | 
| 169 | 
            +
            @@ -323,13 +437,165 @@
         | 
| 170 170 | 
             
             static int heaps_length = 0;
         | 
| 171 171 | 
             
             static int heaps_used   = 0;
         | 
| 172 172 |  | 
| @@ -176,6 +176,8 @@ | |
| 176 176 | 
             
            +static int heap_slots = 10000;
         | 
| 177 177 | 
             
            +
         | 
| 178 178 | 
             
            +static int heap_free_min = 4096;
         | 
| 179 | 
            +
            +static int heap_slots_increment = 10000;
         | 
| 180 | 
            +
            +static double heap_slots_growth_factor = 1.8;
         | 
| 179 181 | 
             
            +
         | 
| 180 182 | 
             
            +static long initial_malloc_limit = GC_MALLOC_LIMIT;
         | 
| 181 183 |  | 
| @@ -188,11 +190,11 @@ | |
| 188 190 |  | 
| 189 191 | 
             
            +static void set_gc_parameters()
         | 
| 190 192 | 
             
            +{
         | 
| 191 | 
            -
            +    char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr,
         | 
| 192 | 
            -
            + | 
| 193 | 
            +
            +    char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr,
         | 
| 194 | 
            +
            +      *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr;
         | 
| 193 195 | 
             
            +
         | 
| 194 196 | 
             
            +    gc_data_file = stderr;
         | 
| 195 | 
            -
            + | 
| 197 | 
            +
            +
         | 
| 196 198 | 
             
            +    gc_stats_ptr = getenv("RUBY_GC_STATS");
         | 
| 197 199 | 
             
            +    if (gc_stats_ptr != NULL) {
         | 
| 198 200 | 
             
            +	int gc_stats_i = atoi(gc_stats_ptr);
         | 
| @@ -200,10 +202,10 @@ | |
| 200 202 | 
             
            +	    verbose_gc_stats = Qtrue;
         | 
| 201 203 | 
             
            +	}
         | 
| 202 204 | 
             
            +    }
         | 
| 203 | 
            -
            + | 
| 205 | 
            +
            +
         | 
| 204 206 | 
             
            +    gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE");
         | 
| 205 207 | 
             
            +    if (gc_heap_file_ptr != NULL) {
         | 
| 206 | 
            -
            +	FILE* data_file = fopen(gc_heap_file_ptr, "w"); | 
| 208 | 
            +
            +	FILE* data_file = fopen(gc_heap_file_ptr, "w");
         | 
| 207 209 | 
             
            +	if (data_file != NULL) {
         | 
| 208 210 | 
             
            +	    gc_data_file = data_file;
         | 
| 209 211 | 
             
            +	}
         | 
| @@ -247,6 +249,28 @@ | |
| 247 249 | 
             
            +	}
         | 
| 248 250 | 
             
            +    }
         | 
| 249 251 | 
             
            +
         | 
| 252 | 
            +
            +    heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT");
         | 
| 253 | 
            +
            +    if (heap_slots_incr_ptr != NULL) {
         | 
| 254 | 
            +
            +	int heap_slots_incr_i = atoi(heap_slots_incr_ptr);
         | 
| 255 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 256 | 
            +
            +	    fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr);
         | 
| 257 | 
            +
            +	}
         | 
| 258 | 
            +
            +	if (heap_slots_incr_i > 0) {
         | 
| 259 | 
            +
            +	    heap_slots_increment = heap_slots_incr_i;
         | 
| 260 | 
            +
            +	}
         | 
| 261 | 
            +
            +    }
         | 
| 262 | 
            +
            +
         | 
| 263 | 
            +
            +    heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR");
         | 
| 264 | 
            +
            +    if (heap_slots_growth_factor_ptr != NULL) {
         | 
| 265 | 
            +
            +	double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr);
         | 
| 266 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 267 | 
            +
            +	    fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr);
         | 
| 268 | 
            +
            +	}
         | 
| 269 | 
            +
            +	if (heap_slots_growth_factor_d > 0) {
         | 
| 270 | 
            +
            +	    heap_slots_growth_factor = heap_slots_growth_factor_d;
         | 
| 271 | 
            +
            +	}
         | 
| 272 | 
            +
            +    }
         | 
| 273 | 
            +
            +
         | 
| 250 274 | 
             
            +    malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
         | 
| 251 275 | 
             
            +    if (malloc_limit_ptr != NULL) {
         | 
| 252 276 | 
             
            +	int malloc_limit_i = atol(malloc_limit_ptr);
         | 
| @@ -311,7 +335,7 @@ | |
| 311 335 | 
             
             static void
         | 
| 312 336 | 
             
             add_heap()
         | 
| 313 337 | 
             
             {
         | 
| 314 | 
            -
            @@ - | 
| 338 | 
            +
            @@ -340,7 +606,7 @@
         | 
| 315 339 | 
             
             	struct heaps_slot *p;
         | 
| 316 340 | 
             
             	int length;
         | 
| 317 341 |  | 
| @@ -320,7 +344,7 @@ | |
| 320 344 | 
             
             	length = heaps_length*sizeof(struct heaps_slot);
         | 
| 321 345 | 
             
             	RUBY_CRITICAL(
         | 
| 322 346 | 
             
             	    if (heaps_used > 0) {
         | 
| 323 | 
            -
            @@ - | 
| 347 | 
            +
            @@ -356,10 +622,10 @@
         | 
| 324 348 | 
             
                 for (;;) {
         | 
| 325 349 | 
             
             	RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
         | 
| 326 350 | 
             
             	if (p == 0) {
         | 
| @@ -333,16 +357,19 @@ | |
| 333 357 | 
             
             	    continue;
         | 
| 334 358 | 
             
             	}
         | 
| 335 359 | 
             
                     heaps[heaps_used].membase = p;
         | 
| 336 | 
            -
            @@ - | 
| 360 | 
            +
            @@ -375,8 +641,9 @@
         | 
| 361 | 
            +
                 if (lomem == 0 || lomem > p) lomem = p;
         | 
| 337 362 | 
             
                 if (himem < pend) himem = pend;
         | 
| 338 363 | 
             
                 heaps_used++;
         | 
| 339 | 
            -
             | 
| 364 | 
            +
            -    heap_slots *= 1.8;
         | 
| 340 365 | 
             
            -    if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
         | 
| 366 | 
            +
            +    heap_slots += heap_slots_increment;
         | 
| 367 | 
            +
            +    heap_slots_increment *= heap_slots_growth_factor;
         | 
| 341 368 | 
             
            +    if (heap_slots <= 0) heap_slots = heap_min_slots;
         | 
| 342 369 |  | 
| 343 370 | 
             
                 while (p < pend) {
         | 
| 344 371 | 
             
             	p->as.free.flags = 0;
         | 
| 345 | 
            -
            @@ - | 
| 372 | 
            +
            @@ -1026,6 +1293,39 @@
         | 
| 346 373 | 
             
                 }
         | 
| 347 374 | 
             
             }
         | 
| 348 375 |  | 
| @@ -382,7 +409,7 @@ | |
| 382 409 | 
             
             static void
         | 
| 383 410 | 
             
             free_unused_heaps()
         | 
| 384 411 | 
             
             {
         | 
| 385 | 
            -
            @@ - | 
| 412 | 
            +
            @@ -1056,12 +1356,21 @@
         | 
| 386 413 | 
             
                 unsigned long live = 0;
         | 
| 387 414 | 
             
                 unsigned long free_min = 0;
         | 
| 388 415 |  | 
| @@ -406,7 +433,7 @@ | |
| 406 433 |  | 
| 407 434 | 
             
                 if (ruby_in_compile && ruby_parser_stack_on_heap()) {
         | 
| 408 435 | 
             
             	/* should not reclaim nodes during compilation
         | 
| 409 | 
            -
            @@ - | 
| 436 | 
            +
            @@ -1094,6 +1403,9 @@
         | 
| 410 437 | 
             
             	    if (!(p->as.basic.flags & FL_MARK)) {
         | 
| 411 438 | 
             
             		if (p->as.basic.flags) {
         | 
| 412 439 | 
             
             		    obj_free((VALUE)p);
         | 
| @@ -416,7 +443,7 @@ | |
| 416 443 | 
             
             		}
         | 
| 417 444 | 
             
             		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
         | 
| 418 445 | 
             
             		    p->as.free.flags = FL_MARK; /* remain marked */
         | 
| 419 | 
            -
            @@ - | 
| 446 | 
            +
            @@ -1101,6 +1413,12 @@
         | 
| 420 447 | 
             
             		    final_list = p;
         | 
| 421 448 | 
             
             		}
         | 
| 422 449 | 
             
             		else {
         | 
| @@ -429,7 +456,7 @@ | |
| 429 456 | 
             
             		    p->as.free.flags = 0;
         | 
| 430 457 | 
             
             		    p->as.free.next = freelist;
         | 
| 431 458 | 
             
             		    freelist = p;
         | 
| 432 | 
            -
            @@ - | 
| 459 | 
            +
            @@ -1114,6 +1432,9 @@
         | 
| 433 460 | 
             
             	    else {
         | 
| 434 461 | 
             
             		RBASIC(p)->flags &= ~FL_MARK;
         | 
| 435 462 | 
             
             		live++;
         | 
| @@ -439,7 +466,7 @@ | |
| 439 466 | 
             
             	    }
         | 
| 440 467 | 
             
             	    p++;
         | 
| 441 468 | 
             
             	}
         | 
| 442 | 
            -
            @@ - | 
| 469 | 
            +
            @@ -1132,7 +1453,7 @@
         | 
| 443 470 | 
             
                 }
         | 
| 444 471 | 
             
                 if (malloc_increase > malloc_limit) {
         | 
| 445 472 | 
             
             	malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
         | 
| @@ -448,7 +475,7 @@ | |
| 448 475 | 
             
                 }
         | 
| 449 476 | 
             
                 malloc_increase = 0;
         | 
| 450 477 | 
             
                 if (freed < free_min) {
         | 
| 451 | 
            -
            @@ - | 
| 478 | 
            +
            @@ -1140,6 +1461,20 @@
         | 
| 452 479 | 
             
                 }
         | 
| 453 480 | 
             
                 during_gc = 0;
         | 
| 454 481 |  | 
| @@ -469,7 +496,7 @@ | |
| 469 496 | 
             
                 /* clear finalization list */
         | 
| 470 497 | 
             
                 if (final_list) {
         | 
| 471 498 | 
             
             	deferred_final_list = final_list;
         | 
| 472 | 
            -
            @@ - | 
| 499 | 
            +
            @@ -1334,6 +1669,7 @@
         | 
| 473 500 | 
             
                 struct gc_list *list;
         | 
| 474 501 | 
             
                 struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug??  */
         | 
| 475 502 | 
             
                 jmp_buf save_regs_gc_mark;
         | 
| @@ -477,7 +504,7 @@ | |
| 477 504 | 
             
                 SET_STACK_END;
         | 
| 478 505 |  | 
| 479 506 | 
             
             #ifdef HAVE_NATIVETHREAD
         | 
| 480 | 
            -
            @@ - | 
| 507 | 
            +
            @@ -1350,6 +1686,14 @@
         | 
| 481 508 | 
             
                 if (during_gc) return;
         | 
| 482 509 | 
             
                 during_gc++;
         | 
| 483 510 |  | 
| @@ -492,7 +519,7 @@ | |
| 492 519 | 
             
                 init_mark_stack();
         | 
| 493 520 |  | 
| 494 521 | 
             
                 gc_mark((VALUE)ruby_current_node, 0);
         | 
| 495 | 
            -
            @@ - | 
| 522 | 
            +
            @@ -1438,6 +1782,17 @@
         | 
| 496 523 | 
             
                 } while (!MARK_STACK_EMPTY);
         | 
| 497 524 |  | 
| 498 525 | 
             
                 gc_sweep();
         | 
| @@ -510,7 +537,7 @@ | |
| 510 537 | 
             
             }
         | 
| 511 538 |  | 
| 512 539 | 
             
             void
         | 
| 513 | 
            -
            @@ - | 
| 540 | 
            +
            @@ -1551,6 +1906,7 @@
         | 
| 514 541 | 
             
                 if (!rb_gc_stack_start) {
         | 
| 515 542 | 
             
             	Init_stack(0);
         | 
| 516 543 | 
             
                 }
         | 
| @@ -518,7 +545,7 @@ | |
| 518 545 | 
             
                 add_heap();
         | 
| 519 546 | 
             
             }
         | 
| 520 547 |  | 
| 521 | 
            -
            @@ - | 
| 548 | 
            +
            @@ -2020,6 +2376,14 @@
         | 
| 522 549 | 
             
                 rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
         | 
| 523 550 | 
             
                 rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
         | 
| 524 551 |  | 
    
        data/ruby186gc.patch
    ADDED
    
    | @@ -0,0 +1,564 @@ | |
| 1 | 
            +
            Index: gc.c
         | 
| 2 | 
            +
            ===================================================================
         | 
| 3 | 
            +
            --- gc.c	(revision 12920)
         | 
| 4 | 
            +
            +++ gc.c	(working copy)
         | 
| 5 | 
            +
            @@ -22,8 +22,16 @@
         | 
| 6 | 
            +
             #include <setjmp.h>
         | 
| 7 | 
            +
             #include <sys/types.h>
         | 
| 8 | 
            +
             
         | 
| 9 | 
            +
            +#ifdef _WIN32
         | 
| 10 | 
            +
            +#include <string.h>
         | 
| 11 | 
            +
            +#else
         | 
| 12 | 
            +
            +#include <strings.h>
         | 
| 13 | 
            +
            +#endif
         | 
| 14 | 
            +
            +
         | 
| 15 | 
            +
             #ifdef HAVE_SYS_TIME_H
         | 
| 16 | 
            +
             #include <sys/time.h>
         | 
| 17 | 
            +
            +#elif defined(_WIN32)
         | 
| 18 | 
            +
            +#include <time.h> 
         | 
| 19 | 
            +
             #endif
         | 
| 20 | 
            +
             
         | 
| 21 | 
            +
             #ifdef HAVE_SYS_RESOURCE_H
         | 
| 22 | 
            +
            @@ -40,7 +48,6 @@
         | 
| 23 | 
            +
             #if !defined(setjmp) && defined(HAVE__SETJMP)
         | 
| 24 | 
            +
             #define setjmp(env) _setjmp(env)
         | 
| 25 | 
            +
             #endif
         | 
| 26 | 
            +
            -
         | 
| 27 | 
            +
             /* Make alloca work the best possible way.  */
         | 
| 28 | 
            +
             #ifdef __GNUC__
         | 
| 29 | 
            +
             # ifndef atarist
         | 
| 30 | 
            +
            @@ -159,8 +166,17 @@
         | 
| 31 | 
            +
             	RUBY_CRITICAL(free(x));
         | 
| 32 | 
            +
             }
         | 
| 33 | 
            +
             
         | 
| 34 | 
            +
            +#if HAVE_LONG_LONG
         | 
| 35 | 
            +
            +#define GC_TIME_TYPE LONG_LONG
         | 
| 36 | 
            +
            +#else
         | 
| 37 | 
            +
            +#define GC_TIME_TYPE long
         | 
| 38 | 
            +
            +#endif
         | 
| 39 | 
            +
            +
         | 
| 40 | 
            +
             extern int ruby_in_compile;
         | 
| 41 | 
            +
             static int dont_gc;
         | 
| 42 | 
            +
            +static int gc_statistics = 0;
         | 
| 43 | 
            +
            +static GC_TIME_TYPE gc_time = 0;
         | 
| 44 | 
            +
            +static int gc_collections = 0;
         | 
| 45 | 
            +
             static int during_gc;
         | 
| 46 | 
            +
             static int need_call_final = 0;
         | 
| 47 | 
            +
             static st_table *finalizer_table = 0;
         | 
| 48 | 
            +
            @@ -195,7 +211,7 @@
         | 
| 49 | 
            +
              *  Disables garbage collection, returning <code>true</code> if garbage
         | 
| 50 | 
            +
              *  collection was already disabled.
         | 
| 51 | 
            +
              *
         | 
| 52 | 
            +
            - *     GC.disable   #=> false
         | 
| 53 | 
            +
            + *     GC.disable   #=> false or true
         | 
| 54 | 
            +
              *     GC.disable   #=> true
         | 
| 55 | 
            +
              *
         | 
| 56 | 
            +
              */
         | 
| 57 | 
            +
            @@ -209,6 +225,104 @@
         | 
| 58 | 
            +
                 return old;
         | 
| 59 | 
            +
             }
         | 
| 60 | 
            +
             
         | 
| 61 | 
            +
            +/*
         | 
| 62 | 
            +
            + *  call-seq:
         | 
| 63 | 
            +
            + *     GC.enable_stats    => true or false
         | 
| 64 | 
            +
            + *
         | 
| 65 | 
            +
            + *  Enables garbage collection statistics, returning <code>true</code> if garbage
         | 
| 66 | 
            +
            + *  collection statistics was already enabled.
         | 
| 67 | 
            +
            + *
         | 
| 68 | 
            +
            + *     GC.enable_stats   #=> false or true
         | 
| 69 | 
            +
            + *     GC.enable_stats   #=> true
         | 
| 70 | 
            +
            + *
         | 
| 71 | 
            +
            + */
         | 
| 72 | 
            +
            +
         | 
| 73 | 
            +
            +VALUE
         | 
| 74 | 
            +
            +rb_gc_enable_stats()
         | 
| 75 | 
            +
            +{
         | 
| 76 | 
            +
            +    int old = gc_statistics;
         | 
| 77 | 
            +
            +    gc_statistics = Qtrue;
         | 
| 78 | 
            +
            +    return old;
         | 
| 79 | 
            +
            +}
         | 
| 80 | 
            +
            +
         | 
| 81 | 
            +
            +/*
         | 
| 82 | 
            +
            + *  call-seq:
         | 
| 83 | 
            +
            + *     GC.disable_stats    => true or false
         | 
| 84 | 
            +
            + *
         | 
| 85 | 
            +
            + *  Disables garbage collection statistics, returning <code>true</code> if garbage
         | 
| 86 | 
            +
            + *  collection statistics was already disabled.
         | 
| 87 | 
            +
            + *
         | 
| 88 | 
            +
            + *     GC.disable_stats   #=> false or true
         | 
| 89 | 
            +
            + *     GC.disable_stats   #=> true
         | 
| 90 | 
            +
            + *
         | 
| 91 | 
            +
            + */
         | 
| 92 | 
            +
            +
         | 
| 93 | 
            +
            +VALUE
         | 
| 94 | 
            +
            +rb_gc_disable_stats()
         | 
| 95 | 
            +
            +{
         | 
| 96 | 
            +
            +    int old = gc_statistics;
         | 
| 97 | 
            +
            +    gc_statistics = Qfalse;
         | 
| 98 | 
            +
            +    return old;
         | 
| 99 | 
            +
            +}
         | 
| 100 | 
            +
            +
         | 
| 101 | 
            +
            +/*
         | 
| 102 | 
            +
            + *  call-seq:
         | 
| 103 | 
            +
            + *     GC.clear_stats    => nil
         | 
| 104 | 
            +
            + *
         | 
| 105 | 
            +
            + *  Clears garbage collection statistics, returning nil. This resets the number
         | 
| 106 | 
            +
            + *  of collections (GC.collections) and the time used (GC.time) to 0.
         | 
| 107 | 
            +
            + *
         | 
| 108 | 
            +
            + *     GC.clear_stats    #=> nil
         | 
| 109 | 
            +
            + *
         | 
| 110 | 
            +
            + */
         | 
| 111 | 
            +
            +
         | 
| 112 | 
            +
            +VALUE
         | 
| 113 | 
            +
            +rb_gc_clear_stats()
         | 
| 114 | 
            +
            +{
         | 
| 115 | 
            +
            +    gc_collections = 0;
         | 
| 116 | 
            +
            +    gc_time = 0;
         | 
| 117 | 
            +
            +    return Qnil; 
         | 
| 118 | 
            +
            +}
         | 
| 119 | 
            +
            +
         | 
| 120 | 
            +
            +/*
         | 
| 121 | 
            +
            + *  call-seq:
         | 
| 122 | 
            +
            + *     GC.collections    => Integer
         | 
| 123 | 
            +
            + *
         | 
| 124 | 
            +
            + *  Returns the number of garbage collections performed while GC statistics collection
         | 
| 125 | 
            +
            + *  was enabled.
         | 
| 126 | 
            +
            + *
         | 
| 127 | 
            +
            + *     GC.collections    #=> 35
         | 
| 128 | 
            +
            + *
         | 
| 129 | 
            +
            + */
         | 
| 130 | 
            +
            +
         | 
| 131 | 
            +
            +VALUE
         | 
| 132 | 
            +
            +rb_gc_collections()
         | 
| 133 | 
            +
            +{
         | 
| 134 | 
            +
            +    return INT2NUM(gc_collections);
         | 
| 135 | 
            +
            +}
         | 
| 136 | 
            +
            +
         | 
| 137 | 
            +
            +/*
         | 
| 138 | 
            +
            + *  call-seq:
         | 
| 139 | 
            +
            + *     GC.time    => Integer
         | 
| 140 | 
            +
            + *
         | 
| 141 | 
            +
            + *  Returns the time spent during garbage collection while GC statistics collection
         | 
| 142 | 
            +
            + *  was enabled (in micro seconds).
         | 
| 143 | 
            +
            + *
         | 
| 144 | 
            +
            + *     GC.time    #=> 20000
         | 
| 145 | 
            +
            + *
         | 
| 146 | 
            +
            + */
         | 
| 147 | 
            +
            +
         | 
| 148 | 
            +
            +VALUE
         | 
| 149 | 
            +
            +rb_gc_time()
         | 
| 150 | 
            +
            +{
         | 
| 151 | 
            +
            +#if HAVE_LONG_LONG
         | 
| 152 | 
            +
            +    return LL2NUM(gc_time);
         | 
| 153 | 
            +
            +#else
         | 
| 154 | 
            +
            +    return LONG2NUM(gc_time);
         | 
| 155 | 
            +
            +#endif
         | 
| 156 | 
            +
            +}
         | 
| 157 | 
            +
            +
         | 
| 158 | 
            +
            +
         | 
| 159 | 
            +
             VALUE rb_mGC;
         | 
| 160 | 
            +
             
         | 
| 161 | 
            +
             static struct gc_list {
         | 
| 162 | 
            +
            @@ -300,7 +414,7 @@
         | 
| 163 | 
            +
             static RVALUE *freelist = 0;
         | 
| 164 | 
            +
             static RVALUE *deferred_final_list = 0;
         | 
| 165 | 
            +
             
         | 
| 166 | 
            +
            -#define HEAPS_INCREMENT 10
         | 
| 167 | 
            +
            +static int heaps_increment = 10;
         | 
| 168 | 
            +
             static struct heaps_slot {
         | 
| 169 | 
            +
                 void *membase;
         | 
| 170 | 
            +
                 RVALUE *slot;
         | 
| 171 | 
            +
            @@ -309,13 +423,165 @@
         | 
| 172 | 
            +
             static int heaps_length = 0;
         | 
| 173 | 
            +
             static int heaps_used   = 0;
         | 
| 174 | 
            +
             
         | 
| 175 | 
            +
            -#define HEAP_MIN_SLOTS 10000
         | 
| 176 | 
            +
            -static int heap_slots = HEAP_MIN_SLOTS;
         | 
| 177 | 
            +
            +static int heap_min_slots = 10000;
         | 
| 178 | 
            +
            +static int heap_slots = 10000;
         | 
| 179 | 
            +
            +
         | 
| 180 | 
            +
            +static int heap_free_min = 4096;
         | 
| 181 | 
            +
            +static int heap_slots_increment = 10000;
         | 
| 182 | 
            +
            +static double heap_slots_growth_factor = 1.8;
         | 
| 183 | 
            +
            +
         | 
| 184 | 
            +
            +static long initial_malloc_limit = GC_MALLOC_LIMIT;
         | 
| 185 | 
            +
            +
         | 
| 186 | 
            +
            +static int verbose_gc_stats = Qfalse;
         | 
| 187 | 
            +
             
         | 
| 188 | 
            +
            -#define FREE_MIN  4096
         | 
| 189 | 
            +
            +static FILE* gc_data_file = NULL;
         | 
| 190 | 
            +
             
         | 
| 191 | 
            +
             static RVALUE *himem, *lomem;
         | 
| 192 | 
            +
             
         | 
| 193 | 
            +
            +static void set_gc_parameters()
         | 
| 194 | 
            +
            +{
         | 
| 195 | 
            +
            +    char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr,
         | 
| 196 | 
            +
            +      *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr;
         | 
| 197 | 
            +
            +
         | 
| 198 | 
            +
            +    gc_data_file = stderr;
         | 
| 199 | 
            +
            +
         | 
| 200 | 
            +
            +    gc_stats_ptr = getenv("RUBY_GC_STATS");
         | 
| 201 | 
            +
            +    if (gc_stats_ptr != NULL) {
         | 
| 202 | 
            +
            +	int gc_stats_i = atoi(gc_stats_ptr);
         | 
| 203 | 
            +
            +	if (gc_stats_i > 0) {
         | 
| 204 | 
            +
            +	    verbose_gc_stats = Qtrue;
         | 
| 205 | 
            +
            +	}
         | 
| 206 | 
            +
            +    }
         | 
| 207 | 
            +
            +
         | 
| 208 | 
            +
            +    gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE");
         | 
| 209 | 
            +
            +    if (gc_heap_file_ptr != NULL) {
         | 
| 210 | 
            +
            +	FILE* data_file = fopen(gc_heap_file_ptr, "w");
         | 
| 211 | 
            +
            +	if (data_file != NULL) {
         | 
| 212 | 
            +
            +	    gc_data_file = data_file;
         | 
| 213 | 
            +
            +	}
         | 
| 214 | 
            +
            +	else {
         | 
| 215 | 
            +
            +	    fprintf(stderr,
         | 
| 216 | 
            +
            +		    "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr);
         | 
| 217 | 
            +
            +	}
         | 
| 218 | 
            +
            +    }
         | 
| 219 | 
            +
            +
         | 
| 220 | 
            +
            +    min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
         | 
| 221 | 
            +
            +    if (min_slots_ptr != NULL) {
         | 
| 222 | 
            +
            +	int min_slots_i = atoi(min_slots_ptr);
         | 
| 223 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 224 | 
            +
            +	    fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr);
         | 
| 225 | 
            +
            +        }
         | 
| 226 | 
            +
            +	if (min_slots_i > 0) {
         | 
| 227 | 
            +
            +	    heap_slots = min_slots_i;
         | 
| 228 | 
            +
            +	    heap_min_slots = min_slots_i;
         | 
| 229 | 
            +
            +	}
         | 
| 230 | 
            +
            +    }
         | 
| 231 | 
            +
            +
         | 
| 232 | 
            +
            +    free_min_ptr = getenv("RUBY_HEAP_FREE_MIN");
         | 
| 233 | 
            +
            +    if (free_min_ptr != NULL) {
         | 
| 234 | 
            +
            +	int free_min_i = atoi(free_min_ptr);
         | 
| 235 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 236 | 
            +
            +	    fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr);
         | 
| 237 | 
            +
            +	}
         | 
| 238 | 
            +
            +	if (free_min_i > 0) {
         | 
| 239 | 
            +
            +	    heap_free_min = free_min_i;
         | 
| 240 | 
            +
            +	}
         | 
| 241 | 
            +
            +    }
         | 
| 242 | 
            +
            +
         | 
| 243 | 
            +
            +    heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT");
         | 
| 244 | 
            +
            +    if (heap_incr_ptr != NULL) {
         | 
| 245 | 
            +
            +	int heap_incr_i = atoi(heap_incr_ptr);
         | 
| 246 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 247 | 
            +
            +	    fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr);
         | 
| 248 | 
            +
            +	}
         | 
| 249 | 
            +
            +	if (heap_incr_i > 0) {
         | 
| 250 | 
            +
            +	    heaps_increment = heap_incr_i;
         | 
| 251 | 
            +
            +	}
         | 
| 252 | 
            +
            +    }
         | 
| 253 | 
            +
            +
         | 
| 254 | 
            +
            +    heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT");
         | 
| 255 | 
            +
            +    if (heap_slots_incr_ptr != NULL) {
         | 
| 256 | 
            +
            +	int heap_slots_incr_i = atoi(heap_slots_incr_ptr);
         | 
| 257 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 258 | 
            +
            +	    fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr);
         | 
| 259 | 
            +
            +	}
         | 
| 260 | 
            +
            +	if (heap_slots_incr_i > 0) {
         | 
| 261 | 
            +
            +	    heap_slots_increment = heap_slots_incr_i;
         | 
| 262 | 
            +
            +	}
         | 
| 263 | 
            +
            +    }
         | 
| 264 | 
            +
            +
         | 
| 265 | 
            +
            +    heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR");
         | 
| 266 | 
            +
            +    if (heap_slots_growth_factor_ptr != NULL) {
         | 
| 267 | 
            +
            +	double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr);
         | 
| 268 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 269 | 
            +
            +	    fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr);
         | 
| 270 | 
            +
            +	}
         | 
| 271 | 
            +
            +	if (heap_slots_growth_factor_d > 0) {
         | 
| 272 | 
            +
            +	    heap_slots_growth_factor = heap_slots_growth_factor_d;
         | 
| 273 | 
            +
            +	}
         | 
| 274 | 
            +
            +    }
         | 
| 275 | 
            +
            +
         | 
| 276 | 
            +
            +    malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
         | 
| 277 | 
            +
            +    if (malloc_limit_ptr != NULL) {
         | 
| 278 | 
            +
            +	int malloc_limit_i = atol(malloc_limit_ptr);
         | 
| 279 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 280 | 
            +
            +	    fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr);
         | 
| 281 | 
            +
            +	}
         | 
| 282 | 
            +
            +	if (malloc_limit_i > 0) {
         | 
| 283 | 
            +
            +	    initial_malloc_limit = malloc_limit_i;
         | 
| 284 | 
            +
            +	}
         | 
| 285 | 
            +
            +    }
         | 
| 286 | 
            +
            +}
         | 
| 287 | 
            +
            +
         | 
| 288 | 
            +
            +/*
         | 
| 289 | 
            +
            + *  call-seq:
         | 
| 290 | 
            +
            + *     GC.dump    => nil
         | 
| 291 | 
            +
            + *
         | 
| 292 | 
            +
            + *  dumps information about the current GC data structures to the GC log file
         | 
| 293 | 
            +
            + *
         | 
| 294 | 
            +
            + *     GC.dump    #=> nil
         | 
| 295 | 
            +
            + *
         | 
| 296 | 
            +
            + */
         | 
| 297 | 
            +
            +
         | 
| 298 | 
            +
            +VALUE
         | 
| 299 | 
            +
            +rb_gc_dump()
         | 
| 300 | 
            +
            +{
         | 
| 301 | 
            +
            +    int i;
         | 
| 302 | 
            +
            +
         | 
| 303 | 
            +
            +    for (i = 0; i < heaps_used; i++) {
         | 
| 304 | 
            +
            +	int heap_size = heaps[i].limit;
         | 
| 305 | 
            +
            +	fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size);
         | 
| 306 | 
            +
            +    }
         | 
| 307 | 
            +
            +
         | 
| 308 | 
            +
            +    return Qnil;
         | 
| 309 | 
            +
            +}
         | 
| 310 | 
            +
            +
         | 
| 311 | 
            +
            +/*
         | 
| 312 | 
            +
            + *  call-seq:
         | 
| 313 | 
            +
            + *     GC.log String  => String
         | 
| 314 | 
            +
            + *
         | 
| 315 | 
            +
            + *  Logs string to the GC data file and returns it.
         | 
| 316 | 
            +
            + *
         | 
| 317 | 
            +
            + *     GC.log "manual GC call"    #=> "manual GC call"
         | 
| 318 | 
            +
            + *
         | 
| 319 | 
            +
            + */
         | 
| 320 | 
            +
            +
         | 
| 321 | 
            +
            +VALUE
         | 
| 322 | 
            +
            +rb_gc_log(self, original_str)
         | 
| 323 | 
            +
            +     VALUE self, original_str;
         | 
| 324 | 
            +
            +{
         | 
| 325 | 
            +
            +    if (original_str == Qnil) {
         | 
| 326 | 
            +
            +        fprintf(gc_data_file, "\n");
         | 
| 327 | 
            +
            +    }
         | 
| 328 | 
            +
            +    else {
         | 
| 329 | 
            +
            +        VALUE str = StringValue(original_str);
         | 
| 330 | 
            +
            +        char *p = RSTRING(str)->ptr;
         | 
| 331 | 
            +
            +        fprintf(gc_data_file, "%s\n", p);
         | 
| 332 | 
            +
            +    }
         | 
| 333 | 
            +
            +    return original_str;
         | 
| 334 | 
            +
            +}
         | 
| 335 | 
            +
            +
         | 
| 336 | 
            +
            +
         | 
| 337 | 
            +
             static void
         | 
| 338 | 
            +
             add_heap()
         | 
| 339 | 
            +
             {
         | 
| 340 | 
            +
            @@ -326,7 +592,7 @@
         | 
| 341 | 
            +
             	struct heaps_slot *p;
         | 
| 342 | 
            +
             	int length;
         | 
| 343 | 
            +
             
         | 
| 344 | 
            +
            -	heaps_length += HEAPS_INCREMENT;
         | 
| 345 | 
            +
            +	heaps_length += heaps_increment;
         | 
| 346 | 
            +
             	length = heaps_length*sizeof(struct heaps_slot);
         | 
| 347 | 
            +
             	RUBY_CRITICAL(
         | 
| 348 | 
            +
             	    if (heaps_used > 0) {
         | 
| 349 | 
            +
            @@ -342,10 +608,10 @@
         | 
| 350 | 
            +
                 for (;;) {
         | 
| 351 | 
            +
             	RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
         | 
| 352 | 
            +
             	if (p == 0) {
         | 
| 353 | 
            +
            -	    if (heap_slots == HEAP_MIN_SLOTS) {
         | 
| 354 | 
            +
            +	    if (heap_slots == heap_min_slots) {
         | 
| 355 | 
            +
             		rb_memerror();
         | 
| 356 | 
            +
             	    }
         | 
| 357 | 
            +
            -	    heap_slots = HEAP_MIN_SLOTS;
         | 
| 358 | 
            +
            +	    heap_slots = heap_min_slots;
         | 
| 359 | 
            +
             	    continue;
         | 
| 360 | 
            +
             	}
         | 
| 361 | 
            +
                     heaps[heaps_used].membase = p;
         | 
| 362 | 
            +
            @@ -361,8 +627,9 @@
         | 
| 363 | 
            +
                 if (lomem == 0 || lomem > p) lomem = p;
         | 
| 364 | 
            +
                 if (himem < pend) himem = pend;
         | 
| 365 | 
            +
                 heaps_used++;
         | 
| 366 | 
            +
            -    heap_slots *= 1.8;
         | 
| 367 | 
            +
            -    if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
         | 
| 368 | 
            +
            +    heap_slots += heap_slots_increment;
         | 
| 369 | 
            +
            +    heap_slots_increment *= heap_slots_growth_factor;
         | 
| 370 | 
            +
            +    if (heap_slots <= 0) heap_slots = heap_min_slots;
         | 
| 371 | 
            +
             
         | 
| 372 | 
            +
                 while (p < pend) {
         | 
| 373 | 
            +
             	p->as.free.flags = 0;
         | 
| 374 | 
            +
            @@ -1015,6 +1282,39 @@
         | 
| 375 | 
            +
                 }
         | 
| 376 | 
            +
             }
         | 
| 377 | 
            +
             
         | 
| 378 | 
            +
            +static char* obj_type(int tp)
         | 
| 379 | 
            +
            +{
         | 
| 380 | 
            +
            +    switch (tp) {
         | 
| 381 | 
            +
            +	case T_NIL    : return "NIL";   
         | 
| 382 | 
            +
            +	case T_OBJECT : return "OBJECT";
         | 
| 383 | 
            +
            +	case T_CLASS  : return "CLASS";
         | 
| 384 | 
            +
            +	case T_ICLASS : return "ICLASS";
         | 
| 385 | 
            +
            +	case T_MODULE : return "MODULE";
         | 
| 386 | 
            +
            +	case T_FLOAT  : return "FLOAT";
         | 
| 387 | 
            +
            +	case T_STRING : return "STRING";
         | 
| 388 | 
            +
            +	case T_REGEXP : return "REGEXP";
         | 
| 389 | 
            +
            +	case T_ARRAY  : return "ARRAY";
         | 
| 390 | 
            +
            +	case T_FIXNUM : return "FIXNUM";
         | 
| 391 | 
            +
            +	case T_HASH   : return "HASH";
         | 
| 392 | 
            +
            +	case T_STRUCT : return "STRUCT";
         | 
| 393 | 
            +
            +	case T_BIGNUM : return "BIGNUM";
         | 
| 394 | 
            +
            +	case T_FILE   : return "FILE";
         | 
| 395 | 
            +
            +	    
         | 
| 396 | 
            +
            +	case T_TRUE   : return "TRUE";
         | 
| 397 | 
            +
            +	case T_FALSE  : return "FALSE";
         | 
| 398 | 
            +
            +	case T_DATA   : return "DATA";
         | 
| 399 | 
            +
            +	case T_MATCH  : return "MATCH";
         | 
| 400 | 
            +
            +	case T_SYMBOL : return "SYMBOL";
         | 
| 401 | 
            +
            +	    
         | 
| 402 | 
            +
            +	case T_BLKTAG : return "BLKTAG";
         | 
| 403 | 
            +
            +	case T_UNDEF  : return "UNDEF";
         | 
| 404 | 
            +
            +	case T_VARMAP : return "VARMAP";
         | 
| 405 | 
            +
            +	case T_SCOPE  : return "SCOPE";
         | 
| 406 | 
            +
            +	case T_NODE   : return "NODE";
         | 
| 407 | 
            +
            +	default: return "____";
         | 
| 408 | 
            +
            +    }
         | 
| 409 | 
            +
            +}
         | 
| 410 | 
            +
            +
         | 
| 411 | 
            +
             static void
         | 
| 412 | 
            +
             free_unused_heaps()
         | 
| 413 | 
            +
             {
         | 
| 414 | 
            +
            @@ -1045,12 +1345,21 @@
         | 
| 415 | 
            +
                 unsigned long live = 0;
         | 
| 416 | 
            +
                 unsigned long free_min = 0;
         | 
| 417 | 
            +
             
         | 
| 418 | 
            +
            +    unsigned long really_freed = 0;
         | 
| 419 | 
            +
            +    int free_counts[256];
         | 
| 420 | 
            +
            +    int live_counts[256];
         | 
| 421 | 
            +
            +    int do_gc_stats = gc_statistics & verbose_gc_stats;
         | 
| 422 | 
            +
            +
         | 
| 423 | 
            +
                 for (i = 0; i < heaps_used; i++) {
         | 
| 424 | 
            +
                     free_min += heaps[i].limit;
         | 
| 425 | 
            +
                 }
         | 
| 426 | 
            +
                 free_min = free_min * 0.2;
         | 
| 427 | 
            +
            -    if (free_min < FREE_MIN)
         | 
| 428 | 
            +
            -        free_min = FREE_MIN;
         | 
| 429 | 
            +
            +    if (free_min < heap_free_min)
         | 
| 430 | 
            +
            +        free_min = heap_free_min;
         | 
| 431 | 
            +
            +
         | 
| 432 | 
            +
            +    if (do_gc_stats) {
         | 
| 433 | 
            +
            +	for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; }
         | 
| 434 | 
            +
            +    }
         | 
| 435 | 
            +
             
         | 
| 436 | 
            +
                 if (ruby_in_compile && ruby_parser_stack_on_heap()) {
         | 
| 437 | 
            +
             	/* should not reclaim nodes during compilation
         | 
| 438 | 
            +
            @@ -1083,6 +1392,9 @@
         | 
| 439 | 
            +
             	    if (!(p->as.basic.flags & FL_MARK)) {
         | 
| 440 | 
            +
             		if (p->as.basic.flags) {
         | 
| 441 | 
            +
             		    obj_free((VALUE)p);
         | 
| 442 | 
            +
            +		    if (do_gc_stats) {
         | 
| 443 | 
            +
            +			really_freed++;
         | 
| 444 | 
            +
            +		    }
         | 
| 445 | 
            +
             		}
         | 
| 446 | 
            +
             		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
         | 
| 447 | 
            +
             		    p->as.free.flags = FL_MARK; /* remain marked */
         | 
| 448 | 
            +
            @@ -1090,6 +1402,12 @@
         | 
| 449 | 
            +
             		    final_list = p;
         | 
| 450 | 
            +
             		}
         | 
| 451 | 
            +
             		else {
         | 
| 452 | 
            +
            +		    if (do_gc_stats) {
         | 
| 453 | 
            +
            +			int obt = p->as.basic.flags & T_MASK;
         | 
| 454 | 
            +
            +			if (obt) {
         | 
| 455 | 
            +
            +			    free_counts[obt]++;
         | 
| 456 | 
            +
            +			}
         | 
| 457 | 
            +
            +		    }
         | 
| 458 | 
            +
             		    p->as.free.flags = 0;
         | 
| 459 | 
            +
             		    p->as.free.next = freelist;
         | 
| 460 | 
            +
             		    freelist = p;
         | 
| 461 | 
            +
            @@ -1103,6 +1421,9 @@
         | 
| 462 | 
            +
             	    else {
         | 
| 463 | 
            +
             		RBASIC(p)->flags &= ~FL_MARK;
         | 
| 464 | 
            +
             		live++;
         | 
| 465 | 
            +
            +		if (do_gc_stats) {
         | 
| 466 | 
            +
            + 		    live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++;
         | 
| 467 | 
            +
            + 		}
         | 
| 468 | 
            +
             	    }
         | 
| 469 | 
            +
             	    p++;
         | 
| 470 | 
            +
             	}
         | 
| 471 | 
            +
            @@ -1121,7 +1442,7 @@
         | 
| 472 | 
            +
                 }
         | 
| 473 | 
            +
                 if (malloc_increase > malloc_limit) {
         | 
| 474 | 
            +
             	malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
         | 
| 475 | 
            +
            -	if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
         | 
| 476 | 
            +
            +	if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
         | 
| 477 | 
            +
                 }
         | 
| 478 | 
            +
                 malloc_increase = 0;
         | 
| 479 | 
            +
                 if (freed < free_min) {
         | 
| 480 | 
            +
            @@ -1129,6 +1450,20 @@
         | 
| 481 | 
            +
                 }
         | 
| 482 | 
            +
                 during_gc = 0;
         | 
| 483 | 
            +
             
         | 
| 484 | 
            +
            +    if (do_gc_stats) {
         | 
| 485 | 
            +
            +	fprintf(gc_data_file, "objects processed: %.7d\n", live+freed);
         | 
| 486 | 
            +
            +	fprintf(gc_data_file, "live objects	: %.7d\n", live);
         | 
| 487 | 
            +
            +	fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed);
         | 
| 488 | 
            +
            +	fprintf(gc_data_file, "freed objects	: %.7d\n", really_freed);
         | 
| 489 | 
            +
            +	for(i=0; i<256; i++) {
         | 
| 490 | 
            +
            +	    if (free_counts[i]>0) {
         | 
| 491 | 
            +
            +		fprintf(gc_data_file,
         | 
| 492 | 
            +
            +			"kept %.7d / freed %.7d objects of type %s\n",
         | 
| 493 | 
            +
            +			live_counts[i], free_counts[i], obj_type(i));
         | 
| 494 | 
            +
            +	    }
         | 
| 495 | 
            +
            +	}
         | 
| 496 | 
            +
            +    }
         | 
| 497 | 
            +
            +
         | 
| 498 | 
            +
                 /* clear finalization list */
         | 
| 499 | 
            +
                 if (final_list) {
         | 
| 500 | 
            +
             	deferred_final_list = final_list;
         | 
| 501 | 
            +
            @@ -1323,6 +1658,7 @@
         | 
| 502 | 
            +
                 struct gc_list *list;
         | 
| 503 | 
            +
                 struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug??  */
         | 
| 504 | 
            +
                 jmp_buf save_regs_gc_mark;
         | 
| 505 | 
            +
            +    struct timeval gctv1, gctv2;
         | 
| 506 | 
            +
                 SET_STACK_END;
         | 
| 507 | 
            +
             
         | 
| 508 | 
            +
             #ifdef HAVE_NATIVETHREAD
         | 
| 509 | 
            +
            @@ -1339,6 +1675,14 @@
         | 
| 510 | 
            +
                 if (during_gc) return;
         | 
| 511 | 
            +
                 during_gc++;
         | 
| 512 | 
            +
             
         | 
| 513 | 
            +
            +    if (gc_statistics) {
         | 
| 514 | 
            +
            +        gc_collections++;
         | 
| 515 | 
            +
            +	gettimeofday(&gctv1, NULL);
         | 
| 516 | 
            +
            +        if (verbose_gc_stats) {
         | 
| 517 | 
            +
            +	    fprintf(gc_data_file, "Garbage collection started\n");
         | 
| 518 | 
            +
            +	}
         | 
| 519 | 
            +
            +    }
         | 
| 520 | 
            +
            +
         | 
| 521 | 
            +
                 init_mark_stack();
         | 
| 522 | 
            +
             
         | 
| 523 | 
            +
                 gc_mark((VALUE)ruby_current_node, 0);
         | 
| 524 | 
            +
            @@ -1414,6 +1758,17 @@
         | 
| 525 | 
            +
                 } while (!MARK_STACK_EMPTY);
         | 
| 526 | 
            +
             
         | 
| 527 | 
            +
                 gc_sweep();
         | 
| 528 | 
            +
            +
         | 
| 529 | 
            +
            +    if (gc_statistics) {
         | 
| 530 | 
            +
            +        GC_TIME_TYPE musecs_used;
         | 
| 531 | 
            +
            +	gettimeofday(&gctv2, NULL);
         | 
| 532 | 
            +
            +	musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec);
         | 
| 533 | 
            +
            +	gc_time += musecs_used;
         | 
| 534 | 
            +
            +
         | 
| 535 | 
            +
            +	if (verbose_gc_stats) {
         | 
| 536 | 
            +
            +	    fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000);
         | 
| 537 | 
            +
            +	}
         | 
| 538 | 
            +
            +    }
         | 
| 539 | 
            +
             }
         | 
| 540 | 
            +
             
         | 
| 541 | 
            +
             void
         | 
| 542 | 
            +
            @@ -1595,6 +1950,7 @@
         | 
| 543 | 
            +
                 if (!rb_gc_stack_start) {
         | 
| 544 | 
            +
             	Init_stack(0);
         | 
| 545 | 
            +
                 }
         | 
| 546 | 
            +
            +    set_gc_parameters();
         | 
| 547 | 
            +
                 add_heap();
         | 
| 548 | 
            +
             }
         | 
| 549 | 
            +
             
         | 
| 550 | 
            +
            @@ -2064,6 +2420,14 @@
         | 
| 551 | 
            +
                 rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
         | 
| 552 | 
            +
                 rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
         | 
| 553 | 
            +
             
         | 
| 554 | 
            +
            +    rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0);
         | 
| 555 | 
            +
            +    rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0);
         | 
| 556 | 
            +
            +    rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0);
         | 
| 557 | 
            +
            +    rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0);
         | 
| 558 | 
            +
            +    rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0);
         | 
| 559 | 
            +
            +    rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0);
         | 
| 560 | 
            +
            +    rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1);
         | 
| 561 | 
            +
            +
         | 
| 562 | 
            +
                 rb_mObSpace = rb_define_module("ObjectSpace");
         | 
| 563 | 
            +
                 rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
         | 
| 564 | 
            +
                 rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);
         |