ささだです. 現在の GC 関連の状態を表示するためのメソッド GC.stat を追加するのはど うでしょうか. {:count=>1, # これまで GC が起こった回数 :elapsed_time=>0.004, # これまで GC にかかったユーザ時間 :heap_used=>20, # 利用中の heap の数 :heap_length=>22, # 確保した heap の数 :heap_live_slot=>4742, # 生きている slot の数 (*1) :heap_free_slot=>5056, # 空いている slot の数 (*1) :heap_waiting_finalize_slot=>23} # ファイナライザを待っている slot の数 *1: 一番最後の GC でカウント. # Gauche では gc-stat というものがある,と shiro さんに聞いたもので. gosh> (gc-stat) ((:total-heap-size 786432) (:free-bytes 163840) (:bytes-since-gc 532376) (:total-bytes 532352)) Index: gc.c =================================================================== --- gc.c (リビジョン 23689) +++ gc.c (作業コピー) @@ -323,6 +323,9 @@ typedef struct rb_objspace { size_t length; size_t used; size_t longlife_used; + size_t total_live_slot; + size_t total_free_slot; + size_t total_waiting_finalize_slot; RVALUE *freelist; RVALUE *longlife_freelist; RVALUE *range[2]; @@ -355,7 +358,8 @@ typedef struct rb_objspace { double invoke_time; } profile; struct gc_list *global_list; - unsigned int count; + size_t count; + double elapsed_time; int gc_stress; } rb_objspace_t; @@ -933,7 +937,8 @@ assign_heap_slot(rb_objspace_t *objspace if (lomem == 0 || lomem > p) lomem = p; if (himem < pend) himem = pend; if (lifetime == lifetime_longlife) objspace->heap.longlife_used++; - heaps_used++; + objspace->heap.used++; + objspace->heap.total_free_slot += objs; while (p < pend) { p->as.free.flags = 0; @@ -1832,7 +1837,7 @@ static void gc_sweep(rb_objspace_t *objspace) { RVALUE *p, *pend, *final_list; - size_t freed = 0; + size_t freed = 0, waiting_finalize = 0; size_t i; size_t live = 0, free_min = 0, do_heap_free = 0; @@ -1868,6 +1873,7 @@ gc_sweep(rb_objspace_t *objspace) p->as.free.next = final_list; final_list = p; final_num++; + waiting_finalize++; } else { add_freelist(objspace, &freelist, p); @@ -1877,6 +1883,7 @@ gc_sweep(rb_objspace_t *objspace) else if (BUILTIN_TYPE(p) == T_ZOMBIE) { /* objects to be finalized */ /* do nothing remain marked */ + waiting_finalize++; } else { RBASIC(p)->flags &= ~FL_MARK; @@ -1923,6 +1930,10 @@ gc_sweep(rb_objspace_t *objspace) free_unused_heaps(objspace); GC_PROF_SET_HEAP_INFO; } + + objspace->heap.total_live_slot = live; + objspace->heap.total_free_slot = freed; + objspace->heap.total_waiting_finalize_slot = waiting_finalize; } static void @@ -2207,6 +2218,8 @@ garbage_collect(rb_objspace_t *objspace) { struct gc_list *list; rb_thread_t *th = GET_THREAD(); + double invoke_time = getrusage_time(); + INIT_GC_PROF_PARAMS; if (GC_NOTIFY) printf("start garbage_collect()\n"); @@ -2286,6 +2299,8 @@ garbage_collect(rb_objspace_t *objspace) GC_PROF_TIMER_STOP; if (GC_NOTIFY) printf("end garbage_collect()\n"); + objspace->elapsed_time += getrusage_time() - invoke_time; + return Qtrue; } @@ -2950,6 +2965,33 @@ gc_count(VALUE self) return UINT2NUM((&rb_objspace)->count); } +/* + * call-seq: + * GC.stat -> Hash + * + * Return information about GC. + * + * It returns several information about GC: + * total count, elapesed time, heap size, and so on. + * + */ +static VALUE +gc_stat(VALUE self) +{ + VALUE hash = rb_hash_new(); + rb_objspace_t *objspace = &rb_objspace; + + rb_hash_aset(hash, ID2SYM(rb_intern("count")), SIZET2NUM(objspace->count)); + rb_hash_aset(hash, ID2SYM(rb_intern("elapsed_time")), DBL2NUM(objspace->elapsed_time)); + rb_hash_aset(hash, ID2SYM(rb_intern("heap_used")), SIZET2NUM(objspace->heap.used)); + rb_hash_aset(hash, ID2SYM(rb_intern("heap_length")), SIZET2NUM(objspace->heap.length)); + rb_hash_aset(hash, ID2SYM(rb_intern("heap_live_slot")), SIZET2NUM(objspace->heap.total_live_slot)); + rb_hash_aset(hash, ID2SYM(rb_intern("heap_free_slot")), SIZET2NUM(objspace->heap.total_free_slot)); + rb_hash_aset(hash, ID2SYM(rb_intern("heap_waiting_finalize_slot")), SIZET2NUM(objspace->heap.total_waiting_finalize_slot)); + + return hash; +} + #if CALC_EXACT_MALLOC_SIZE /* * call-seq: @@ -3122,6 +3164,7 @@ Init_GC(void) rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0); rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1); rb_define_singleton_method(rb_mGC, "count", gc_count, 0); + rb_define_singleton_method(rb_mGC, "stat", gc_stat, 0); rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler"); -- // SASADA Koichi at atdot dot net