narie$B$G$9!#e(B
GCe$BMQ$N%W%m%U%!%$%i$r:n$j$^$7$?!#e(B
e$BLdBj$,L5$1$l$P%3%_%C%H$7$?$N$G$9$,!"$$$+$,$G$7$g$&$+!)e(B
nari
Index: gc.c
— gc.c (e$B%j%S%8%g%se(B 18054)
+++ gc.c (e$B:n6H%3%T!<e(B)
@@ -179,6 +179,10 @@
struct gc_list *global_list;
unsigned int count;
int gc_stress;
+#if GC_PROFILE
- gc_profile_data *gc_profile;
- size_t gc_profile_size;
+#endif
} rb_objspace_t;
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
@@ -212,6 +216,11 @@
#define need_call_final (finalizer_table &&
finalizer_table->num_entries)
+#if GC_PROFILE
+#define gc_profile objspace->gc_profile
+#define gc_profile_size objspace->gc_profile_size
+#endif
+
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
rb_objspace_t *
rb_objspace_alloc(void)
@@ -1440,6 +1449,7 @@
freed += n;
}
}
-
GC_PROF_SET_MALLOC_INFO;
if (malloc_increase > malloc_limit) {
malloc_limit += (malloc_increase - malloc_limit) * (double)live /
(live + freed);
if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
@@ -1453,10 +1463,12 @@/* clear finalization list */
if (final_list) { -
GC_PROF_SET_INFO;
deferred_final_list = final_list;
return;
}
free_unused_heaps(objspace); -
GC_PROF_SET_INFO;
}
void
@@ -1672,6 +1684,7 @@
{
struct gc_list *list;
rb_thread_t *th = GET_THREAD();
-
INIT_GC_PROF_PARAMS;
if (GC_NOTIFY) printf(“start garbage_collect()\n”);
@@ -1691,6 +1704,8 @@
during_gc++;
objspace->count++;
-
GC_PROF_TIMER_START;
-
GC_PROF_MARK_TIMER_START;
SET_STACK_END;init_mark_stack(objspace);
@@ -1731,9 +1746,13 @@
gc_mark_rest(objspace);
}
} -
GC_PROF_MARK_TIMER_STOP;
-
GC_PROF_SWEEP_TIMER_START;
gc_sweep(objspace); -
GC_PROF_SWEEP_TIMER_STOP;
-
GC_PROF_TIMER_STOP;
if (GC_NOTIFY) printf(“end garbage_collect()\n”);
return Qtrue;
}
@@ -2386,6 +2405,36 @@
}
#endif
+#if GC_PROFILE
+VALUE
+gc_profile_report(void)
+{
- VALUE prof = 0;
- VALUE res = rb_hash_new();
- VALUE datas = rb_ary_new();
- size_t i;
- rb_objspace_t *objspace = (&rb_objspace);
- for (i =0; i < objspace->count; i++) {
- prof = rb_hash_new();
-
rb_hash_aset(prof, rb_str_new2("gc_time"),
DOUBLE2NUM(gc_profile[i]._gc_time));
-
rb_hash_aset(prof, rb_str_new2("gc_mark_time"),
DOUBLE2NUM(gc_profile[i]._gc_mark_time));
- rb_hash_aset(prof, rb_str_new2(“gc_sweep_time”),
DOUBLE2NUM(gc_profile[i]._gc_sweep_time)); -
rb_hash_aset(prof, rb_str_new2("heaps_used"),
rb_uint2inum(gc_profile[i]._heaps_used));
-
rb_hash_aset(prof, rb_str_new2("live"),
rb_uint2inum(gc_profile[i]._live));
-
rb_hash_aset(prof, rb_str_new2("freed"),
rb_uint2inum(gc_profile[i]._freed));
-
rb_hash_aset(prof, rb_str_new2("heap_objects"),
rb_uint2inum(gc_profile[i]._heap_objects));
-
rb_hash_aset(prof, rb_str_new2("is_exist_finalize"),
gc_profile[i]._is_exist_finalize);
-
rb_hash_aset(prof, rb_str_new2("malloc_increase"),
rb_uint2inum(gc_profile[i]._malloc_increase));
-
rb_hash_aset(prof, rb_str_new2("malloc_limit"),
rb_uint2inum(gc_profile[i]._malloc_limit));
- rb_ary_push(datas, prof);
- }
- rb_hash_aset(res, rb_str_new2(“count”),
rb_uint2inum(objspace->count)); - rb_hash_aset(res, rb_str_new2(“report”), datas);
- return res;
+}
+#endif
/*
- The
GC
module provides an interface to Ruby’s mark and - sweep garbage collection mechanism. Some of the underlying methods
@@ -2430,4 +2479,7 @@
rb_define_singleton_method(rb_mGC, “malloc_allocated_size”,
gc_malloc_allocated_size, 0);
rb_define_singleton_method(rb_mGC, “malloc_allocations”,
gc_malloc_allocations, 0);
#endif
+#if GC_PROFILE
- rb_define_singleton_method(rb_mGC, “profile_report”,
gc_profile_report, 0);
+#endif
}
Index: gc.h
===================================================================
— gc.h (e$B%j%S%8%g%se(B 18054)
+++ gc.h (e$B:n6H%3%T!<e(B)
@@ -72,4 +72,102 @@
define STACK_UPPER(x, a, b) (stack_growup_p(x) ? a : b)
#endif
+/* for GC profile */
+#define GC_PROFILE 0
+#if GC_PROFILE
+
+typedef struct gc_profile_data {
- double _gc_time;
- double _gc_mark_time;
- double _gc_sweep_time;
- size_t _heaps_used;
- size_t _live;
- size_t _freed;
- size_t _heap_objects;
- int _is_exist_finalize;
- size_t _malloc_increase;
- size_t _malloc_limit;
+} gc_profile_data;
+static double
+cputime(void)
+{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec + (double)tv.tv_usec*1e-6;
+}
+#define INIT_GC_PROF_PARAMS double gc_time = 0, mark_time = 0,
sweep_time = 0;\
- size_t count = objspace->count\
+#define GC_PROF_TIMER_START do {\
- if (!gc_profile) {\
-
gc_profile_size = 1000;\
- gc_profile = malloc(sizeof(gc_profile_data) * gc_profile_size);\
- }\
- if (count >= gc_profile_size) {\
-
gc_profile_size += 1000;\
- gc_profile = realloc(gc_profile, sizeof(gc_profile_data) *
gc_profile_size);\ - }\
- if (!gc_profile) {\
- rb_bug(“gc_profile malloc or realloc miss”);\
- }\
- MEMZERO(&gc_profile[count], gc_profile_data, 1);\
- gc_time = cputime();
+} while(0)
+#define GC_PROF_TIMER_STOP do {\
- gc_time = cputime() - gc_time;\
- gc_profile[count]._gc_time = gc_time;
+} while(0)
+#define GC_PROF_MARK_TIMER_START do {\
- mark_time = cputime();
+} while(0)
+#define GC_PROF_MARK_TIMER_STOP do {\
- mark_time = cputime() - mark_time;\
- gc_profile[count]._gc_mark_time = mark_time;
+} while(0)
+#define GC_PROF_SWEEP_TIMER_START do {\
- sweep_time = cputime();
+} while(0)
+#define GC_PROF_SWEEP_TIMER_STOP do {\
- sweep_time = cputime() - sweep_time;\
- gc_profile[count]._gc_sweep_time = sweep_time;
+} while(0)
+#define GC_PROF_SET_MALLOC_INFO do {\
- size_t count = objspace->count - 1;\
- gc_profile[count]._malloc_increase = malloc_increase;\
- gc_profile[count]._malloc_limit = malloc_limit;
+} while(0)
+#define GC_PROF_SET_INFO do {\
- size_t count = objspace->count - 1;\
- gc_profile[count]._heaps_used = heaps_used;\
- gc_profile[count]._live = live;\
- gc_profile[count]._freed = freed;\
- gc_profile[count]._heap_objects = heaps_used * HEAP_OBJ_LIMIT;\
- gc_profile[count]._is_exist_finalize = final_list ? Qtrue : Qfalse;
+} while(0)
+#else
+#define INIT_GC_PROF_PARAMS
+#define GC_PROF_TIMER_START
+#define GC_PROF_TIMER_STOP
+#define GC_PROF_MARK_TIMER_START
+#define GC_PROF_MARK_TIMER_STOP
+#define GC_PROF_SWEEP_TIMER_START
+#define GC_PROF_SWEEP_TIMER_STOP
+#define GC_PROF_SET_MALLOC_INFO
+#define GC_PROF_SET_INFO
+#endif
+
+
#endif /* RUBY_GC_H */
+
+