railsbench 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
data/ruby185gc.patch ADDED
@@ -0,0 +1,535 @@
1
+ --- gc.c.orig 2006-10-30 04:35:55.000000000 +0100
2
+ +++ gc.c 2006-11-06 20:25:12.562500000 +0100
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
+ @@ -159,8 +166,17 @@
29
+ RUBY_CRITICAL(free(x));
30
+ }
31
+
32
+ +#if HAVE_LONG_LONG
33
+ +#define GC_TIME_TYPE LONG_LONG
34
+ +#else
35
+ +#define GC_TIME_TYPE long
36
+ +#endif
37
+ +
38
+ extern int ruby_in_compile;
39
+ static int dont_gc;
40
+ +static int gc_statistics = 0;
41
+ +static GC_TIME_TYPE gc_time = 0;
42
+ +static int gc_collections = 0;
43
+ static int during_gc;
44
+ static int need_call_final = 0;
45
+ static st_table *finalizer_table = 0;
46
+ @@ -195,7 +211,7 @@
47
+ * Disables garbage collection, returning <code>true</code> if garbage
48
+ * collection was already disabled.
49
+ *
50
+ - * GC.disable #=> false
51
+ + * GC.disable #=> false or true
52
+ * GC.disable #=> true
53
+ *
54
+ */
55
+ @@ -209,6 +225,104 @@
56
+ return old;
57
+ }
58
+
59
+ +/*
60
+ + * call-seq:
61
+ + * GC.enable_stats => true or false
62
+ + *
63
+ + * Enables garbage collection statistics, returning <code>true</code> if garbage
64
+ + * collection statistics was already enabled.
65
+ + *
66
+ + * GC.enable_stats #=> false or true
67
+ + * GC.enable_stats #=> true
68
+ + *
69
+ + */
70
+ +
71
+ +VALUE
72
+ +rb_gc_enable_stats()
73
+ +{
74
+ + int old = gc_statistics;
75
+ + gc_statistics = Qtrue;
76
+ + return old;
77
+ +}
78
+ +
79
+ +/*
80
+ + * call-seq:
81
+ + * GC.disable_stats => true or false
82
+ + *
83
+ + * Disables garbage collection statistics, returning <code>true</code> if garbage
84
+ + * collection statistics was already disabled.
85
+ + *
86
+ + * GC.disable_stats #=> false or true
87
+ + * GC.disable_stats #=> true
88
+ + *
89
+ + */
90
+ +
91
+ +VALUE
92
+ +rb_gc_disable_stats()
93
+ +{
94
+ + int old = gc_statistics;
95
+ + gc_statistics = Qfalse;
96
+ + return old;
97
+ +}
98
+ +
99
+ +/*
100
+ + * call-seq:
101
+ + * GC.clear_stats => nil
102
+ + *
103
+ + * Clears garbage collection statistics, returning nil. This resets the number
104
+ + * of collections (GC.collections) and the time used (GC.time) to 0.
105
+ + *
106
+ + * GC.clear_stats #=> nil
107
+ + *
108
+ + */
109
+ +
110
+ +VALUE
111
+ +rb_gc_clear_stats()
112
+ +{
113
+ + gc_collections = 0;
114
+ + gc_time = 0;
115
+ + return Qnil;
116
+ +}
117
+ +
118
+ +/*
119
+ + * call-seq:
120
+ + * GC.collections => Integer
121
+ + *
122
+ + * Returns the number of garbage collections performed while GC statistics collection
123
+ + * was enabled.
124
+ + *
125
+ + * GC.collections #=> 35
126
+ + *
127
+ + */
128
+ +
129
+ +VALUE
130
+ +rb_gc_collections()
131
+ +{
132
+ + return INT2NUM(gc_collections);
133
+ +}
134
+ +
135
+ +/*
136
+ + * call-seq:
137
+ + * GC.time => Integer
138
+ + *
139
+ + * Returns the time spent during garbage collection while GC statistics collection
140
+ + * was enabled (in micro seconds).
141
+ + *
142
+ + * GC.time #=> 20000
143
+ + *
144
+ + */
145
+ +
146
+ +VALUE
147
+ +rb_gc_time()
148
+ +{
149
+ +#if HAVE_LONG_LONG
150
+ + return LL2NUM(gc_time);
151
+ +#else
152
+ + return LONG2NUM(gc_time);
153
+ +#endif
154
+ +}
155
+ +
156
+ +
157
+ VALUE rb_mGC;
158
+
159
+ static struct gc_list {
160
+ @@ -300,7 +414,7 @@
161
+ static RVALUE *freelist = 0;
162
+ static RVALUE *deferred_final_list = 0;
163
+
164
+ -#define HEAPS_INCREMENT 10
165
+ +static int heaps_increment = 10;
166
+ static struct heaps_slot {
167
+ void *membase;
168
+ RVALUE *slot;
169
+ @@ -309,13 +423,141 @@
170
+ static int heaps_length = 0;
171
+ static int heaps_used = 0;
172
+
173
+ -#define HEAP_MIN_SLOTS 10000
174
+ -static int heap_slots = HEAP_MIN_SLOTS;
175
+ +static int heap_min_slots = 10000;
176
+ +static int heap_slots = 10000;
177
+ +
178
+ +static int heap_free_min = 4096;
179
+ +
180
+ +static long initial_malloc_limit = GC_MALLOC_LIMIT;
181
+
182
+ -#define FREE_MIN 4096
183
+ +static int verbose_gc_stats = Qfalse;
184
+ +
185
+ +static FILE* gc_data_file = NULL;
186
+
187
+ static RVALUE *himem, *lomem;
188
+
189
+ +static void set_gc_parameters()
190
+ +{
191
+ + char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr,
192
+ + *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr;
193
+ +
194
+ + gc_data_file = stderr;
195
+ +
196
+ + gc_stats_ptr = getenv("RUBY_GC_STATS");
197
+ + if (gc_stats_ptr != NULL) {
198
+ + int gc_stats_i = atoi(gc_stats_ptr);
199
+ + if (gc_stats_i > 0) {
200
+ + verbose_gc_stats = Qtrue;
201
+ + }
202
+ + }
203
+ +
204
+ + gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE");
205
+ + if (gc_heap_file_ptr != NULL) {
206
+ + FILE* data_file = fopen(gc_heap_file_ptr, "w");
207
+ + if (data_file != NULL) {
208
+ + gc_data_file = data_file;
209
+ + }
210
+ + else {
211
+ + fprintf(stderr,
212
+ + "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr);
213
+ + }
214
+ + }
215
+ +
216
+ + min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
217
+ + if (min_slots_ptr != NULL) {
218
+ + int min_slots_i = atoi(min_slots_ptr);
219
+ + if (verbose_gc_stats) {
220
+ + fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr);
221
+ + }
222
+ + if (min_slots_i > 0) {
223
+ + heap_slots = min_slots_i;
224
+ + heap_min_slots = min_slots_i;
225
+ + }
226
+ + }
227
+ +
228
+ + free_min_ptr = getenv("RUBY_HEAP_FREE_MIN");
229
+ + if (free_min_ptr != NULL) {
230
+ + int free_min_i = atoi(free_min_ptr);
231
+ + if (verbose_gc_stats) {
232
+ + fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr);
233
+ + }
234
+ + if (free_min_i > 0) {
235
+ + heap_free_min = free_min_i;
236
+ + }
237
+ + }
238
+ +
239
+ + heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT");
240
+ + if (heap_incr_ptr != NULL) {
241
+ + int heap_incr_i = atoi(heap_incr_ptr);
242
+ + if (verbose_gc_stats) {
243
+ + fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr);
244
+ + }
245
+ + if (heap_incr_i > 0) {
246
+ + heaps_increment = heap_incr_i;
247
+ + }
248
+ + }
249
+ +
250
+ + malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
251
+ + if (malloc_limit_ptr != NULL) {
252
+ + int malloc_limit_i = atol(malloc_limit_ptr);
253
+ + if (verbose_gc_stats) {
254
+ + fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr);
255
+ + }
256
+ + if (malloc_limit_i > 0) {
257
+ + initial_malloc_limit = malloc_limit_i;
258
+ + }
259
+ + }
260
+ +}
261
+ +
262
+ +/*
263
+ + * call-seq:
264
+ + * GC.dump => nil
265
+ + *
266
+ + * dumps information about the current GC data structures to the GC log file
267
+ + *
268
+ + * GC.dump #=> nil
269
+ + *
270
+ + */
271
+ +
272
+ +VALUE
273
+ +rb_gc_dump()
274
+ +{
275
+ + int i;
276
+ +
277
+ + for (i = 0; i < heaps_used; i++) {
278
+ + int heap_size = heaps[i].limit;
279
+ + fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size);
280
+ + }
281
+ +
282
+ + return Qnil;
283
+ +}
284
+ +
285
+ +/*
286
+ + * call-seq:
287
+ + * GC.log String => String
288
+ + *
289
+ + * Logs string to the GC data file and returns it.
290
+ + *
291
+ + * GC.log "manual GC call" #=> "manual GC call"
292
+ + *
293
+ + */
294
+ +
295
+ +VALUE
296
+ +rb_gc_log(self, original_str)
297
+ + VALUE self, original_str;
298
+ +{
299
+ + if (original_str == Qnil) {
300
+ + fprintf(gc_data_file, "\n");
301
+ + }
302
+ + else {
303
+ + VALUE str = StringValue(original_str);
304
+ + char *p = RSTRING(str)->ptr;
305
+ + fprintf(gc_data_file, "%s\n", p);
306
+ + }
307
+ + return original_str;
308
+ +}
309
+ +
310
+ +
311
+ static void
312
+ add_heap()
313
+ {
314
+ @@ -326,7 +568,7 @@
315
+ struct heaps_slot *p;
316
+ int length;
317
+
318
+ - heaps_length += HEAPS_INCREMENT;
319
+ + heaps_length += heaps_increment;
320
+ length = heaps_length*sizeof(struct heaps_slot);
321
+ RUBY_CRITICAL(
322
+ if (heaps_used > 0) {
323
+ @@ -342,10 +584,10 @@
324
+ for (;;) {
325
+ RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
326
+ if (p == 0) {
327
+ - if (heap_slots == HEAP_MIN_SLOTS) {
328
+ + if (heap_slots == heap_min_slots) {
329
+ rb_memerror();
330
+ }
331
+ - heap_slots = HEAP_MIN_SLOTS;
332
+ + heap_slots = heap_min_slots;
333
+ continue;
334
+ }
335
+ heaps[heaps_used].membase = p;
336
+ @@ -362,7 +604,7 @@
337
+ if (himem < pend) himem = pend;
338
+ heaps_used++;
339
+ heap_slots *= 1.8;
340
+ - if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
341
+ + if (heap_slots <= 0) heap_slots = heap_min_slots;
342
+
343
+ while (p < pend) {
344
+ p->as.free.flags = 0;
345
+ @@ -1015,6 +1257,39 @@
346
+ }
347
+ }
348
+
349
+ +static char* obj_type(int tp)
350
+ +{
351
+ + switch (tp) {
352
+ + case T_NIL : return "NIL";
353
+ + case T_OBJECT : return "OBJECT";
354
+ + case T_CLASS : return "CLASS";
355
+ + case T_ICLASS : return "ICLASS";
356
+ + case T_MODULE : return "MODULE";
357
+ + case T_FLOAT : return "FLOAT";
358
+ + case T_STRING : return "STRING";
359
+ + case T_REGEXP : return "REGEXP";
360
+ + case T_ARRAY : return "ARRAY";
361
+ + case T_FIXNUM : return "FIXNUM";
362
+ + case T_HASH : return "HASH";
363
+ + case T_STRUCT : return "STRUCT";
364
+ + case T_BIGNUM : return "BIGNUM";
365
+ + case T_FILE : return "FILE";
366
+ +
367
+ + case T_TRUE : return "TRUE";
368
+ + case T_FALSE : return "FALSE";
369
+ + case T_DATA : return "DATA";
370
+ + case T_MATCH : return "MATCH";
371
+ + case T_SYMBOL : return "SYMBOL";
372
+ +
373
+ + case T_BLKTAG : return "BLKTAG";
374
+ + case T_UNDEF : return "UNDEF";
375
+ + case T_VARMAP : return "VARMAP";
376
+ + case T_SCOPE : return "SCOPE";
377
+ + case T_NODE : return "NODE";
378
+ + default: return "____";
379
+ + }
380
+ +}
381
+ +
382
+ static void
383
+ free_unused_heaps()
384
+ {
385
+ @@ -1045,12 +1320,21 @@
386
+ unsigned long live = 0;
387
+ unsigned long free_min = 0;
388
+
389
+ + unsigned long really_freed = 0;
390
+ + int free_counts[256];
391
+ + int live_counts[256];
392
+ + int do_gc_stats = gc_statistics & verbose_gc_stats;
393
+ +
394
+ for (i = 0; i < heaps_used; i++) {
395
+ free_min += heaps[i].limit;
396
+ }
397
+ free_min = free_min * 0.2;
398
+ - if (free_min < FREE_MIN)
399
+ - free_min = FREE_MIN;
400
+ + if (free_min < heap_free_min)
401
+ + free_min = heap_free_min;
402
+ +
403
+ + if (do_gc_stats) {
404
+ + for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; }
405
+ + }
406
+
407
+ if (ruby_in_compile && ruby_parser_stack_on_heap()) {
408
+ /* should not reclaim nodes during compilation
409
+ @@ -1083,6 +1367,9 @@
410
+ if (!(p->as.basic.flags & FL_MARK)) {
411
+ if (p->as.basic.flags) {
412
+ obj_free((VALUE)p);
413
+ + if (do_gc_stats) {
414
+ + really_freed++;
415
+ + }
416
+ }
417
+ if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
418
+ p->as.free.flags = FL_MARK; /* remain marked */
419
+ @@ -1090,6 +1377,12 @@
420
+ final_list = p;
421
+ }
422
+ else {
423
+ + if (do_gc_stats) {
424
+ + int obt = p->as.basic.flags & T_MASK;
425
+ + if (obt) {
426
+ + free_counts[obt]++;
427
+ + }
428
+ + }
429
+ p->as.free.flags = 0;
430
+ p->as.free.next = freelist;
431
+ freelist = p;
432
+ @@ -1103,6 +1396,9 @@
433
+ else {
434
+ RBASIC(p)->flags &= ~FL_MARK;
435
+ live++;
436
+ + if (do_gc_stats) {
437
+ + live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++;
438
+ + }
439
+ }
440
+ p++;
441
+ }
442
+ @@ -1121,7 +1417,7 @@
443
+ }
444
+ if (malloc_increase > malloc_limit) {
445
+ malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
446
+ - if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
447
+ + if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
448
+ }
449
+ malloc_increase = 0;
450
+ if (freed < free_min) {
451
+ @@ -1129,6 +1425,20 @@
452
+ }
453
+ during_gc = 0;
454
+
455
+ + if (do_gc_stats) {
456
+ + fprintf(gc_data_file, "objects processed: %.7d\n", live+freed);
457
+ + fprintf(gc_data_file, "live objects : %.7d\n", live);
458
+ + fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed);
459
+ + fprintf(gc_data_file, "freed objects : %.7d\n", really_freed);
460
+ + for(i=0; i<256; i++) {
461
+ + if (free_counts[i]>0) {
462
+ + fprintf(gc_data_file,
463
+ + "kept %.7d / freed %.7d objects of type %s\n",
464
+ + live_counts[i], free_counts[i], obj_type(i));
465
+ + }
466
+ + }
467
+ + }
468
+ +
469
+ /* clear finalization list */
470
+ if (final_list) {
471
+ deferred_final_list = final_list;
472
+ @@ -1323,6 +1633,7 @@
473
+ struct gc_list *list;
474
+ struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
475
+ jmp_buf save_regs_gc_mark;
476
+ + struct timeval gctv1, gctv2;
477
+ SET_STACK_END;
478
+
479
+ #ifdef HAVE_NATIVETHREAD
480
+ @@ -1339,6 +1650,14 @@
481
+ if (during_gc) return;
482
+ during_gc++;
483
+
484
+ + if (gc_statistics) {
485
+ + gc_collections++;
486
+ + gettimeofday(&gctv1, NULL);
487
+ + if (verbose_gc_stats) {
488
+ + fprintf(gc_data_file, "Garbage collection started\n");
489
+ + }
490
+ + }
491
+ +
492
+ init_mark_stack();
493
+
494
+ gc_mark((VALUE)ruby_current_node, 0);
495
+ @@ -1414,6 +1733,17 @@
496
+ } while (!MARK_STACK_EMPTY);
497
+
498
+ gc_sweep();
499
+ +
500
+ + if (gc_statistics) {
501
+ + GC_TIME_TYPE musecs_used;
502
+ + gettimeofday(&gctv2, NULL);
503
+ + musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec);
504
+ + gc_time += musecs_used;
505
+ +
506
+ + if (verbose_gc_stats) {
507
+ + fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000);
508
+ + }
509
+ + }
510
+ }
511
+
512
+ void
513
+ @@ -1582,6 +1912,7 @@
514
+ if (!rb_gc_stack_start) {
515
+ Init_stack(0);
516
+ }
517
+ + set_gc_parameters();
518
+ add_heap();
519
+ }
520
+
521
+ @@ -2051,6 +2382,14 @@
522
+ rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
523
+ rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
524
+
525
+ + rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0);
526
+ + rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0);
527
+ + rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0);
528
+ + rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0);
529
+ + rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0);
530
+ + rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0);
531
+ + rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1);
532
+ +
533
+ rb_mObSpace = rb_define_module("ObjectSpace");
534
+ rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
535
+ rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);