ruby-prof 0.7.4 → 0.7.5

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.
@@ -0,0 +1,720 @@
1
+ --- gc.c 2007-03-03 09:30:46.000000000 +0200
2
+ +++ gc.c 2008-01-29 11:30:49.000000000 +0200
3
+ @@ -22,8 +22,16 @@
4
+ #include <setjmp.h>
5
+ #include <sys/types.h>
6
+
7
+ +#ifdef _WIN32
8
+ +#include <string.h>
9
+ +#else
10
+ +#include <strings.h>
11
+ +#endif
12
+ +
13
+ #ifdef HAVE_SYS_TIME_H
14
+ #include <sys/time.h>
15
+ +#elif defined(_WIN32)
16
+ +#include <time.h>
17
+ #endif
18
+
19
+ #ifdef HAVE_SYS_RESOURCE_H
20
+ @@ -40,7 +48,6 @@
21
+ #if !defined(setjmp) && defined(HAVE__SETJMP)
22
+ #define setjmp(env) _setjmp(env)
23
+ #endif
24
+ -
25
+ /* Make alloca work the best possible way. */
26
+ #ifdef __GNUC__
27
+ # ifndef atarist
28
+ @@ -74,6 +81,20 @@
29
+ static VALUE nomem_error;
30
+ static void garbage_collect();
31
+
32
+ +static unsigned long live_objects = 0;
33
+ +unsigned long rb_os_live_objects()
34
+ +{ return live_objects; }
35
+ +
36
+ +#if defined(HAVE_LONG_LONG)
37
+ +static unsigned long long allocated_objects = 0;
38
+ +unsigned long long rb_os_allocated_objects()
39
+ +{ return allocated_objects; }
40
+ +#else
41
+ +static unsigned long allocated_objects = 0;
42
+ +unsigned long rb_os_allocated_objects()
43
+ +{ return allocated_objects; }
44
+ +#endif
45
+ +
46
+ void
47
+ rb_memerror()
48
+ {
49
+ @@ -87,6 +108,10 @@
50
+ rb_exc_raise(nomem_error);
51
+ }
52
+
53
+ +long gc_allocated_size = 0;
54
+ +long gc_num_allocations = 0;
55
+ +static int gc_statistics = 0;
56
+ +
57
+ void *
58
+ ruby_xmalloc(size)
59
+ long size;
60
+ @@ -110,6 +135,10 @@
61
+ rb_memerror();
62
+ }
63
+ }
64
+ + if (gc_statistics) {
65
+ + gc_allocated_size += size;
66
+ + gc_num_allocations += 1;
67
+ + }
68
+
69
+ return mem;
70
+ }
71
+ @@ -159,8 +188,16 @@
72
+ RUBY_CRITICAL(free(x));
73
+ }
74
+
75
+ +#if HAVE_LONG_LONG
76
+ +#define GC_TIME_TYPE LONG_LONG
77
+ +#else
78
+ +#define GC_TIME_TYPE long
79
+ +#endif
80
+ +
81
+ extern int ruby_in_compile;
82
+ static int dont_gc;
83
+ +static GC_TIME_TYPE gc_time = 0;
84
+ +static int gc_collections = 0;
85
+ static int during_gc;
86
+ static int need_call_final = 0;
87
+ static st_table *finalizer_table = 0;
88
+ @@ -195,7 +232,7 @@
89
+ * Disables garbage collection, returning <code>true</code> if garbage
90
+ * collection was already disabled.
91
+ *
92
+ - * GC.disable #=> false
93
+ + * GC.disable #=> false or true
94
+ * GC.disable #=> true
95
+ *
96
+ */
97
+ @@ -209,6 +246,140 @@
98
+ return old;
99
+ }
100
+
101
+ +/*
102
+ + * call-seq:
103
+ + * GC.enable_stats => true or false
104
+ + *
105
+ + * Enables garbage collection statistics, returning <code>true</code> if garbage
106
+ + * collection statistics was already enabled.
107
+ + *
108
+ + * GC.enable_stats #=> false or true
109
+ + * GC.enable_stats #=> true
110
+ + *
111
+ + */
112
+ +
113
+ +VALUE
114
+ +rb_gc_enable_stats()
115
+ +{
116
+ + int old = gc_statistics;
117
+ + gc_statistics = Qtrue;
118
+ + return old;
119
+ +}
120
+ +
121
+ +/*
122
+ + * call-seq:
123
+ + * GC.disable_stats => true or false
124
+ + *
125
+ + * Disables garbage collection statistics, returning <code>true</code> if garbage
126
+ + * collection statistics was already disabled.
127
+ + *
128
+ + * GC.disable_stats #=> false or true
129
+ + * GC.disable_stats #=> true
130
+ + *
131
+ + */
132
+ +
133
+ +VALUE
134
+ +rb_gc_disable_stats()
135
+ +{
136
+ + int old = gc_statistics;
137
+ + gc_statistics = Qfalse;
138
+ + gc_allocated_size = 0;
139
+ + gc_num_allocations = 0;
140
+ + return old;
141
+ +}
142
+ +
143
+ +/*
144
+ + * call-seq:
145
+ + * GC.clear_stats => nil
146
+ + *
147
+ + * Clears garbage collection statistics, returning nil. This resets the number
148
+ + * of collections (GC.collections) and the time used (GC.time) to 0.
149
+ + *
150
+ + * GC.clear_stats #=> nil
151
+ + *
152
+ + */
153
+ +
154
+ +VALUE
155
+ +rb_gc_clear_stats()
156
+ +{
157
+ + gc_collections = 0;
158
+ + gc_time = 0;
159
+ + gc_allocated_size = 0;
160
+ + gc_num_allocations = 0;
161
+ + return Qnil;
162
+ +}
163
+ +
164
+ +/*
165
+ + * call-seq:
166
+ + * GC.allocated_size => Integer
167
+ + *
168
+ + * Returns the size of memory (in bytes) allocated since GC statistics collection
169
+ + * was enabled.
170
+ + *
171
+ + * GC.allocated_size #=> 35
172
+ + *
173
+ + */
174
+ +VALUE
175
+ +rb_gc_allocated_size()
176
+ +{
177
+ + return INT2NUM(gc_allocated_size);
178
+ +}
179
+ +
180
+ +/*
181
+ + * call-seq:
182
+ + * GC.num_allocations => Integer
183
+ + *
184
+ + * Returns the number of memory allocations since GC statistics collection
185
+ + * was enabled.
186
+ + *
187
+ + * GC.num_allocations #=> 150
188
+ + *
189
+ + */
190
+ +VALUE
191
+ +rb_gc_num_allocations()
192
+ +{
193
+ + return INT2NUM(gc_num_allocations);
194
+ +}
195
+ +
196
+ +/*
197
+ + * call-seq:
198
+ + * GC.collections => Integer
199
+ + *
200
+ + * Returns the number of garbage collections performed while GC statistics collection
201
+ + * was enabled.
202
+ + *
203
+ + * GC.collections #=> 35
204
+ + *
205
+ + */
206
+ +
207
+ +VALUE
208
+ +rb_gc_collections()
209
+ +{
210
+ + return INT2NUM(gc_collections);
211
+ +}
212
+ +
213
+ +/*
214
+ + * call-seq:
215
+ + * GC.time => Integer
216
+ + *
217
+ + * Returns the time spent during garbage collection while GC statistics collection
218
+ + * was enabled (in micro seconds).
219
+ + *
220
+ + * GC.time #=> 20000
221
+ + *
222
+ + */
223
+ +
224
+ +VALUE
225
+ +rb_gc_time()
226
+ +{
227
+ +#if HAVE_LONG_LONG
228
+ + return LL2NUM(gc_time);
229
+ +#else
230
+ + return LONG2NUM(gc_time);
231
+ +#endif
232
+ +}
233
+ +
234
+ +
235
+ VALUE rb_mGC;
236
+
237
+ static struct gc_list {
238
+ @@ -300,7 +471,7 @@
239
+ static RVALUE *freelist = 0;
240
+ static RVALUE *deferred_final_list = 0;
241
+
242
+ -#define HEAPS_INCREMENT 10
243
+ +static int heaps_increment = 10;
244
+ static struct heaps_slot {
245
+ void *membase;
246
+ RVALUE *slot;
247
+ @@ -309,13 +480,165 @@
248
+ static int heaps_length = 0;
249
+ static int heaps_used = 0;
250
+
251
+ -#define HEAP_MIN_SLOTS 10000
252
+ -static int heap_slots = HEAP_MIN_SLOTS;
253
+ +static int heap_min_slots = 10000;
254
+ +static int heap_slots = 10000;
255
+ +
256
+ +static int heap_free_min = 4096;
257
+ +static int heap_slots_increment = 10000;
258
+ +static double heap_slots_growth_factor = 1.8;
259
+
260
+ -#define FREE_MIN 4096
261
+ +static long initial_malloc_limit = GC_MALLOC_LIMIT;
262
+ +
263
+ +static int verbose_gc_stats = Qfalse;
264
+ +
265
+ +static FILE* gc_data_file = NULL;
266
+
267
+ static RVALUE *himem, *lomem;
268
+
269
+ +static void set_gc_parameters()
270
+ +{
271
+ + char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr,
272
+ + *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr;
273
+ +
274
+ + gc_data_file = stderr;
275
+ +
276
+ + gc_stats_ptr = getenv("RUBY_GC_STATS");
277
+ + if (gc_stats_ptr != NULL) {
278
+ + int gc_stats_i = atoi(gc_stats_ptr);
279
+ + if (gc_stats_i > 0) {
280
+ + verbose_gc_stats = Qtrue;
281
+ + }
282
+ + }
283
+ +
284
+ + gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE");
285
+ + if (gc_heap_file_ptr != NULL) {
286
+ + FILE* data_file = fopen(gc_heap_file_ptr, "w");
287
+ + if (data_file != NULL) {
288
+ + gc_data_file = data_file;
289
+ + }
290
+ + else {
291
+ + fprintf(stderr,
292
+ + "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr);
293
+ + }
294
+ + }
295
+ +
296
+ + min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
297
+ + if (min_slots_ptr != NULL) {
298
+ + int min_slots_i = atoi(min_slots_ptr);
299
+ + if (verbose_gc_stats) {
300
+ + fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr);
301
+ + }
302
+ + if (min_slots_i > 0) {
303
+ + heap_slots = min_slots_i;
304
+ + heap_min_slots = min_slots_i;
305
+ + }
306
+ + }
307
+ +
308
+ + free_min_ptr = getenv("RUBY_HEAP_FREE_MIN");
309
+ + if (free_min_ptr != NULL) {
310
+ + int free_min_i = atoi(free_min_ptr);
311
+ + if (verbose_gc_stats) {
312
+ + fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr);
313
+ + }
314
+ + if (free_min_i > 0) {
315
+ + heap_free_min = free_min_i;
316
+ + }
317
+ + }
318
+ +
319
+ + heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT");
320
+ + if (heap_incr_ptr != NULL) {
321
+ + int heap_incr_i = atoi(heap_incr_ptr);
322
+ + if (verbose_gc_stats) {
323
+ + fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr);
324
+ + }
325
+ + if (heap_incr_i > 0) {
326
+ + heaps_increment = heap_incr_i;
327
+ + }
328
+ + }
329
+ +
330
+ + heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT");
331
+ + if (heap_slots_incr_ptr != NULL) {
332
+ + int heap_slots_incr_i = atoi(heap_slots_incr_ptr);
333
+ + if (verbose_gc_stats) {
334
+ + fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr);
335
+ + }
336
+ + if (heap_slots_incr_i > 0) {
337
+ + heap_slots_increment = heap_slots_incr_i;
338
+ + }
339
+ + }
340
+ +
341
+ + heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR");
342
+ + if (heap_slots_growth_factor_ptr != NULL) {
343
+ + double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr);
344
+ + if (verbose_gc_stats) {
345
+ + fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr);
346
+ + }
347
+ + if (heap_slots_growth_factor_d > 0) {
348
+ + heap_slots_growth_factor = heap_slots_growth_factor_d;
349
+ + }
350
+ + }
351
+ +
352
+ + malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
353
+ + if (malloc_limit_ptr != NULL) {
354
+ + int malloc_limit_i = atol(malloc_limit_ptr);
355
+ + if (verbose_gc_stats) {
356
+ + fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr);
357
+ + }
358
+ + if (malloc_limit_i > 0) {
359
+ + initial_malloc_limit = malloc_limit_i;
360
+ + }
361
+ + }
362
+ +}
363
+ +
364
+ +/*
365
+ + * call-seq:
366
+ + * GC.dump => nil
367
+ + *
368
+ + * dumps information about the current GC data structures to the GC log file
369
+ + *
370
+ + * GC.dump #=> nil
371
+ + *
372
+ + */
373
+ +
374
+ +VALUE
375
+ +rb_gc_dump()
376
+ +{
377
+ + int i;
378
+ +
379
+ + for (i = 0; i < heaps_used; i++) {
380
+ + int heap_size = heaps[i].limit;
381
+ + fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size);
382
+ + }
383
+ +
384
+ + return Qnil;
385
+ +}
386
+ +
387
+ +/*
388
+ + * call-seq:
389
+ + * GC.log String => String
390
+ + *
391
+ + * Logs string to the GC data file and returns it.
392
+ + *
393
+ + * GC.log "manual GC call" #=> "manual GC call"
394
+ + *
395
+ + */
396
+ +
397
+ +VALUE
398
+ +rb_gc_log(self, original_str)
399
+ + VALUE self, original_str;
400
+ +{
401
+ + if (original_str == Qnil) {
402
+ + fprintf(gc_data_file, "\n");
403
+ + }
404
+ + else {
405
+ + VALUE str = StringValue(original_str);
406
+ + char *p = RSTRING(str)->ptr;
407
+ + fprintf(gc_data_file, "%s\n", p);
408
+ + }
409
+ + return original_str;
410
+ +}
411
+ +
412
+ +
413
+ static void
414
+ add_heap()
415
+ {
416
+ @@ -326,7 +649,7 @@
417
+ struct heaps_slot *p;
418
+ int length;
419
+
420
+ - heaps_length += HEAPS_INCREMENT;
421
+ + heaps_length += heaps_increment;
422
+ length = heaps_length*sizeof(struct heaps_slot);
423
+ RUBY_CRITICAL(
424
+ if (heaps_used > 0) {
425
+ @@ -342,10 +665,10 @@
426
+ for (;;) {
427
+ RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
428
+ if (p == 0) {
429
+ - if (heap_slots == HEAP_MIN_SLOTS) {
430
+ + if (heap_slots == heap_min_slots) {
431
+ rb_memerror();
432
+ }
433
+ - heap_slots = HEAP_MIN_SLOTS;
434
+ + heap_slots = heap_min_slots;
435
+ continue;
436
+ }
437
+ heaps[heaps_used].membase = p;
438
+ @@ -361,8 +684,9 @@
439
+ if (lomem == 0 || lomem > p) lomem = p;
440
+ if (himem < pend) himem = pend;
441
+ heaps_used++;
442
+ - heap_slots *= 1.8;
443
+ - if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
444
+ + heap_slots += heap_slots_increment;
445
+ + heap_slots_increment *= heap_slots_growth_factor;
446
+ + if (heap_slots <= 0) heap_slots = heap_min_slots;
447
+
448
+ while (p < pend) {
449
+ p->as.free.flags = 0;
450
+ @@ -387,6 +711,8 @@
451
+ RANY(obj)->file = ruby_sourcefile;
452
+ RANY(obj)->line = ruby_sourceline;
453
+ #endif
454
+ + live_objects++;
455
+ + allocated_objects++;
456
+ return obj;
457
+ }
458
+
459
+ @@ -1015,6 +1341,39 @@
460
+ }
461
+ }
462
+
463
+ +static char* obj_type(int tp)
464
+ +{
465
+ + switch (tp) {
466
+ + case T_NIL : return "NIL";
467
+ + case T_OBJECT : return "OBJECT";
468
+ + case T_CLASS : return "CLASS";
469
+ + case T_ICLASS : return "ICLASS";
470
+ + case T_MODULE : return "MODULE";
471
+ + case T_FLOAT : return "FLOAT";
472
+ + case T_STRING : return "STRING";
473
+ + case T_REGEXP : return "REGEXP";
474
+ + case T_ARRAY : return "ARRAY";
475
+ + case T_FIXNUM : return "FIXNUM";
476
+ + case T_HASH : return "HASH";
477
+ + case T_STRUCT : return "STRUCT";
478
+ + case T_BIGNUM : return "BIGNUM";
479
+ + case T_FILE : return "FILE";
480
+ +
481
+ + case T_TRUE : return "TRUE";
482
+ + case T_FALSE : return "FALSE";
483
+ + case T_DATA : return "DATA";
484
+ + case T_MATCH : return "MATCH";
485
+ + case T_SYMBOL : return "SYMBOL";
486
+ +
487
+ + case T_BLKTAG : return "BLKTAG";
488
+ + case T_UNDEF : return "UNDEF";
489
+ + case T_VARMAP : return "VARMAP";
490
+ + case T_SCOPE : return "SCOPE";
491
+ + case T_NODE : return "NODE";
492
+ + default: return "____";
493
+ + }
494
+ +}
495
+ +
496
+ static void
497
+ free_unused_heaps()
498
+ {
499
+ @@ -1044,13 +1403,23 @@
500
+ int i;
501
+ unsigned long live = 0;
502
+ unsigned long free_min = 0;
503
+ + live_objects = 0;
504
+ +
505
+ + unsigned long really_freed = 0;
506
+ + int free_counts[256];
507
+ + int live_counts[256];
508
+ + int do_gc_stats = gc_statistics & verbose_gc_stats;
509
+
510
+ for (i = 0; i < heaps_used; i++) {
511
+ free_min += heaps[i].limit;
512
+ }
513
+ free_min = free_min * 0.2;
514
+ - if (free_min < FREE_MIN)
515
+ - free_min = FREE_MIN;
516
+ + if (free_min < heap_free_min)
517
+ + free_min = heap_free_min;
518
+ +
519
+ + if (do_gc_stats) {
520
+ + for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; }
521
+ + }
522
+
523
+ if (ruby_in_compile && ruby_parser_stack_on_heap()) {
524
+ /* should not reclaim nodes during compilation
525
+ @@ -1083,6 +1452,9 @@
526
+ if (!(p->as.basic.flags & FL_MARK)) {
527
+ if (p->as.basic.flags) {
528
+ obj_free((VALUE)p);
529
+ + if (do_gc_stats) {
530
+ + really_freed++;
531
+ + }
532
+ }
533
+ if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
534
+ p->as.free.flags = FL_MARK; /* remain marked */
535
+ @@ -1090,6 +1462,12 @@
536
+ final_list = p;
537
+ }
538
+ else {
539
+ + if (do_gc_stats) {
540
+ + int obt = p->as.basic.flags & T_MASK;
541
+ + if (obt) {
542
+ + free_counts[obt]++;
543
+ + }
544
+ + }
545
+ p->as.free.flags = 0;
546
+ p->as.free.next = freelist;
547
+ freelist = p;
548
+ @@ -1102,7 +1480,10 @@
549
+ }
550
+ else {
551
+ RBASIC(p)->flags &= ~FL_MARK;
552
+ - live++;
553
+ + live_objects++;
554
+ + if (do_gc_stats) {
555
+ + live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++;
556
+ + }
557
+ }
558
+ p++;
559
+ }
560
+ @@ -1120,8 +1501,8 @@
561
+ }
562
+ }
563
+ if (malloc_increase > malloc_limit) {
564
+ - malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
565
+ - if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
566
+ + malloc_limit += (malloc_increase - malloc_limit) * (double)live_objects / (live_objects + freed);
567
+ + if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
568
+ }
569
+ malloc_increase = 0;
570
+ if (freed < free_min) {
571
+ @@ -1129,6 +1510,20 @@
572
+ }
573
+ during_gc = 0;
574
+
575
+ + if (do_gc_stats) {
576
+ + fprintf(gc_data_file, "objects processed: %.7d\n", live+freed);
577
+ + fprintf(gc_data_file, "live objects : %.7d\n", live);
578
+ + fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed);
579
+ + fprintf(gc_data_file, "freed objects : %.7d\n", really_freed);
580
+ + for(i=0; i<256; i++) {
581
+ + if (free_counts[i]>0) {
582
+ + fprintf(gc_data_file,
583
+ + "kept %.7d / freed %.7d objects of type %s\n",
584
+ + live_counts[i], free_counts[i], obj_type(i));
585
+ + }
586
+ + }
587
+ + }
588
+ +
589
+ /* clear finalization list */
590
+ if (final_list) {
591
+ deferred_final_list = final_list;
592
+ @@ -1323,6 +1718,7 @@
593
+ struct gc_list *list;
594
+ struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
595
+ jmp_buf save_regs_gc_mark;
596
+ + struct timeval gctv1, gctv2;
597
+ SET_STACK_END;
598
+
599
+ #ifdef HAVE_NATIVETHREAD
600
+ @@ -1339,6 +1735,14 @@
601
+ if (during_gc) return;
602
+ during_gc++;
603
+
604
+ + if (gc_statistics) {
605
+ + gc_collections++;
606
+ + gettimeofday(&gctv1, NULL);
607
+ + if (verbose_gc_stats) {
608
+ + fprintf(gc_data_file, "Garbage collection started\n");
609
+ + }
610
+ + }
611
+ +
612
+ init_mark_stack();
613
+
614
+ gc_mark((VALUE)ruby_current_node, 0);
615
+ @@ -1414,6 +1818,17 @@
616
+ } while (!MARK_STACK_EMPTY);
617
+
618
+ gc_sweep();
619
+ +
620
+ + if (gc_statistics) {
621
+ + GC_TIME_TYPE musecs_used;
622
+ + gettimeofday(&gctv2, NULL);
623
+ + musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec);
624
+ + gc_time += musecs_used;
625
+ +
626
+ + if (verbose_gc_stats) {
627
+ + fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000);
628
+ + }
629
+ + }
630
+ }
631
+
632
+ void
633
+ @@ -1595,6 +2010,7 @@
634
+ if (!rb_gc_stack_start) {
635
+ Init_stack(0);
636
+ }
637
+ + set_gc_parameters();
638
+ add_heap();
639
+ }
640
+
641
+ @@ -2047,6 +2463,35 @@
642
+ return (VALUE)((long)obj|FIXNUM_FLAG);
643
+ }
644
+
645
+ +/* call-seq:
646
+ + * ObjectSpace.live_objects => number
647
+ + *
648
+ + * Returns the count of objects currently allocated in the system. This goes
649
+ + * down after the garbage collector runs.
650
+ + */
651
+ +static
652
+ +VALUE os_live_objects(VALUE self)
653
+ +{ return ULONG2NUM(live_objects); }
654
+ +
655
+ +/* call-seq:
656
+ + * ObjectSpace.allocated_objects => number
657
+ + *
658
+ + * Returns the count of objects allocated since the Ruby interpreter has
659
+ + * started. This number can only increase. To know how many objects are
660
+ + * currently allocated, use ObjectSpace::live_objects
661
+ + */
662
+ +static
663
+ +VALUE os_allocated_objects(VALUE self)
664
+ +{
665
+ +#if defined(HAVE_LONG_LONG)
666
+ + return ULL2NUM(allocated_objects);
667
+ +#else
668
+ + return ULONG2NUM(allocated_objects);
669
+ +#endif
670
+ +}
671
+ +
672
+ +
673
+ +
674
+ /*
675
+ * The <code>GC</code> module provides an interface to Ruby's mark and
676
+ * sweep garbage collection mechanism. Some of the underlying methods
677
+ @@ -2064,6 +2509,16 @@
678
+ rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
679
+ rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
680
+
681
+ + rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0);
682
+ + rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0);
683
+ + rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0);
684
+ + rb_define_singleton_method(rb_mGC, "allocated_size", rb_gc_allocated_size, 0);
685
+ + rb_define_singleton_method(rb_mGC, "num_allocations", rb_gc_num_allocations, 0);
686
+ + rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0);
687
+ + rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0);
688
+ + rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0);
689
+ + rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1);
690
+ +
691
+ rb_mObSpace = rb_define_module("ObjectSpace");
692
+ rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
693
+ rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);
694
+ @@ -2071,6 +2526,8 @@
695
+ rb_define_module_function(rb_mObSpace, "remove_finalizer", rm_final, 1);
696
+ rb_define_module_function(rb_mObSpace, "finalizers", finals, 0);
697
+ rb_define_module_function(rb_mObSpace, "call_finalizer", call_final, 1);
698
+ + rb_define_module_function(rb_mObSpace, "live_objects", os_live_objects, 0);
699
+ + rb_define_module_function(rb_mObSpace, "allocated_objects", os_allocated_objects, 0);
700
+
701
+ rb_define_module_function(rb_mObSpace, "define_finalizer", define_final, -1);
702
+ rb_define_module_function(rb_mObSpace, "undefine_finalizer", undefine_final, 1);
703
+ --- intern.h 2007-08-22 05:41:24.000000000 +0300
704
+ +++ intern.h 2008-01-29 13:36:52.000000000 +0200
705
+ @@ -253,6 +253,15 @@
706
+ VALUE rb_gc_enable _((void));
707
+ VALUE rb_gc_disable _((void));
708
+ VALUE rb_gc_start _((void));
709
+ +VALUE rb_gc_enable_stats _((void));
710
+ +VALUE rb_gc_disable_stats _((void));
711
+ +VALUE rb_gc_allocated_size _((void));
712
+ +unsigned long rb_os_live_objects _((void));
713
+ +#ifdef HAVE_LONG_LONG
714
+ +unsigned long long rb_os_allocated_objects _((void));
715
+ +#else
716
+ +unsigned long rb_os_allocated_objects _((void));
717
+ +#endif
718
+ /* hash.c */
719
+ void st_foreach_safe _((struct st_table *, int (*)(ANYARGS), unsigned long));
720
+ void rb_hash_foreach _((VALUE, int (*)(ANYARGS), VALUE));