bleak_house 7.1 → 7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ RUBY_VERSION = `ruby -v`.split(" ")[1]
2
+ require 'mkmf'
3
+ $CFLAGS = ENV['CFLAGS']
4
+ dir_config('snapshot')
5
+ create_makefile('snapshot')
@@ -0,0 +1,26 @@
1
+ require 'fileutils'
2
+
3
+ module BleakHouse
4
+
5
+ LOGDIR = File.expand_path('../../log', __FILE__)
6
+ LOGFILE = File.join(LOGDIR, 'bleak_house.log')
7
+
8
+ FileUtils.mkdir_p(LOGDIR)
9
+
10
+ def self.write_to_log(message)
11
+ File.open(LOGFILE, 'a') { |f| f.puts message }
12
+ end
13
+
14
+ def self.execute(command)
15
+ unless system(command)
16
+ puts File.open(LOGFILE).read
17
+ exit -1
18
+ end
19
+ end
20
+ end
21
+
22
+ BleakHouse.write_to_log('-%{ BUILDING RUBY }%-')
23
+ BleakHouse.execute("ruby build_ruby.rb >> #{BleakHouse::LOGFILE} 2>&1")
24
+
25
+ BleakHouse.write_to_log('-%{ BUILDING SNAPSHOT }%-')
26
+ BleakHouse.execute("ruby-bleak-house build_snapshot.rb >> #{BleakHouse::LOGFILE} 2>&1")
@@ -0,0 +1,153 @@
1
+ #include <time.h>
2
+ #include "snapshot.h"
3
+
4
+ static VALUE rb_mB;
5
+ static VALUE rb_cC;
6
+
7
+ /* Number of filled <tt>heaps_slots</tt> */
8
+ static VALUE heaps_used(VALUE self) {
9
+ return INT2FIX(rb_gc_heaps_used());
10
+ }
11
+
12
+ /* Number of allocated <tt>heaps_slots</tt> */
13
+ static VALUE heaps_length(VALUE self) {
14
+ return INT2FIX(rb_gc_heaps_length());
15
+ }
16
+
17
+ /* Inner method; call BleakHouse.snapshot instead. */
18
+ static VALUE ext_snapshot(VALUE self, VALUE _logfile, VALUE _gc_runs) {
19
+ Check_Type(_logfile, T_STRING);
20
+ Check_Type(_gc_runs, T_FIXNUM);
21
+
22
+ RVALUE *obj, *obj_end;
23
+ st_table_entry *sym;
24
+
25
+ struct heaps_slot * heaps = rb_gc_heap_slots();
26
+ struct st_table * sym_tbl = rb_parse_sym_tbl();
27
+
28
+ /* see if the logfile exists already */
29
+ FILE *logfile = fopen(StringValueCStr(_logfile), "r");
30
+ int is_new;
31
+ if (!(is_new = (logfile == NULL)))
32
+ fclose(logfile);
33
+
34
+ /* reopen for writing */
35
+ if ((logfile = fopen(StringValueCStr(_logfile), "w")) == NULL)
36
+ rb_raise(rb_eRuntimeError, "couldn't open snapshot file");
37
+
38
+ int filled_slots = 0;
39
+ int free_slots = 0;
40
+
41
+ int i;
42
+ int gc_runs = FIX2INT(_gc_runs);
43
+ char * chr;
44
+
45
+ for (i = 0; i < gc_runs; i++) {
46
+ /* request GC run */
47
+ rb_funcall(rb_mGC, rb_intern("start"), 0);
48
+ rb_thread_schedule();
49
+ }
50
+ fprintf(logfile, "%i GC runs performed before dump\n", gc_runs);
51
+
52
+ /* walk the heap */
53
+ for (i = 0; i < rb_gc_heaps_used(); i++) {
54
+ obj = heaps[i].slot;
55
+ obj_end = obj + heaps[i].limit;
56
+ for (; obj < obj_end; obj++) {
57
+ if (obj->as.basic.flags) { /* always 0 for freed objects */
58
+ filled_slots ++;
59
+
60
+ /* write the source file*/
61
+ if (obj->file) {
62
+ chr = obj->file;
63
+ if (*chr != '\0') {
64
+ fprintf(logfile, "%s", obj->file);
65
+ } else {
66
+ fprintf(logfile, "__empty__");
67
+ }
68
+ } else {
69
+ fprintf(logfile, "__null__");
70
+ }
71
+
72
+ /* write the source line */
73
+ fprintf(logfile, ":");
74
+ if (obj->line) {
75
+ fprintf(logfile, "%i", obj->line);
76
+ } else {
77
+ fprintf(logfile, "__null__");
78
+ }
79
+
80
+ /* write the class */
81
+ fprintf(logfile, ":");
82
+ switch (TYPE(obj)) {
83
+ case T_NONE:
84
+ fprintf(logfile, "__none__"); break;
85
+ case T_BLKTAG:
86
+ fprintf(logfile, "__blktag__"); break;
87
+ case T_UNDEF:
88
+ fprintf(logfile, "__undef__"); break;
89
+ case T_VARMAP:
90
+ fprintf(logfile, "__varmap__"); break;
91
+ case T_SCOPE:
92
+ fprintf(logfile, "__scope__"); break;
93
+ case T_NODE:
94
+ fprintf(logfile, "__node__"); break;
95
+ default:
96
+ if (!obj->as.basic.klass) {
97
+ fprintf(logfile, "__unknown__");
98
+ } else {
99
+ fprintf(logfile, rb_obj_classname((VALUE)obj));
100
+ }
101
+ }
102
+
103
+ /* write newline */
104
+ fprintf(logfile, "\n");
105
+ } else {
106
+ free_slots ++;
107
+ }
108
+ }
109
+ }
110
+
111
+ /* walk the symbol table */
112
+ /* hashed = lookup_builtin("Symbol");
113
+ for (i = 0; i < sym_tbl->num_bins; i++) {
114
+ for (sym = sym_tbl->bins[i]; sym != 0; sym = sym->next) {
115
+ fprintf(logfile, "%i,%lu\n", hashed + 1, sym->record);
116
+ }
117
+ } */
118
+
119
+ fprintf(logfile, "%i filled\n", filled_slots);
120
+ fprintf(logfile, "%i free\n", free_slots);
121
+ fclose(logfile);
122
+
123
+ return Qnil;
124
+ }
125
+
126
+
127
+ /*
128
+
129
+ This class performs the actual object logging of BleakHouse. To use it directly, you need to make calls to BleakHouse.snapshot.
130
+
131
+ By default, BleakHouse records a snapshot on exit. You can disable this by setting the environment variable <tt>NO_EXIT_HANDLER</tt> before startup.
132
+
133
+ It is also possible to externally trigger the snapshot at any time by sending <tt>SIGUSR2</tt> to the process.
134
+
135
+ == Example
136
+
137
+ At the start of your app, put:
138
+ require 'rubygems'
139
+ require 'bleak_house'
140
+ $logfile = "/path/to/logfile"
141
+
142
+ Run your app. Once it exits, analyze your data:
143
+ bleak /path/to/logfile
144
+
145
+ */
146
+ void
147
+ Init_snapshot()
148
+ {
149
+ rb_mB = rb_define_module("BleakHouse");
150
+ rb_define_singleton_method(rb_mB, "ext_snapshot", ext_snapshot, 2);
151
+ rb_define_singleton_method(rb_mB, "heaps_used", heaps_used, 0);
152
+ rb_define_singleton_method(rb_mB, "heaps_length", heaps_length, 0);
153
+ }
@@ -0,0 +1,59 @@
1
+ #include "ruby.h"
2
+ #include "env.h"
3
+ #include "node.h"
4
+ #include "st.h"
5
+ #include "re.h"
6
+ #include "util.h"
7
+ #include "intern.h"
8
+ #include "string.h"
9
+
10
+ typedef struct RVALUE {
11
+ union {
12
+ struct {
13
+ unsigned long flags; /* always 0 for freed obj */
14
+ struct RVALUE *next;
15
+ } free;
16
+ struct RBasic basic;
17
+ struct RObject object;
18
+ struct RClass klass;
19
+ struct RFloat flonum;
20
+ struct RString string;
21
+ struct RArray array;
22
+ struct RRegexp regexp;
23
+ struct RHash hash;
24
+ struct RData data;
25
+ struct RStruct rstruct;
26
+ struct RBignum bignum;
27
+ struct RFile file;
28
+ struct RNode node;
29
+ struct RMatch match;
30
+ struct RVarmap varmap;
31
+ struct SCOPE scope;
32
+ } as;
33
+ char *file;
34
+ int line;
35
+ } RVALUE;
36
+
37
+ struct heaps_slot {
38
+ void *membase;
39
+ RVALUE *slot;
40
+ int limit;
41
+ };
42
+
43
+ typedef struct st_table_entry st_table_entry;
44
+
45
+ struct st_table_entry {
46
+ unsigned int hash;
47
+ st_data_t key;
48
+ st_data_t record;
49
+ st_table_entry *next;
50
+ };
51
+
52
+ struct st_table * rb_parse_sym_tbl();
53
+ struct heaps_slot * rb_gc_heap_slots();
54
+ int rb_gc_heaps_used();
55
+ int rb_gc_heaps_length();
56
+
57
+ char * inspect(VALUE);
58
+ char * handle_exception(VALUE);
59
+ int lookup_builtin(char *);
@@ -1,17 +1,22 @@
1
1
 
2
- if ENV['BLEAK_HOUSE']
2
+ unless RUBY_PATCHLEVEL >= 905
3
+ raise "This build of Ruby has not been successfully patched for BleakHouse."
4
+ end
3
5
 
4
- # rails
5
- require 'dispatcher'
6
-
7
- # logger
8
- require 'bleak_house/c'
9
- require 'bleak_house/bleak_house'
6
+ RUBY_VERSION = `ruby -v`.split(" ")[1]
7
+ require 'snapshot'
8
+ require 'bleak_house/hook'
10
9
 
11
- # overrides
12
- require 'bleak_house/dispatcher'
13
- require 'bleak_house/action_controller'
10
+ class << BleakHouse
11
+ private :ext_snapshot
12
+ end
13
+
14
+ module BleakHouse
14
15
 
15
- BleakHouse.warn "enabled (log/bleak_house_#{RAILS_ENV}.dump)"
16
-
16
+ # Walk the live, instrumented objects on the heap and write them to
17
+ # <tt>logfile</tt>. Accepts an optional number of GC runs to perform
18
+ # before dumping the heap.
19
+ def self.snapshot(logfile, gc_runs = 3)
20
+ ext_snapshot(logfile, gc_runs)
21
+ end
17
22
  end
@@ -0,0 +1,54 @@
1
+
2
+ module BleakHouse
3
+ module Analyzer
4
+
5
+ # Analyze a compatible <tt>bleak.dump</tt>. Accepts one or more filename and the number of lines to display.
6
+ def self.run(*args)
7
+ lines = args.last[/^\d+$/] ? args.pop.to_i : 20
8
+
9
+ raise "Can't diff more than 2 files" if args.size > 2
10
+
11
+ outputs = args.map do |file|
12
+ filled, free = `tail -n 2 #{file}`.split("\n")
13
+ unless filled =~ /filled/ and free =~ /free/
14
+ raise "#{file} is incomplete or corrupted"
15
+ end
16
+
17
+ length = `wc #{file}`.to_i - 2
18
+ cmd = ENV['NO_TRACE'] ? "awk -F: '{print $3}' " + file : "cat #{file}"
19
+ cmd += " | sort | uniq -c | sort -nr | head -#{lines}"
20
+
21
+ ["#{length} total objects", "#{filled} heap slots", "#{free} heap slots"] + `#{cmd}`.split("\n")
22
+ end
23
+
24
+ if outputs.size == 1
25
+ # Just output the data
26
+ puts "Displaying top #{lines} most common line/class pairs"
27
+ puts outputs.first
28
+ else
29
+ puts "Displaying change in top #{lines} most common line/class pairs"
30
+ puts diff(outputs)
31
+ end
32
+
33
+ end
34
+
35
+ def self.diff(outputs)
36
+ # Calculate the diff
37
+ diff = Hash.new(0)
38
+ # Iterate each item
39
+ outputs.each_with_index do |output, index|
40
+ output[3..-1].each do |line|
41
+ c, key = line.split(" ", 2)
42
+ index.zero? ? diff[key] -= c.to_i : diff[key] += c.to_i
43
+ end
44
+ end
45
+ # Format the lines in descending order
46
+ diff.sort_by do |key, value|
47
+ -value
48
+ end.map do |key, value|
49
+ "#{value.to_s.rjust(6)} #{key}"
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,24 @@
1
+
2
+ module BleakHouse
3
+ # The body of the exit handler and <tt>SIGUSR2</tt> trap. It writes a snapshot to a dumpfile named after the current Process.pid.
4
+ def self.hook(gc_runs = 3)
5
+ @count ||= 0
6
+ filename = "/tmp/bleak.%s.%03i.dump" % [Process.pid,@count]
7
+ STDERR.puts "** BleakHouse: working..."
8
+ BleakHouse.snapshot(filename, gc_runs)
9
+ STDERR.puts "** BleakHouse: complete\n** Bleakhouse: Run 'bleak #{filename}' to analyze."
10
+ @count += 1
11
+ end
12
+ end
13
+
14
+ unless ENV['NO_EXIT_HANDLER']
15
+ Kernel.at_exit do
16
+ BleakHouse.hook
17
+ end
18
+ STDERR.puts "** Bleakhouse: installed"
19
+ end
20
+
21
+ Kernel.trap("USR2") do
22
+ STDERR.puts "** BleakHouse: we get signal."
23
+ BleakHouse.hook
24
+ end
@@ -0,0 +1,483 @@
1
+ diff --git a/Makefile.in b/Makefile.in
2
+ index a37bcf6..52f723c 100644
3
+ --- a/Makefile.in
4
+ +++ b/Makefile.in
5
+ @@ -34,7 +34,7 @@ RIDATADIR = $(DESTDIR)$(datadir)/ri/$(MAJOR).$(MINOR)/system
6
+
7
+ empty =
8
+ OUTFLAG = @OUTFLAG@$(empty)
9
+ -CFLAGS = @CFLAGS@ @XCFLAGS@ @ARCH_FLAG@
10
+ +CFLAGS = @CFLAGS@ @XCFLAGS@ @ARCH_FLAG@ @VALGRIND_CFLAGS@
11
+ cflags = @cflags@
12
+ optflags = @optflags@
13
+ debugflags = @debugflags@
14
+ diff --git a/configure b/configure
15
+ index faf2b45..16287ca 100755
16
+ --- a/configure
17
+ +++ b/configure
18
+ @@ -724,6 +724,7 @@ cflags
19
+ optflags
20
+ debugflags
21
+ XCFLAGS
22
+ +VALGRIND_CFLAGS
23
+ XLDFLAGS
24
+ LIBRUBY_LDSHARED
25
+ LIBRUBY_DLDFLAGS
26
+ @@ -1353,6 +1354,7 @@ Optional Features:
27
+ --enable-setreuid use setreuid()/setregid() according to need even if obsolete.
28
+ --disable-rpath embed run path into extension libraries.
29
+ --enable-shared build a shared library for Ruby.
30
+ + --enable-valgrind Use valgrind support
31
+ --enable-install-doc build and install rdoc indexes during install
32
+
33
+ Optional Packages:
34
+ @@ -13012,12 +13014,11 @@ cat confdefs.h >>conftest.$ac_ext
35
+ cat >>conftest.$ac_ext <<_ACEOF
36
+ /* end confdefs.h. */
37
+ #include <sys/types.h> /* for off_t */
38
+ - #include <stdio.h>
39
+ +#include <stdio.h>
40
+ int
41
+ main ()
42
+ {
43
+ -int (*fp) (FILE *, off_t, int) = fseeko;
44
+ - return fseeko (stdin, 0, 0) && fp (stdin, 0, 0);
45
+ +return fseeko (stdin, 0, 0) && (fseeko) (stdin, 0, 0);
46
+ ;
47
+ return 0;
48
+ }
49
+ @@ -16462,6 +16463,173 @@ done
50
+ fi
51
+ fi
52
+
53
+ +# Check whether --enable-valgrind was given.
54
+ +if test "${enable_valgrind+set}" = set; then
55
+ + enableval=$enable_valgrind; want_valgrind=$enableval
56
+ +else
57
+ + want_valgrind=auto
58
+ +fi
59
+ +
60
+ +
61
+ +if test x"$want_valgrind" != xno; then
62
+ +
63
+ +for ac_header in valgrind/memcheck.h
64
+ +do
65
+ +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
66
+ +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
67
+ + { echo "$as_me:$LINENO: checking for $ac_header" >&5
68
+ +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
69
+ +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
70
+ + echo $ECHO_N "(cached) $ECHO_C" >&6
71
+ +fi
72
+ +ac_res=`eval echo '${'$as_ac_Header'}'`
73
+ + { echo "$as_me:$LINENO: result: $ac_res" >&5
74
+ +echo "${ECHO_T}$ac_res" >&6; }
75
+ +else
76
+ + # Is the header compilable?
77
+ +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
78
+ +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
79
+ +cat >conftest.$ac_ext <<_ACEOF
80
+ +/* confdefs.h. */
81
+ +_ACEOF
82
+ +cat confdefs.h >>conftest.$ac_ext
83
+ +cat >>conftest.$ac_ext <<_ACEOF
84
+ +/* end confdefs.h. */
85
+ +$ac_includes_default
86
+ +#include <$ac_header>
87
+ +_ACEOF
88
+ +rm -f conftest.$ac_objext
89
+ +if { (ac_try="$ac_compile"
90
+ +case "(($ac_try" in
91
+ + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
92
+ + *) ac_try_echo=$ac_try;;
93
+ +esac
94
+ +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
95
+ + (eval "$ac_compile") 2>conftest.er1
96
+ + ac_status=$?
97
+ + grep -v '^ *+' conftest.er1 >conftest.err
98
+ + rm -f conftest.er1
99
+ + cat conftest.err >&5
100
+ + echo "$as_me:$LINENO: \$? = $ac_status" >&5
101
+ + (exit $ac_status); } && {
102
+ + test -z "$ac_c_werror_flag" ||
103
+ + test ! -s conftest.err
104
+ + } && test -s conftest.$ac_objext; then
105
+ + ac_header_compiler=yes
106
+ +else
107
+ + echo "$as_me: failed program was:" >&5
108
+ +sed 's/^/| /' conftest.$ac_ext >&5
109
+ +
110
+ + ac_header_compiler=no
111
+ +fi
112
+ +
113
+ +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
114
+ +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
115
+ +echo "${ECHO_T}$ac_header_compiler" >&6; }
116
+ +
117
+ +# Is the header present?
118
+ +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
119
+ +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
120
+ +cat >conftest.$ac_ext <<_ACEOF
121
+ +/* confdefs.h. */
122
+ +_ACEOF
123
+ +cat confdefs.h >>conftest.$ac_ext
124
+ +cat >>conftest.$ac_ext <<_ACEOF
125
+ +/* end confdefs.h. */
126
+ +#include <$ac_header>
127
+ +_ACEOF
128
+ +if { (ac_try="$ac_cpp conftest.$ac_ext"
129
+ +case "(($ac_try" in
130
+ + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
131
+ + *) ac_try_echo=$ac_try;;
132
+ +esac
133
+ +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
134
+ + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
135
+ + ac_status=$?
136
+ + grep -v '^ *+' conftest.er1 >conftest.err
137
+ + rm -f conftest.er1
138
+ + cat conftest.err >&5
139
+ + echo "$as_me:$LINENO: \$? = $ac_status" >&5
140
+ + (exit $ac_status); } >/dev/null && {
141
+ + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
142
+ + test ! -s conftest.err
143
+ + }; then
144
+ + ac_header_preproc=yes
145
+ +else
146
+ + echo "$as_me: failed program was:" >&5
147
+ +sed 's/^/| /' conftest.$ac_ext >&5
148
+ +
149
+ + ac_header_preproc=no
150
+ +fi
151
+ +
152
+ +rm -f conftest.err conftest.$ac_ext
153
+ +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
154
+ +echo "${ECHO_T}$ac_header_preproc" >&6; }
155
+ +
156
+ +# So? What about this header?
157
+ +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
158
+ + yes:no: )
159
+ + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
160
+ +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
161
+ + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
162
+ +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
163
+ + ac_header_preproc=yes
164
+ + ;;
165
+ + no:yes:* )
166
+ + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
167
+ +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
168
+ + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
169
+ +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
170
+ + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
171
+ +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
172
+ + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
173
+ +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
174
+ + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
175
+ +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
176
+ + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
177
+ +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
178
+ +
179
+ + ;;
180
+ +esac
181
+ +{ echo "$as_me:$LINENO: checking for $ac_header" >&5
182
+ +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
183
+ +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
184
+ + echo $ECHO_N "(cached) $ECHO_C" >&6
185
+ +else
186
+ + eval "$as_ac_Header=\$ac_header_preproc"
187
+ +fi
188
+ +ac_res=`eval echo '${'$as_ac_Header'}'`
189
+ + { echo "$as_me:$LINENO: result: $ac_res" >&5
190
+ +echo "${ECHO_T}$ac_res" >&6; }
191
+ +
192
+ +fi
193
+ +if test `eval echo '${'$as_ac_Header'}'` = yes; then
194
+ + cat >>confdefs.h <<_ACEOF
195
+ +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
196
+ +_ACEOF
197
+ + have_valgrind=yes
198
+ +else
199
+ + have_valgrind=no
200
+ +fi
201
+ +
202
+ +done
203
+ +
204
+ + if test x"$have_valgrind" = xyes; then
205
+ + cat >>confdefs.h <<\_ACEOF
206
+ +#define HAVE_VALGRIND 1
207
+ +_ACEOF
208
+ +
209
+ + VALGRIND_CFLAGS="";
210
+ + elif test x"$want_valgrind" = xyes -a x"$have_valgrind" = xno; then
211
+ + { { echo "$as_me:$LINENO: error: valgrind support requested but valgrind not found" >&5
212
+ +echo "$as_me: error: valgrind support requested but valgrind not found" >&2;}
213
+ + { (exit 1); exit 1; }; }
214
+ + else
215
+ + VALGRIND_CFLAGS="";
216
+ + fi
217
+ +fi
218
+ +
219
+ +
220
+ DEFAULT_KCODE="KCODE_NONE"
221
+
222
+
223
+ @@ -18588,6 +18756,7 @@ cflags!$cflags$ac_delim
224
+ optflags!$optflags$ac_delim
225
+ debugflags!$debugflags$ac_delim
226
+ XCFLAGS!$XCFLAGS$ac_delim
227
+ +VALGRIND_CFLAGS!$VALGRIND_CFLAGS$ac_delim
228
+ XLDFLAGS!$XLDFLAGS$ac_delim
229
+ LIBRUBY_LDSHARED!$LIBRUBY_LDSHARED$ac_delim
230
+ LIBRUBY_DLDFLAGS!$LIBRUBY_DLDFLAGS$ac_delim
231
+ @@ -18622,7 +18791,7 @@ MANTYPE!$MANTYPE$ac_delim
232
+ LTLIBOBJS!$LTLIBOBJS$ac_delim
233
+ _ACEOF
234
+
235
+ - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 47; then
236
+ + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 48; then
237
+ break
238
+ elif $ac_last_try; then
239
+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
240
+ diff --git a/configure.in b/configure.in
241
+ index fe63c0c..e0cdcdd 100644
242
+ --- a/configure.in
243
+ +++ b/configure.in
244
+ @@ -1043,6 +1043,23 @@ if test x"$ac_cv_header_ucontext_h" = xyes; then
245
+ fi
246
+ fi
247
+
248
+ +AC_ARG_ENABLE(valgrind,
249
+ + [ --enable-valgrind use valgrind support],
250
+ + [want_valgrind=$enableval], [want_valgrind=auto])
251
+ +
252
+ +if test x"$want_valgrind" != xno; then
253
+ + AC_CHECK_HEADERS(valgrind/memcheck.h, have_valgrind=yes, have_valgrind=no)
254
+ + if test x"$have_valgrind" = xyes; then
255
+ + AC_DEFINE(HAVE_VALGRIND)
256
+ + VALGRIND_CFLAGS="";
257
+ + elif test x"$want_valgrind" = xyes -a x"$have_valgrind" = xno; then
258
+ + AC_MSG_ERROR(valgrind support requested but valgrind not found)
259
+ + else
260
+ + VALGRIND_CFLAGS="";
261
+ + fi
262
+ +fi
263
+ +
264
+ +
265
+ dnl default value for $KANJI
266
+ DEFAULT_KCODE="KCODE_NONE"
267
+
268
+ @@ -1663,6 +1680,7 @@ AC_SUBST(cflags, ['${optflags} ${debugflags}'])dnl
269
+ AC_SUBST(optflags)dnl
270
+ AC_SUBST(debugflags)dnl
271
+ AC_SUBST(XCFLAGS)dnl
272
+ +AC_SUBST(VALGRIND_CFLAGS)dnl
273
+ AC_SUBST(XLDFLAGS)dnl
274
+ AC_SUBST(LIBRUBY_LDSHARED)
275
+ AC_SUBST(LIBRUBY_DLDFLAGS)
276
+ diff --git a/eval.c b/eval.c
277
+ index 11264f7..09ec7a6 100644
278
+ --- a/eval.c
279
+ +++ b/eval.c
280
+ @@ -28,6 +28,12 @@
281
+ #define EXIT_FAILURE 1
282
+ #endif
283
+
284
+ +#ifdef HAVE_VALGRIND
285
+ +#include <valgrind/memcheck.h>
286
+ +#else
287
+ +#define VALGRIND_MAKE_MEM_DEFINED(p, n) /* empty */
288
+ +#endif
289
+ +
290
+ #include <stdio.h>
291
+
292
+ #include "st.h"
293
+ @@ -1149,7 +1149,7 @@ static VALUE trace_func = 0;
294
+ static int tracing = 0;
295
+ static void call_trace_func _((rb_event_t,NODE*,VALUE,ID,VALUE));
296
+
297
+ -#if 0
298
+ +#if 1
299
+ #define SET_CURRENT_SOURCE() (ruby_sourcefile = ruby_current_node->nd_file, \
300
+ ruby_sourceline = nd_line(ruby_current_node))
301
+ #else
302
+ @@ -5290,6 +5296,9 @@ assign(self, lhs, val, pcall)
303
+ int pcall;
304
+ {
305
+ ruby_current_node = lhs;
306
+ +
307
+ + VALGRIND_MAKE_MEM_DEFINED(&val, sizeof(val));
308
+ +
309
+ if (val == Qundef) {
310
+ rb_warning("assigning void value");
311
+ val = Qnil;
312
+ diff --git a/gc.c b/gc.c
313
+ index 45facf0..933b76e 100644
314
+ --- a/gc.c
315
+ +++ b/gc.c
316
+ @@ -30,6 +30,12 @@
317
+ #include <sys/resource.h>
318
+ #endif
319
+
320
+ +#ifdef HAVE_VALGRIND
321
+ +#include <valgrind/memcheck.h>
322
+ +#else
323
+ +#define VALGRIND_MAKE_MEM_DEFINED(p, n) /* empty */
324
+ +#endif
325
+ +
326
+ #if defined _WIN32 || defined __CYGWIN__
327
+ #include <windows.h>
328
+ #endif
329
+ @@ -138,6 +144,9 @@ ruby_xmalloc(size)
330
+ {
331
+ void *mem;
332
+
333
+ + VALGRIND_MAKE_MEM_DEFINED(&malloc_increase, sizeof(malloc_increase));
334
+ + VALGRIND_MAKE_MEM_DEFINED(&malloc_limit, sizeof(malloc_limit));
335
+ +
336
+ if (size < 0) {
337
+ rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
338
+ }
339
+ @@ -297,8 +306,6 @@ rb_gc_unregister_address(addr)
340
+ }
341
+ }
342
+
343
+ -#undef GC_DEBUG
344
+ -
345
+ void
346
+ rb_global_variable(var)
347
+ VALUE *var;
348
+ @@ -333,10 +340,8 @@ typedef struct RVALUE {
349
+ struct RVarmap varmap;
350
+ struct SCOPE scope;
351
+ } as;
352
+ -#ifdef GC_DEBUG
353
+ char *file;
354
+ int line;
355
+ -#endif
356
+ } RVALUE;
357
+
358
+ #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
359
+ @@ -355,6 +360,22 @@ static struct heaps_slot {
360
+ static int heaps_length = 0;
361
+ static int heaps_used = 0;
362
+
363
+ +struct heaps_slot *
364
+ +rb_gc_heap_slots()
365
+ +{
366
+ + return heaps;
367
+ +}
368
+ +
369
+ +int
370
+ +rb_gc_heaps_used() {
371
+ + return heaps_used;
372
+ +}
373
+ +
374
+ +int
375
+ +rb_gc_heaps_length() {
376
+ + return heaps_length;
377
+ +}
378
+ +
379
+ #define HEAP_MIN_SLOTS 10000
380
+ static int heap_slots = HEAP_MIN_SLOTS;
381
+
382
+ @@ -438,10 +438,8 @@ rb_newobj()
383
+ obj = (VALUE)freelist;
384
+ freelist = freelist->as.free.next;
385
+ MEMZERO((void*)obj, RVALUE, 1);
386
+ -#ifdef GC_DEBUG
387
+ RANY(obj)->file = ruby_sourcefile;
388
+ RANY(obj)->line = ruby_sourceline;
389
+ -#endif
390
+ return obj;
391
+ }
392
+
393
+ @@ -678,6 +704,9 @@ mark_locations_array(x, n)
394
+ register long n;
395
+ {
396
+ VALUE v;
397
+ +
398
+ + VALGRIND_MAKE_MEM_DEFINED(x, sizeof(*x) * n);
399
+ +
400
+ while (n--) {
401
+ v = *x;
402
+ if (is_pointer_to_heap((void *)v)) {
403
+ @@ -768,12 +797,18 @@ gc_mark(ptr, lev)
404
+ {
405
+ register RVALUE *obj;
406
+
407
+ + VALGRIND_MAKE_MEM_DEFINED(&ptr, sizeof(ptr));
408
+ obj = RANY(ptr);
409
+ + VALGRIND_MAKE_MEM_DEFINED(obj, sizeof(*obj));
410
+ +
411
+ if (rb_special_const_p(ptr)) return; /* special const not marked */
412
+ if (obj->as.basic.flags == 0) return; /* free cell */
413
+ if (obj->as.basic.flags & FL_MARK) return; /* already marked */
414
+ obj->as.basic.flags |= FL_MARK;
415
+
416
+ + /* mark our new reference point for sourcefile objects */
417
+ + mark_source_filename(RANY(obj)->file);
418
+ +
419
+ if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) {
420
+ if (!mark_stack_overflow) {
421
+ if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) {
422
+ @@ -1077,6 +1078,10 @@ gc_mark(ptr, lev)
423
+ if (obj->as.basic.flags == 0) return; /* free cell */
424
+ if (obj->as.basic.flags & FL_MARK) return; /* already marked */
425
+ obj->as.basic.flags |= FL_MARK;
426
+ +
427
+ + /* mark our new reference point for sourcefile objects */
428
+ + mark_source_filename(RANY(obj)->file);
429
+ +
430
+
431
+ if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) {
432
+ if (!mark_stack_overflow) {
433
+ @@ -1115,6 +1120,10 @@ gc_mark_children(ptr, lev)
434
+ if (obj->as.basic.flags == 0) return; /* free cell */
435
+ if (obj->as.basic.flags & FL_MARK) return; /* already marked */
436
+ obj->as.basic.flags |= FL_MARK;
437
+ +
438
+ + /* mark our new reference point for sourcefile objects */
439
+ + mark_source_filename(RANY(obj)->file);
440
+ +
441
+
442
+ marking:
443
+ if (FL_TEST(obj, FL_EXIVAR)) {
444
+ diff --git a/parse.c b/parse.c
445
+ index 6b3d80d..b320cf2 100644
446
+ --- a/parse.c
447
+ +++ b/parse.c
448
+ @@ -11403,6 +11403,11 @@ symbols_i(key, value, ary)
449
+ * :wait2, :$>]
450
+ */
451
+
452
+ +struct st_table *
453
+ +rb_parse_sym_tbl() {
454
+ + return sym_tbl;
455
+ +}
456
+ +
457
+ VALUE
458
+ rb_sym_all_symbols()
459
+ {
460
+ diff --git a/parse.y b/parse.y
461
+ index ab0b83c..3ce1dfb 100644
462
+ --- a/parse.y
463
+ +++ b/parse.y
464
+ @@ -6263,6 +6263,11 @@ symbols_i(key, value, ary)
465
+ * :wait2, :$>]
466
+ */
467
+
468
+ +struct st_table *
469
+ +rb_parse_sym_tbl() {
470
+ + return sym_tbl;
471
+ +}
472
+ +
473
+ VALUE
474
+ rb_sym_all_symbols()
475
+ {
476
+ diff --git a/version.h b/version.h
477
+ index 70fc28a..76aa188 100644
478
+ --- a/version.h
479
+ +++ b/version.h
480
+ @@ -5,2 +5,2 @@
481
+ -#define RUBY_PATCHLEVEL 174
482
+ +#define RUBY_PATCHLEVEL 905
483
+