[#17480] Array#fill behavior — "Vladimir Sizikov" <vsizikov@...>
Hi,
[#17488] HOME and USERPROFILE aliasing under Windows — "John Lam (IRONRUBY)" <jflam@...>
MRI currently expects the HOME environment variable to be set under Windows=
[#17491] [Ruby 1.8.7 - Bug #213] (Open) Different ERB behavior across versions — Federico Builes <redmine@...>
Issue #213 has been reported by Federico Builes.
[#17503] Possible misbehaviour in mkmf.rb package — S駻gio Durigan J佖ior <sergiodj@...>
Hello all,
On Wednesday 02 July 2008, S駻gio Durigan J佖ior wrote:
[#17509] YAML in Ruby — Trans <transfire@...>
Might we ever imagine a time when YAML is an integral part of Ruby?
[#17518] [Ruby 1.8 - Bug #216] (Open) Memory leaks in 1.8.6p230 and p238 — Igal Koshevoy <redmine@...>
Issue #216 has been reported by Igal Koshevoy.
[#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.
Why not write it in ruby?
Kurt Stephens wrote:
I've split up the code of rubychecker. One git repo has the GNU Bash
[#17574] rubyspec reports for ruby_1_8, ruby_1_8_7, and v1_8_6_p265 — Stephen Bannasch <stephen.bannasch@...>
I wanted to learn more about specs recently started using git and so
Stephen Bannasch wrote:
[#17595] Crashes and hangups on latest 1_8 branch — "Vladimir Sizikov" <vsizikov@...>
Hi,
[#17609] [PATCH] Fix Makefile update-rubyspec task — Gaston Ramos <ramos.gaston@...>
Hi, I'm trying to run rubyspec tests on 1.8 branch and get this error:
[#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
It was designed to fix the following case:
Here's a third patch that fixes a bug in the second and uses a quicker
One more patch which fixes a few bugs in the the last one.
Hi,
Looks like version 22 doesn't support explicitly numbered regexp groups.
Hi,
Hi,
Alright, here's a version that fixes both the highlighting bug and the
Hi,
Are you asking me? If so, go right ahead. Also, for posterity's sake,
One more bugfix.
Hi,
[#17627] ncurses-specific functions in ruby's curses — "Kirill A. Shutemov" <kirill@...>
Is it possible to add ncurses-specific functions to curses ruby module?
On Sunday 06 July 2008, Kirill A. Shutemov wrote:
On Mon, Jul 07, 2008 at 10:25:42AM +0200, Marc Haisenko wrote:
On Monday 07 July 2008, Kirill A. Shutemov wrote:
[#17629] Proper exception out of throw? — "Vladimir Sizikov" <vsizikov@...>
Hi,
[#17644] Features to be included in Ruby 1.9.1 — "Yugui (Yuki Sonoda)" <yugui@...>
Hi, all
Dave Thomas wrote:
There are two things I would like to see added to 1.9.1. A one-byte
Hi,
Hi,
In article <E1KGF2L-0000Qx-K5@x61.netlab.jp>,
Hi,
[#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.
[#17690] [Ruby 1.8 - Feature #249] (Open) wish list item: binding.set_local_variable — Roger Pack <redmine@...>
Issue #249 has been reported by Roger Pack.
[#17694] Mark functions not called on exit — Charlie Savage <cfis@...>
Hi everyone,
Hi,
[#17699] Omissions on the ruby-lang.org website and in redmine — "Austin Ziegler" <halostatue@...>
As far as I can tell, there's nowhere on the ruby-lang.org website
On Jul 9, 2008, at 8:05 AM, Austin Ziegler wrote:
On Jul 9, 2008, at 6:07 PM, Ryan Davis wrote:
On Wed, Jul 9, 2008 at 5:14 PM, James Gray <james@grayproductions.net> wrote:
[#17708] [Ruby 1.8 - Bug #252] (Open) Array#sort doesn't respect overridden <=> — Ryan Davis <redmine@...>
Issue #252 has been reported by Ryan Davis.
Issue #252 has been updated by Vladimir Sizikov.
Hi,
Nobuyoshi Nakada wrote:
[#17759] Ruby 1.9.1 Feature and 1.9.0-3 release plan — "Yugui (Yuki Sonoda)" <yugui@...>
Thank you for your replies to [ruby-core:17644]. < all
[#17785] [Ruby 1.9 - Bug #277] (Open) 1.9/trunk: build broken in ruby/ruby.h — Ollivier Robert <redmine@...>
Issue #277 has been reported by Ollivier Robert.
[#17812] Tracing versus coverage (was Re: Re: Features to be included in Ruby 1.9.1) — "Rocky Bernstein" <rocky.bernstein@...>
Sorry for not noticing sooner. It occurs to me that the built-in
It seems to me what you need is not a coverage system but a general hook
I just looked at the code to set the coverage hash and it seems to
Hi Rocky,
[#17822] rdoc defines Hash#method_missing — "Yusuke ENDOH" <mame@...>
Hi,
[#17829] FAILURE of "expand_path" — "C.E. Thornton" <admin@...>
Core,
C.E. Thornton wrote:
Urabe Shyouhei wrote:
On Sat, Jul 19, 2008 at 04:27:09AM +0900, C.E. Thornton wrote:
[#17833] Object allocation tracking — Christopher Thompson <cthompson@...>
Please excuse the blog spam.
[#17843] Exapand_path Patch good as stands. — "C.E. Thornton" <admin@...>
Core,
[#17865] Expand_Path: New Patch - Modified Processing — "C.E. Thornton" <admin@...>
Core,
Hi,
Hi,
[#17871] duping the NilClass — "Nasir Khan" <rubylearner@...>
While nil is an object, calling dup on it causes TypeError. This doesnt seem
Nasir Khan wrote:
On Sun, Jul 20, 2008 at 7:55 PM, Urabe Shyouhei <shyouhei@ruby-lang.org>
Meinrad Recheis wrote:
Urabe Shyouhei wrote:
I write a lot of hand crafted dup or clone because I want control as well as
Hi --
+1 to David. A convenient way to do Marshal idiom should be a new
On Mon, Jul 21, 2008 at 8:21 AM, Urabe Shyouhei <shyouhei@ruby-lang.org> wrote:
Hi --
On Mon, Jul 21, 2008 at 1:02 PM, David A. Black <dblack@rubypal.com> wrote:
Hi --
On Mon, Jul 21, 2008 at 5:18 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.
[#17915] select returning an enumerator — "David A. Black" <dblack@...>
Hi --
[#17922] [Ruby 1.9 - Bug #345] (Open) 1.9 racc appears to seg fault — Roger Pack <redmine@...>
Issue #345 has been reported by Roger Pack.
[#17943] RUBY_ENGINE? — "Vladimir Sizikov" <vsizikov@...>
Hi,
In article <3454c9680807241200xf7cc766qb987905a3987bb78@mail.gmail.com>,
On Thu, Jul 24, 2008 at 7:46 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:
Hi,
In article <3454c9680807250054i70db563duf44b42d92ba41bfb@mail.gmail.com>,
On Sat, Jul 26, 2008 at 5:09 AM, Tanaka Akira <akr@fsij.org> wrote:
Hi,
Since this thread seemed to die out, I'll ask again:
Hi,
Hi all.
Hi,
Yukihiro Matsumoto wrote:
[#17954] Expand_path -- Proposal: An alternate method — "C.E. Thornton" <admin@...>
HI,
Hi,
Yukihiro Matsumoto wrote:
[#17973] Proposal of GC::Profiler — Narihiro Nakamura <authorNari@...>
Hi.
On Fri, 2008-07-25 at 23:59 +0900, Narihiro Nakamura wrote:
[#18016] Re: Hex string literals [Patch] — gdefty@...
Before posting the message below I thought long
[#18029] [Ruby 1.9 - Bug #378] (Open) rbconfig.rb:173: [BUG] Stack consistency error — Anonymous <redmine@...>
Issue #378 has been reported by Anonymous.
[#18033] JRuby adding ConcurrencyError for fatal concurrent modification — Charles Oliver Nutter <charles.nutter@...>
In order to limit or reduce the likelihood that multiple threads
Hi,
Yukihiro Matsumoto wrote:
[ruby-core:17973] Proposal of GC::Profiler
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)
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);