[#17566] rubychecker - runs checks on a Ruby interpreter — Igal Koshevoy <igal@...>

I've put together a shell script that runs checks on a Ruby interpreter.

14 messages 2008/07/03

[#17615] [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nathan Weizenbaum <nex342@...>

At the moment, ruby-mode.el uses font-lock-keywords as opposed to

22 messages 2008/07/05
[#17657] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Yukihiro Matsumoto <matz@...> 2008/07/08

[#17678] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nathan Weizenbaum <nex342@...> 2008/07/09

It was designed to fix the following case:

[#17755] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nathan Weizenbaum <nex342@...> 2008/07/13

Here's a third patch that fixes a bug in the second and uses a quicker

[#17772] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nathan Weizenbaum <nex342@...> 2008/07/15

One more patch which fixes a few bugs in the the last one.

[#17773] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nobuyoshi Nakada <nobu@...> 2008/07/15

Hi,

[#17776] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nathan Weizenbaum <nex342@...> 2008/07/15

Looks like version 22 doesn't support explicitly numbered regexp groups.

[#17779] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nobuyoshi Nakada <nobu@...> 2008/07/15

Hi,

[#17783] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nobuyoshi Nakada <nobu@...> 2008/07/15

Hi,

[#17788] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nathan Weizenbaum <nex342@...> 2008/07/15

Alright, here's a version that fixes both the highlighting bug and the

[#17793] Re: [PATCH] ruby-mode.el: Fix here-doc strings with inner quotes — Nobuyoshi Nakada <nobu@...> 2008/07/16

Hi,

[#17644] Features to be included in Ruby 1.9.1 — "Yugui (Yuki Sonoda)" <yugui@...>

Hi, all

27 messages 2008/07/08

[#17674] [Ruby 1.8 - Bug #238] (Open) Ruby doesn't respect the Windows read-only flag — Jim Deville <redmine@...>

Issue #238 has been reported by Jim Deville.

10 messages 2008/07/08

[#17708] [Ruby 1.8 - Bug #252] (Open) Array#sort doesn't respect overridden <=> — Ryan Davis <redmine@...>

Issue #252 has been reported by Ryan Davis.

13 messages 2008/07/09

[#17871] duping the NilClass — "Nasir Khan" <rubylearner@...>

While nil is an object, calling dup on it causes TypeError. This doesnt seem

33 messages 2008/07/20
[#17872] Re: duping the NilClass — Urabe Shyouhei <shyouhei@...> 2008/07/20

Nasir Khan wrote:

[#17873] Re: duping the NilClass — "Meinrad Recheis" <meinrad.recheis@...> 2008/07/20

On Sun, Jul 20, 2008 at 7:55 PM, Urabe Shyouhei <shyouhei@ruby-lang.org>

[#17877] Re: duping the NilClass — Urabe Shyouhei <shyouhei@...> 2008/07/20

Meinrad Recheis wrote:

[#17879] Re: duping the NilClass — Kurt Stephens <ks@...> 2008/07/20

Urabe Shyouhei wrote:

[#17880] Re: duping the NilClass — "Nasir Khan" <rubylearner@...> 2008/07/21

I write a lot of hand crafted dup or clone because I want control as well as

[#17881] Re: duping the NilClass — "David A. Black" <dblack@...> 2008/07/21

Hi --

[#17882] Re: duping the NilClass — Urabe Shyouhei <shyouhei@...> 2008/07/21

+1 to David. A convenient way to do Marshal idiom should be a new

[#17885] Re: duping the NilClass — "Robert Dober" <robert.dober@...> 2008/07/21

On Mon, Jul 21, 2008 at 8:21 AM, Urabe Shyouhei <shyouhei@ruby-lang.org> wrote:

[#17887] Re: duping the NilClass — "David A. Black" <dblack@...> 2008/07/21

Hi --

[#17889] Re: duping the NilClass — "Robert Dober" <robert.dober@...> 2008/07/21

On Mon, Jul 21, 2008 at 1:02 PM, David A. Black <dblack@rubypal.com> wrote:

[#17883] [Ruby 1.9 - Bug #340] (Open) 1.9/trunk does not work when compiled with llvm-gcc4 2.3 (gcc 4.2.1) — Ollivier Robert <redmine@...>

Issue #340 has been reported by Ollivier Robert.

14 messages 2008/07/21

[#17943] RUBY_ENGINE? — "Vladimir Sizikov" <vsizikov@...>

Hi,

56 messages 2008/07/24
[#17950] Re: RUBY_ENGINE? — Tanaka Akira <akr@...> 2008/07/25

In article <3454c9680807241200xf7cc766qb987905a3987bb78@mail.gmail.com>,

[#17958] Re: RUBY_ENGINE? — "Vladimir Sizikov" <vsizikov@...> 2008/07/25

Hi,

[#17981] Re: RUBY_ENGINE? — Tanaka Akira <akr@...> 2008/07/26

In article <3454c9680807250054i70db563duf44b42d92ba41bfb@mail.gmail.com>,

[ruby-core:17973] Proposal of GC::Profiler

From: Narihiro Nakamura <authorNari@...>
Date: 2008-07-25 14:59:45 UTC
List: ruby-core #17973
Hi.

make profiler for GC.

== usage
GC::Profiler.enable

:
:
:
# gc is invoked several times

GC::Profiler.report

---------- out -------------
GC 10 invokes.
Index	Invoke Time(sec)	Use Size(byte)	Total Size(byte)	Total Object	GC time(ms)
1 	0.016 			338420 		360448 			18018 		0.40000000000000007772
2 	0.024 			605640 		622592 			31122 		0.00000000000000008843
3 	0.040 			1080320 	1097728 		54873 		0.00000000000000022972
4 	0.060			1931460 	1949696 		97461 		0.40010000000000034426
5 	0.100 			3470040 	3489792 		174447 		0.79999999999999971134
6 	0.168 			6236240 	6258688 		312858 		1.20009999999999994458


2008303 used objects 52 free objects and 2008355 total objects in Heap.
Index	Count		%		Kind (class)
1 	1500000 	74.68799092 	Child
2 	500000 		24.89599697 	Parent
3 	5986 		0.29805488 	Object
4 	1648 		0.08205721 	String
5 	417 		0.02076326 	Class
6 	81 		0.00403315 	Encoding
8 	48 		0.00239002 	RubyVM::InstructionSequence
9 	23 		0.00114522 	Float
10 	20 		0.00099584 	Module
11 	17 		0.00084646 	Array
12 	16 		0.00079667 	Hash
13 	10 		0.00049792 	Regexp
14 	9 		0.00044813 	Enumerable
15 	5 		0.00024896 	Comparable
16 	3 		0.00014938 	IO
17 	3 		0.00014938 	Precision
18 	2 		0.00009958 	Bignum
19 	1 		0.00004979 	RubyVM::Env
20 	1 		0.00004979 	RubyVM
21 	1 		0.00004979 	Complex
22 	1 		0.00004979 	NoMemoryError
23 	1 		0.00004979 	Binding
24 	1 		0.00004979 	SystemStackError
25 	1 		0.00004979 	ThreadGroup
26 	1 		0.00004979 	Thread
27 	1 		0.00004979 	File::Constants
28 	1 		0.00004979 	ARGF.class
29 	1 		0.00004979 	Mutex
30 	1 		0.00004979 	Data
31 	1 		0.00004979 	fatal
32 	1 		0.00004979 	Kernel
33 	1 		0.00004979 	Gem::QuickLoader
----------------------------

== use module and method introduce
* GC::Profiler
for Profiler

* GC::Profiler.enable?
returns current status of GC profile mode.

* GC::Profiler.enable
updates GC profile mode.
start profiler for GC.

* GC::Profiler.disable
stop profiler.

* GC::Profiler.clear
clear before profile data.

* GC::Profiler.report
Please quote the above-mentioned.

* GC::Profiler.format
return string of GC::Profiler.report

* GC::Profiler.data
Report profile data to wrap hash.
It returns a hash as :
[{:GC_TIME => 0.001, :HEAP_USE_SIZE => 342840,
:HEAP_TOTAL_SIZE=>360360}, ... ]

* ObjectSpace.count_classes
Counts classes for each type.
It returns a hash as :
{:TOTAL=>10000, :FREE=>3011, :String=>6, :Array=>404, ...}


== merit
1. find memory leak
Now, not get detail info in heap.
ObjectSpace.count_classes, will be help to find memory leak.

2. Performance tuning
This provide simple way to get detail data of gc, and get heap
size change data by gc.
This will be help to performance tuning.

== patch
patch file append to mail.

== Please tell me idea for this
For example, more good method name, want more output data,
and this propose is bad idea... etc

thanks.

nari

-- 
Narihiro Nakamura <authorNari@gmail.com>




Attachments (1)

gc_profiler.diff (15.5 KB, text/x-diff)
Index: prelude.rb
===================================================================
--- prelude.rb	(revision 18143)
+++ prelude.rb	(working copy)
@@ -33,3 +33,33 @@
   absolute_feature = File.expand_path(File.join(File.dirname(file), relative_feature))
   require absolute_feature
 end
+
+module GC::Profiler
+  def self.format()
+    rep_data = self.data
+    h_inf = ObjectSpace.count_classes
+    prof = sprintf("GC %1$d invokes.\n", GC.count)
+
+    if GC::Profiler.enable? and !rep_data.empty?
+      prof += "Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC time(ms)\n"
+      rep_data.each_with_index do |e, i|
+        prof += sprintf("%1$5d %2$18.3f %3$20d %4$20d %5$20d %6$30.20f\n",
+                        i+1, e[:GC_INVOKE_TIME], e[:HEAP_USE_SIZE], e[:HEAP_TOTAL_SIZE], e[:HEAP_TOTAL_OBJECTS], e[:GC_TIME]*100)
+      end
+      prof += "\n\n"
+    end
+
+    prof += sprintf("%1$d used objects %2$d free objects and %3$d total objects in Heap.\n", h_inf[:TOTAL] - h_inf[:FREE], h_inf[:FREE], h_inf[:TOTAL])
+    prof += "Index                Count                    %          Kind (class)\n"
+    h_inf.to_a.sort{|b, a| a[1] <=> b[1] }.each_with_index do |e, i|
+       unless %w"FREE TOTAL".include? e[0].to_s
+         prof += sprintf("%1$5d %2$20d %3$20.8f %4$20s\n", i, e[1], e[1].to_f/h_inf[:TOTAL].to_f*100, e[0])
+       end
+    end
+    return prof
+  end
+
+  def self.report(out=$stdout)
+    out.puts self.format
+  end
+end
Index: gc.c
===================================================================
--- gc.c	(revision 18143)
+++ gc.c	(working copy)
@@ -92,6 +92,130 @@
 
 #undef GC_DEBUG
 
+/* for GC profile */
+#define GC_PROFILE_MORE_DETAIL 0
+typedef struct gc_profile_data {
+    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_data;
+
+/* 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 + (double)time.tv_usec*1e-6;
+}
+
+#define GC_PROF_TIMER_START do {\
+	if (objspace->profile.run) {\
+	    if (!objspace->profile.data) {\
+		objspace->profile.size = 1000;\
+		objspace->profile.data = malloc(sizeof(gc_profile_data) * objspace->profile.size);\
+	    }\
+	    if (count >= objspace->profile.size) {\
+		objspace->profile.size += 1000;\
+		objspace->profile.data = realloc(objspace->profile.data, sizeof(gc_profile_data) * objspace->profile.size);\
+	    }\
+	    if (!objspace->profile.data) {\
+		rb_bug("gc_profile malloc or realloc miss");\
+	    }\
+	    MEMZERO(&objspace->profile.data[count], gc_profile_data, 1);\
+	    gc_time = getrusage_time();\
+	    objspace->profile.data[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;\
+	    objspace->profile.data[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;\
+	    objspace->profile.data[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;\
+	    objspace->profile.data[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.data[count].allocate_increase = malloc_increase;\
+	    objspace->profile.data[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.data[count].heap_use_slots = heaps_used;\
+	    objspace->profile.data[count].heap_live_objects = live;\
+	    objspace->profile.data[count].heap_free_objects = freed;\
+	    objspace->profile.data[count].heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
+	    objspace->profile.data[count].have_finalize = final_list ? Qtrue : Qfalse;\
+	    objspace->profile.data[count].heap_use_size = live * sizeof(RVALUE);\
+	    objspace->profile.data[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.data[count].heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
+	    objspace->profile.data[count].heap_use_size = live * sizeof(RVALUE);\
+	    objspace->profile.data[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 +300,13 @@
 	VALUE *ptr;
 	int overflow;
     } markstack;
+    struct {
+	int run;
+	gc_profile_data *data;
+	size_t count;
+	size_t size;
+	double invoke_time;
+    } profile;
     struct gc_list *global_list;
     unsigned int count;
     int gc_stress;
@@ -309,6 +440,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.data, gc_profile_data, objspace->profile.size);
+    objspace->profile.count = 0;
+    return Qnil;
+}
+
 static void *
 vm_xmalloc(rb_objspace_t *objspace, size_t size)
 {
@@ -630,6 +828,7 @@
     	assign_heap_slot(objspace);
     }
     heaps_inc = 0;
+    objspace->profile.invoke_time = getrusage_time();
 }
 
 
@@ -899,8 +1098,9 @@
 	mid = (lo + hi) / 2;
 	heap = &heaps[mid];
 	if (heap->slot <= p) {
-	    if (p < heap->slot + heap->limit)
+	    if (p < heap->slot + heap->limit) {
 		return Qtrue;
+	    }
 	    lo = mid + 1;
 	}
 	else {
@@ -1440,6 +1640,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 +1654,12 @@
 
     /* clear finalization list */
     if (final_list) {
+	GC_PROF_SET_HEAP_INFO;
 	deferred_final_list = final_list;
 	return;
     }
     free_unused_heaps(objspace);
+    GC_PROF_SET_HEAP_INFO;
 }
 
 void
@@ -1672,6 +1875,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 +1895,8 @@
     during_gc++;
     objspace->count++;
 
+    GC_PROF_TIMER_START;
+    GC_PROF_MARK_TIMER_START;
     SET_STACK_END;
 
     init_mark_stack(objspace);
@@ -1731,9 +1937,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;
 }
@@ -2300,6 +2510,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) {
@@ -2340,6 +2551,87 @@
 
 /*
  *  call-seq:
+ *     ObjectSpace.count_classes([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
+count_classes(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 && RANY(p)->as.basic.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, 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.
@@ -2387,6 +2679,56 @@
 #endif
 
 /*
+ *  call-seq:
+ *     GC::Profiler.data -> hash
+ *
+ *  Report profile data to wrap hash.
+ *
+ *  It returns a hash as:
+ *  [{:GC_TIME => 0.001, :HEAP_USE_SIZE => 342840, :HEAP_TOTAL_SIZE=>360360}, ... ]
+ *
+ *  if GC_PROFILE_MORE_DETAIL is 1:
+ *  [{:GC_TIME=>0.004, :HEAP_USE_SIZE=>342840, :HEAP_TOTAL_SIZE=>360360, :GC_MARK_TIME=>-5.28548559086683e-19,
+ *      :GC_SWEEP_TIME=>0.004, :ALLOCATE_INCREASE=>40470, :ALLOCATE_LIMIT=>8000000, :HEAP_USE_SLOTS=>22,
+ *      :HEAP_LIVE_OBJECTS=>17142, :HEAP_FREE_OBJECTS=>44, :HEAP_TOTAL_OBJECTS=>18018, :HAVE_FINALIZE=>false}, .. ]
+ */
+
+VALUE
+gc_profile_data_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.data[i].gc_time));
+        rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DOUBLE2NUM(objspace->profile.data[i].gc_invoke_time));
+        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), rb_uint2inum(objspace->profile.data[i].heap_use_size));
+        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), rb_uint2inum(objspace->profile.data[i].heap_total_size));
+        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), rb_uint2inum(objspace->profile.data[i].heap_total_objects));
+#if GC_PROFILE_MORE_DETAIL
+        rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DOUBLE2NUM(objspace->profile.data[i].gc_mark_time));
+	rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DOUBLE2NUM(objspace->profile.data[i].gc_sweep_time));
+        rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), rb_uint2inum(objspace->profile.data[i].allocate_increase));
+        rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), rb_uint2inum(objspace->profile.data[i].allocate_limit));
+        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SLOTS")), rb_uint2inum(objspace->profile.data[i].heap_use_slots));
+        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), rb_uint2inum(objspace->profile.data[i].heap_live_objects));
+        rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), rb_uint2inum(objspace->profile.data[i].heap_free_objects));
+        rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), objspace->profile.data[i].have_finalize);
+#endif
+	rb_ary_push(gc_profile, prof);
+    }
+
+    return gc_profile;
+}
+
+/*
  *  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.
@@ -2396,6 +2738,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);
@@ -2406,6 +2749,13 @@
     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, "enable?", 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, "data", gc_profile_data_get, 0);
+    rb_define_singleton_method(rb_mProfiler, "clear", gc_profile_clear, 0);
+
     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);
@@ -2425,6 +2775,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, "count_classes", count_classes, -1);
 
 #if CALC_EXACT_MALLOC_SIZE
     rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);



In This Thread

Prev Next