[#35719] Windows-31J <-> UTF-8 roundtrip — Tanaka Akira <akr@...>
以下のように Windows-31J と UTF-8 が roundtrip するかどうか
成瀬です。
In article <48932335.7010209@airemix.jp>,
成瀬です。
In article <48935EBD.3010603@airemix.jp>,
成瀬です。
[#35724] $SAFE=4の場合のReadline::HISTORY.each — Takao Kouji <kouji@...7.net>
knu さんへ
[#35726] "\x01\x00\x00\x00\x00\x00\x00\x21".encode("utf-8", "utf-32be", :invalid=>:replace) — Tanaka Akira <akr@...>
UTF-32BE で、文字として正しくない 4バイトと、文字として正し
[#35733] Re: [ruby-core:18078] We'll release 1.8.6/1.8.7 this Friday, #2 — Urabe Shyouhei <shyouhei@...>
というわけでそろそろリリースしようと思います。予定日は8月8日です。問題点
[#35745] [Bug:1.9] default_external depends on the order of -K and -E — sheepman <sh@...>
こんにちは sheepman です。
成瀬です。
Yuguiです。
[#35763] 文字コードがシンボルでないのは何故? — take_tk <ggb03124@...>
たけ(tk)です。
なかだです。
たけ(tk)です
[#35789] [Ruby 1.9 - Bug #407] (Open) String#<< — Shyouhei Urabe <redmine@...>
チケット #407 が報告されました。 (by Shyouhei Urabe)
まつもと ゆきひろです
Yukihiro Matsumoto さんは書きました:
まつもと ゆきひろです
成瀬です。
At 08:00 08/09/20, NARUSE, Yui wrote:
まつもと ゆきひろです
[#35811] fail to build extension libraries that includes some ruby header files — "Yusuke ENDOH" <mame@...>
遠藤です。
[#35834] 「サポートレベル」の定義、1.9.1のサポート予定プラットフォーム、メンテナ募集 — "Yugui (Yuki Sonoda)" <yugui@...>
Yuguiです。
[#35845] [Bug #437] test_strftime(TestTime) fails on Solaris — Shugo Maeda <redmine@...>
Bug #437: test_strftime(TestTime) fails on Solaris
前田です。
さとうふみやす @ OSS テクノロジです。
まつもと ゆきひろです
前田です。
まつもと ゆきひろです
前田です。
前田です。
まつもと ゆきひろです
前田です。
[#35851] [Feature:1.9] name referencing in sprintf — "Yusuke ENDOH" <mame@...>
遠藤です。
[#35863] Refactoring of enumerating prime numbers — "Yugui (Yuki Sonoda)" <yugui@...>
Yuguiです。
けいじゅ@いしつかです.
Yuguiです。
けいじゅ@いしつかです.
なかだです。
けいじゅ@いしつかです.
なかだです。
けいじゅ@いしつかです.
Yuguiです。
けいじゅ@いしつかです.
[#35899] [Bug #466] test_str_crypt(TestM17NComb) failed — Kazuhiro NISHIYAMA <redmine@...>
Bug #466: test_str_crypt(TestM17NComb) failed
[#35904] [Feature:1.9] pack format 'm' based on RFC 4648 — "Yusuke ENDOH" <mame@...>
遠藤です。
チケット #471 が更新されました。 (by Yuki Sonoda)
遠藤です。
In article <e0b1e5700809220338g5f3b5627p95e94744d5c10505@mail.gmail.com>,
遠藤です。
In article <e0b1e5700809231144n376fd4eencfe06c49ed66665e@mail.gmail.com>,
遠藤です。
[#35906] %N for Time#strftime — "Shugo Maeda" <shugo@...>
前田です。
In article <704d5db90808210811p7f3aef73h97913ade156323f3@mail.gmail.com>,
なかだです。
まつもと ゆきひろです
[#35922] [Bug #475] cgi.rbにNKFに依存したコードが入っている — Takeyuki Fujioka <redmine@...>
Bug #475: cgi.rbにNKFに依存したコードが入っている
[#35945] Re: [ruby-list:45386] Re: [ANN] REXMLのDoS脆弱性 — "Shugo Maeda" <shugo@...>
前田です。
前田です。
In message <704d5db90809010656k2042969bx3d8a4abdafeeea8e@mail.gmail.com>
[#35954] Re: [ruby-cvs:26052] Ruby:r18834 (trunk): * compile.c (defined_expr): should handle NODE_{AND,OR} as — SASADA Koichi <ko1@...>
ささだです.
まつもと ゆきひろです
ささだです.
まつもと ゆきひろです
ささだです.
まつもと ゆきひろです
[#35977] block parameter for Delagator — keiju@... (Keiju ISHITSUKA)
けいじゅ@いしつかです.
[#35986] 1.9と1.8で、delegateのインスタンスのクラス名の違う — Fujioka <fuj@...>
xibbarこと藤岡です。
まつもと ゆきひろです
けいじゅ@いしつかです.
藤岡です。
けいじゅ@いしつかです.
こんにちは、なかむら(う)です。
[#36008] [Bug #505] 1.upto 2 {|i| p i } — Shyouhei Urabe <redmine@...>
Bug #505: 1.upto 2 {|i| p i }
[#36028] [Bug #513] Tempfile yields [BUG] Stack consistency error — Shyouhei Urabe <redmine@...>
Bug #513: Tempfile yields [BUG] Stack consistency error
[#36033] [Bug #515] String#rindexが期待通りに動かない — Takeyuki Fujioka <redmine@...>
Bug #515: String#rindexが期待通りに動かない
[#36048] TypeError from Encoding.compatible? (r18920) — Yukihiro Matsumoto <matz@...>
まつもと ゆきひろです
[#36066] Numeric#scalar? — Tadayoshi Funaba <tadf@...>
1.9 の Numeric#scalar? について、適当でないのでは (real? などのほうがい
原です。
> やはり、scalar? はずれているんじゃないかな。real? の方がいい
原です。
> ここで、scalar? を疑問視する理由を復習すると、たとえば、「複
1.9.1 までに時間がないので scalar? だけ何とかしたいと思っていましたが、
前田です。
原です。
[ruby-dev:35806] Re: make profiler for gc
nariです。
返信ありがとうございます。
Yukihiro Matsumoto さんは書きました:
> いいんじゃないかと思いますが、これだとstatisticのキーはあいか
> わらずSymbolになってますね。すでに指摘したようにネストしたク
> ラスに対応するため、ここはClassそのものか、あるいは文字列がキー
> になるべきではないかと思います。
すみません。うっかりしていました。
その様に修正します。
Takao Kouji さんは書きました:
> これは、nari くんを含め、直接話をしたときに
> GC::Profiler.enabled? という案もでたのですが、
> どうでしょうかね。
すみません、これはruby-coreでも指摘された点で、
すでに手元では修正済みだったのでした。
指摘を頂いた点を修正しました。
== module,method
* GC::Profiler
Profiler用のモジュール
* GC::Profiler.enabled?
現在のステータスを返却
* GC::Profiler.enable
Profilerを有効化
* GC::Profiler.disable
Profilerを無効化
* GC::Profiler.clear
Profilerにて保持していたデータを削除
* GC::Profiler.report
Profile結果表示
* GC::Profiler.result
Profile結果を文字列で返却
* ObjectSpace.statistic
ObjectSpace内の統計を取ります。
戻り値 :
{:TOTAL=>10000, :FREE=>3011, "Foo::Bar"=>6, "Array"=>404, ...}
今回添付したパッチで問題なければコミットしたいと思います。
--
Narihiro Nakamura <authorNari@gmail.com>
Attachments (1)
Index: gc.c
===================================================================
--- gc.c (revision 18458)
+++ gc.c (working copy)
@@ -92,6 +92,133 @@
#undef GC_DEBUG
+/* for GC profile */
+#define GC_PROFILE_MORE_DETAIL 0
+typedef struct gc_profile_record {
+ double gc_time;
+ double gc_mark_time;
+ double gc_sweep_time;
+ double gc_invoke_time;
+ size_t heap_use_slots;
+ size_t heap_live_objects;
+ size_t heap_free_objects;
+ size_t heap_total_objects;
+ size_t heap_use_size;
+ size_t heap_total_size;
+ int have_finalize;
+ size_t allocate_increase;
+ size_t allocate_limit;
+} gc_profile_record;
+
+/* referenced document http://kzk9.net/column/time.html */
+static double
+getrusage_time(void)
+{
+ struct rusage usage;
+ struct timeval time;
+ getrusage(RUSAGE_SELF, &usage);
+ time = usage.ru_utime;
+ return time.tv_sec + time.tv_usec * 1e-6;
+}
+
+#define GC_PROF_TIMER_START do {\
+ if (objspace->profile.run) {\
+ if (!objspace->profile.record) {\
+ objspace->profile.size = 1000;\
+ objspace->profile.record = malloc(sizeof(gc_profile_record) * objspace->profile.size);\
+ }\
+ if (count >= objspace->profile.size) {\
+ objspace->profile.size += 1000;\
+ objspace->profile.record = realloc(objspace->profile.record, sizeof(gc_profile_record) * objspace->profile.size);\
+ }\
+ if (!objspace->profile.record) {\
+ rb_bug("gc_profile malloc or realloc miss");\
+ }\
+ MEMZERO(&objspace->profile.record[count], gc_profile_record, 1);\
+ gc_time = getrusage_time();\
+ objspace->profile.record[count].gc_invoke_time = gc_time - objspace->profile.invoke_time;\
+ }\
+ } while(0)
+
+#define GC_PROF_TIMER_STOP do {\
+ if (objspace->profile.run) {\
+ gc_time = getrusage_time() - gc_time;\
+ if(gc_time < 0) gc_time = 0;\
+ objspace->profile.record[count].gc_time = gc_time;\
+ objspace->profile.count++;\
+ }\
+ } while(0)
+
+#if GC_PROFILE_MORE_DETAIL
+#define INIT_GC_PROF_PARAMS double gc_time = 0, mark_time = 0, sweep_time = 0;\
+ size_t count = objspace->profile.count
+
+#define GC_PROF_MARK_TIMER_START do {\
+ if (objspace->profile.run) {\
+ mark_time = getrusage_time();\
+ }\
+ } while(0)
+
+#define GC_PROF_MARK_TIMER_STOP do {\
+ if (objspace->profile.run) {\
+ mark_time = getrusage_time() - mark_time;\
+ if (mark_time < 0) mark_time = 0;\
+ objspace->profile.record[count].gc_mark_time = mark_time;\
+ }\
+ } while(0)
+
+#define GC_PROF_SWEEP_TIMER_START do {\
+ if (objspace->profile.run) {\
+ sweep_time = getrusage_time();\
+ }\
+ } while(0)
+
+#define GC_PROF_SWEEP_TIMER_STOP do {\
+ if (objspace->profile.run) {\
+ sweep_time = getrusage_time() - sweep_time;\
+ if (sweep_time < 0) sweep_time = 0;\
+ objspace->profile.record[count].gc_sweep_time = sweep_time;\
+ }\
+ } while(0)
+#define GC_PROF_SET_MALLOC_INFO do {\
+ if (objspace->profile.run) {\
+ size_t count = objspace->profile.count;\
+ objspace->profile.record[count].allocate_increase = malloc_increase;\
+ objspace->profile.record[count].allocate_limit = malloc_limit; \
+ }\
+ } while(0)
+#define GC_PROF_SET_HEAP_INFO do {\
+ if (objspace->profile.run) {\
+ size_t count = objspace->profile.count;\
+ objspace->profile.record[count].heap_use_slots = heaps_used;\
+ objspace->profile.record[count].heap_live_objects = live;\
+ objspace->profile.record[count].heap_free_objects = freed;\
+ objspace->profile.record[count].heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
+ objspace->profile.record[count].have_finalize = final_list ? Qtrue : Qfalse;\
+ objspace->profile.record[count].heap_use_size = live * sizeof(RVALUE);\
+ objspace->profile.record[count].heap_total_size = heaps_used * (HEAP_OBJ_LIMIT * sizeof(RVALUE));\
+ }\
+ } while(0)
+
+#else
+#define INIT_GC_PROF_PARAMS double gc_time = 0;\
+ size_t count = objspace->profile.count
+#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_HEAP_INFO do {\
+ if (objspace->profile.run) {\
+ size_t count = objspace->profile.count;\
+ objspace->profile.record[count].heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
+ objspace->profile.record[count].heap_use_size = live * sizeof(RVALUE);\
+ objspace->profile.record[count].heap_total_size = heaps_used * HEAP_SIZE;\
+ }\
+ } while(0)
+#endif
+
+
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
#pragma pack(push, 1) /* magic for reducing sizeof(RVALUE): 24 -> 20 */
#endif
@@ -176,6 +303,13 @@
VALUE *ptr;
int overflow;
} markstack;
+ struct {
+ int run;
+ gc_profile_record *record;
+ size_t count;
+ size_t size;
+ double invoke_time;
+ } profile;
struct gc_list *global_list;
unsigned int count;
int gc_stress;
@@ -309,6 +443,73 @@
return bool;
}
+/*
+ * call-seq:
+ * GC::Profiler.enable? => true or false
+ *
+ * returns current status of GC profile mode.
+ */
+
+static VALUE
+gc_profile_enable_get(VALUE self)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ return objspace->profile.run;
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.enable => nil
+ *
+ * updates GC profile mode.
+ * start profiler for GC.
+ *
+ */
+
+static VALUE
+gc_profile_enable(void)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+
+ objspace->profile.run = Qtrue;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.disable => nil
+ *
+ * updates GC profile mode.
+ * stop profiler for GC.
+ *
+ */
+
+static VALUE
+gc_profile_disable(void)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+
+ objspace->profile.run = Qfalse;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.clear => nil
+ *
+ * clear before profile data.
+ *
+ */
+
+static VALUE
+gc_profile_clear(void)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ MEMZERO(objspace->profile.record, gc_profile_record, objspace->profile.size);
+ objspace->profile.count = 0;
+ return Qnil;
+}
+
static void *
vm_xmalloc(rb_objspace_t *objspace, size_t size)
{
@@ -634,6 +835,7 @@
assign_heap_slot(objspace);
}
heaps_inc = 0;
+ objspace->profile.invoke_time = getrusage_time();
}
@@ -1461,6 +1663,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;
@@ -1474,11 +1677,13 @@
/* clear finalization list */
if (final_list) {
+ GC_PROF_SET_HEAP_INFO;
deferred_final_list = final_list;
RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD());
}
else{
free_unused_heaps(objspace);
+ GC_PROF_SET_HEAP_INFO;
}
}
@@ -1706,6 +1911,7 @@
{
struct gc_list *list;
rb_thread_t *th = GET_THREAD();
+ INIT_GC_PROF_PARAMS;
if (GC_NOTIFY) printf("start garbage_collect()\n");
@@ -1725,6 +1931,8 @@
during_gc++;
objspace->count++;
+ GC_PROF_TIMER_START;
+ GC_PROF_MARK_TIMER_START;
SET_STACK_END;
init_mark_stack(objspace);
@@ -1765,9 +1973,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;
}
@@ -2354,6 +2566,7 @@
}
rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
+
for (i = 0; i <= T_MASK; i++) {
VALUE type;
switch (i) {
@@ -2395,6 +2608,88 @@
/*
* call-seq:
+ * ObjectSpace.statistic([result_hash]) -> hash
+ *
+ * Counts classes for each type.
+ *
+ * It returns a hash as:
+ * {:TOTAL=>10000, :FREE=>3011, "String"=>6, "Array"=>404, ...}
+ *
+ * If the optional argument, result_hash, is given,
+ * it is overwritten and returned.
+ * This is intended to avoid probe effect.
+ *
+ * The contents of the returned hash is implementation defined.
+ */
+
+VALUE
+statistic(int argc, VALUE *argv, VALUE os)
+{
+ VALUE hash;
+ rb_objspace_t *objspace = (&rb_objspace);
+ VALUE syms = rb_ary_new();
+ st_table *table;
+ st_data_t *cnt;
+ size_t free_objs= 0, total_objs = 0, i = 0;
+
+ if (rb_scan_args(argc, argv, "01", &hash) == 1) {
+ if (TYPE(hash) != T_HASH)
+ rb_raise(rb_eTypeError, "non-hash given");
+ }
+
+ table = st_init_numtable();
+ cnt = vm_xmalloc(objspace, sizeof(st_data_t));
+ for (i = 0; i < heaps_used; i++) {
+ RVALUE *p, *pend;
+ ID sym;
+
+ p = heaps[i].slot; pend = p + heaps[i].limit;
+ for (;p < pend; p++) {
+ *cnt = 1;
+ if (BUILTIN_TYPE(p) != 0 && BUILTIN_TYPE(p) != T_UNDEF &&
+ RBASIC(p)->klass && RBASIC(p)->flags) {
+ sym = rb_intern(rb_obj_classname((VALUE)p));
+ if (st_lookup(table, (st_data_t)sym, cnt)) {
+ *cnt = *cnt + 1;
+ st_insert(table, (st_data_t)sym, *cnt);
+ } else {
+ rb_ary_push(syms, ID2SYM(sym));
+ st_add_direct(table, (st_data_t)sym, *cnt);
+ }
+ }
+ else {
+ free_objs++;
+ }
+ }
+ total_objs += heaps[i].limit;
+ }
+
+ if (hash == Qnil) {
+ hash = rb_hash_new();
+ }
+ else if (!RHASH_EMPTY_P(hash)) {
+ st_foreach(RHASH_TBL(hash), set_zero, hash);
+ }
+
+ rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), rb_uint2inum(total_objs));
+ rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), rb_uint2inum(free_objs));
+
+ for (i = 0; i < RARRAY_LEN(syms); i++) {
+ VALUE sym;
+ sym = rb_ary_entry(syms, i);
+ if (st_lookup(table, (VALUE)SYM2ID(sym), cnt)) {
+ rb_hash_aset(hash, rb_str_new2(rb_id2name(SYM2ID(sym))), rb_uint2inum(*cnt));
+ }
+ }
+
+ vm_xfree(objspace, cnt);
+ st_free_table(table);
+
+ return hash;
+}
+
+/*
+ * call-seq:
* GC.count -> Integer
*
* The number of times GC occured.
@@ -2441,7 +2736,164 @@
}
#endif
+VALUE
+gc_profile_record_get(void)
+{
+ VALUE prof;
+ VALUE gc_profile = rb_ary_new();
+ size_t i;
+ rb_objspace_t *objspace = (&rb_objspace);
+
+ if (!objspace->profile.run) {
+ return Qnil;
+ }
+
+ for (i =0; i < objspace->profile.count; i++) {
+ prof = rb_hash_new();
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DOUBLE2NUM(objspace->profile.record[i].gc_time));
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DOUBLE2NUM(objspace->profile.record[i].gc_invoke_time));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), rb_uint2inum(objspace->profile.record[i].heap_use_size));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), rb_uint2inum(objspace->profile.record[i].heap_total_size));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_total_objects));
+#if GC_PROFILE_MORE_DETAIL
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DOUBLE2NUM(objspace->profile.record[i].gc_mark_time));
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DOUBLE2NUM(objspace->profile.record[i].gc_sweep_time));
+ rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), rb_uint2inum(objspace->profile.record[i].allocate_increase));
+ rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), rb_uint2inum(objspace->profile.record[i].allocate_limit));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SLOTS")), rb_uint2inum(objspace->profile.record[i].heap_use_slots));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_live_objects));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_free_objects));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), objspace->profile.record[i].have_finalize);
+#endif
+ rb_ary_push(gc_profile, prof);
+ }
+
+ return gc_profile;
+}
+
+static int
+hash_to_a(VALUE key, VALUE value, VALUE ary)
+{
+ if (key == Qundef) return ST_CONTINUE;
+ rb_ary_push(ary, rb_assoc_new(value, key));
+ return ST_CONTINUE;
+}
+
/*
+ * call-seq:
+ * GC::Profiler.result -> string
+ *
+ * Report profile data to string.
+ *
+ * It returns a string as:
+ * GC 1 invokes.
+ * Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC time(ms)
+ * 1 0.012 159240 212940 10647 0.00000000000001530000
+ *
+ *
+ * 2264 used objects 8375 free objects and 10639 total objects in Heap.
+ * Index Count % Kind (class)
+ * 1 1627 15.29279068 String
+ * 2 417 3.91954131 Class
+ * 3 81 0.76134975 Encoding
+ * 4 39 0.36657581 Foo::Bar
+ */
+
+VALUE
+gc_profile_result(void)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE record = gc_profile_record_get();
+ VALUE stc = statistic(0, 0, 0);
+ VALUE result = rb_str_new2("");
+ int i;
+ char buf[1024];
+
+ sprintf(buf, "GC %1$d invokes.\n", NUM2INT(gc_count(0)));
+ rb_str_concat(result, rb_str_new2(buf));
+ if(objspace->profile.run && objspace->profile.count) {
+ rb_str_concat(result, rb_str_new2("Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC Time(ms)\n"));
+ for(i = 0; i < (int)RARRAY_LEN(record); i++) {
+ memset(buf, 0, 1024);
+ VALUE r = RARRAY_PTR(record)[i];
+ sprintf(buf, "%1$5d %2$19.3f %3$20d %4$20d %5$20d %6$30.20f\n",
+ i+1, NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_INVOKE_TIME")))),
+ NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SIZE")))),
+ NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")))),
+ NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")))),
+ NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_TIME"))))*100);
+ rb_str_concat(result, rb_str_new2(buf));
+ }
+ rb_str_concat(result, rb_str_new2("\n\n"));
+#if GC_PROFILE_MORE_DETAIL
+ rb_str_concat(result, rb_str_new2("More detail.\n"));
+ rb_str_concat(result, rb_str_new2("Index Allocate Increase Allocate Limit Use Slot Have Finalize Mark Time(ms) Sweep Time(ms)\n"));
+ for(i = 0; i < (int)RARRAY_LEN(record); i++) {
+ memset(buf, 0, 1024);
+ VALUE r = RARRAY_PTR(record)[i];
+ sprintf(buf, "%1$5d %2$17d %3$17d %4$9d %5$14s %6$25.20f %7$25.20f\n",
+ i+1, NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_INCREASE")))),
+ NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_LIMIT")))),
+ NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SLOTS")))),
+ rb_hash_aref(r, ID2SYM(rb_intern("HAVE_FINALIZE")))? "true" : "false",
+ NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_MARK_TIME"))))*100,
+ NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_SWEEP_TIME"))))*100);
+ rb_str_concat(result, rb_str_new2(buf));
+ }
+ rb_str_concat(result, rb_str_new2("\n\n"));
+#endif
+ }
+ memset(buf, 0, 1024);
+ int total = NUM2INT(rb_hash_aref(stc, ID2SYM(rb_intern("TOTAL"))));
+ sprintf(buf, "%1$d used objects %2$d free objects and %3$d total objects in Heap.\n",
+ total - NUM2INT(rb_hash_aref(stc, ID2SYM(rb_intern("FREE")))),
+ NUM2INT(rb_hash_aref(stc, ID2SYM(rb_intern("FREE")))), total);
+ rb_str_concat(result, rb_str_new2(buf));
+ rb_str_concat(result, rb_str_new2("Index Count % Kind (class)\n"));
+ rb_hash_delete(stc, ID2SYM(rb_intern("FREE")));
+ rb_hash_delete(stc, ID2SYM(rb_intern("TOTAL")));
+
+ VALUE stc_ary = rb_ary_new();
+ rb_hash_foreach(stc, hash_to_a, stc_ary);
+ rb_ary_sort_bang(stc_ary);
+ rb_ary_reverse(stc_ary);
+ for(i = 0; i < (int)RARRAY_LEN(stc_ary); i++) {
+ VALUE s = RARRAY_PTR(stc_ary)[i];
+ memset(buf, 0, 1024);
+ sprintf(buf, "%1$5d %2$20d %3$20.8f %4$20s\n", i+1, NUM2INT(RARRAY_PTR(s)[0]),
+ NUM2DBL(RARRAY_PTR(s)[0])/total*100, StringValuePtr(RARRAY_PTR(s)[1]));
+ rb_str_concat(result, rb_str_new2(buf));
+ }
+ return result;
+}
+
+
+/*
+ * call-seq:
+ * GC::Profiler.report
+ *
+ * GC::Profiler.result display
+ *
+ */
+
+VALUE
+gc_profile_report(int argc, VALUE *argv, VALUE self)
+{
+ VALUE out;
+
+ if (argc == 0) {
+ out = rb_stdout;
+ }
+ else {
+ rb_scan_args(argc, argv, "01", &out);
+ }
+ rb_io_write(out, gc_profile_result());
+
+ return Qnil;
+}
+
+
+/*
* The <code>GC</code> module provides an interface to Ruby's mark and
* sweep garbage collection mechanism. Some of the underlying methods
* are also available via the <code>ObjectSpace</code> module.
@@ -2451,6 +2903,7 @@
Init_GC(void)
{
VALUE rb_mObSpace;
+ VALUE rb_mProfiler;
rb_mGC = rb_define_module("GC");
rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0);
@@ -2461,6 +2914,14 @@
rb_define_singleton_method(rb_mGC, "count", gc_count, 0);
rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
+ rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler");
+ rb_define_singleton_method(rb_mProfiler, "enabled?", gc_profile_enable_get, 0);
+ rb_define_singleton_method(rb_mProfiler, "enable", gc_profile_enable, 0);
+ rb_define_singleton_method(rb_mProfiler, "disable", gc_profile_disable, 0);
+ rb_define_singleton_method(rb_mProfiler, "clear", gc_profile_clear, 0);
+ rb_define_singleton_method(rb_mProfiler, "result", gc_profile_result, 0);
+ rb_define_singleton_method(rb_mProfiler, "report", gc_profile_report, -1);
+
rb_mObSpace = rb_define_module("ObjectSpace");
rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);
@@ -2480,6 +2941,7 @@
rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1);
+ rb_define_module_function(rb_mObSpace, "statistic", statistic, -1);
#if CALC_EXACT_MALLOC_SIZE
rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);