honkster-perftools.rb 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ diff --git a/Makefile.in b/Makefile.in
2
+ index c3bf409..c613939 100644
3
+ --- a/Makefile.in
4
+ +++ b/Makefile.in
5
+ @@ -1367,13 +1367,13 @@ AUTOMAKE = @AUTOMAKE@
6
+ AWK = @AWK@
7
+ CC = @CC@
8
+ CCDEPMODE = @CCDEPMODE@
9
+ -CFLAGS = @CFLAGS@ -DBUILD_FOR_RUBY -fPIC
10
+ +CFLAGS = @CFLAGS@ -DBUILD_FOR_RUBY -fPIC -O0 -ggdb
11
+ CPP = @CPP@
12
+ CPPFLAGS = @CPPFLAGS@
13
+ CXX = @CXX@
14
+ CXXCPP = @CXXCPP@
15
+ CXXDEPMODE = @CXXDEPMODE@
16
+ -CXXFLAGS = @CXXFLAGS@ -DBUILD_FOR_RUBY -fPIC
17
+ +CXXFLAGS = @CXXFLAGS@ -DBUILD_FOR_RUBY -fPIC -O0 -ggdb
18
+ CYGPATH_W = @CYGPATH_W@
19
+ DEFS = @DEFS@
20
+ DEPDIR = @DEPDIR@
@@ -0,0 +1,13 @@
1
+ diff --git a/src/profiledata.h b/src/profiledata.h
2
+ index ccdf96f..0517614 100644
3
+ --- a/src/profiledata.h
4
+ +++ b/src/profiledata.h
5
+ @@ -106,7 +106,7 @@ class ProfileData {
6
+ int frequency_; // Sample frequency.
7
+ };
8
+
9
+ - static const int kMaxStackDepth = 64; // Max stack depth stored in profile
10
+ + static const int kMaxStackDepth = 300; // Max stack depth stored in profile
11
+
12
+ ProfileData();
13
+ ~ProfileData();
@@ -0,0 +1,107 @@
1
+ diff --git a/src/profiledata.cc b/src/profiledata.cc
2
+ index e6240d9..b901ee8 100644
3
+ --- a/src/profiledata.cc
4
+ +++ b/src/profiledata.cc
5
+ @@ -198,6 +198,29 @@ static void DumpProcSelfMaps(int fd) {
6
+ }
7
+ }
8
+
9
+ +#ifdef BUILD_FOR_RUBY
10
+ +void ProfileData::GcMark(void (*mark)(VALUE)) {
11
+ + if (!enabled()) {
12
+ + return;
13
+ + }
14
+ +
15
+ + for (int b = 0; b < kBuckets; b++) {
16
+ + Bucket* bucket = &hash_[b];
17
+ + for (int a = 0; a < kAssociativity; a++) {
18
+ + if (bucket->entry[a].count > 0) {
19
+ + Entry e = bucket->entry[a];
20
+ + if (e.depth > 1)
21
+ + for (int n=0; n<e.depth; n+=3) {
22
+ + if (e.stack[n])
23
+ + mark(e.stack[n]);
24
+ + mark(e.stack[n+1]);
25
+ + }
26
+ + }
27
+ + }
28
+ + }
29
+ +}
30
+ +#endif
31
+ +
32
+ void ProfileData::Stop() {
33
+ if (!enabled()) {
34
+ return;
35
+ diff --git a/src/profiledata.h b/src/profiledata.h
36
+ index 67c463d..a68e12f 100644
37
+ --- a/src/profiledata.h
38
+ +++ b/src/profiledata.h
39
+ @@ -40,6 +40,12 @@
40
+ #ifndef BASE_PROFILEDATA_H_
41
+ #define BASE_PROFILEDATA_H_
42
+
43
+ +#ifdef BUILD_FOR_RUBY
44
+ +extern "C" {
45
+ + typedef unsigned long VALUE;
46
+ +}
47
+ +#endif
48
+ +
49
+ #include <config.h>
50
+ #include <time.h> // for time_t
51
+ #include <stdint.h>
52
+ @@ -141,6 +147,10 @@ class ProfileData {
53
+ // Get the current state of the data collector.
54
+ void GetCurrentState(State* state) const;
55
+
56
+ +#ifdef BUILD_FOR_RUBY
57
+ + void GcMark(void (*cb)(VALUE));
58
+ +#endif
59
+ +
60
+ private:
61
+ static const int kAssociativity = 4; // For hashtable
62
+ static const int kBuckets = 1 << 10; // For hashtable
63
+ diff --git a/src/profiler.cc b/src/profiler.cc
64
+ index d89a53a..37234b2 100644
65
+ --- a/src/profiler.cc
66
+ +++ b/src/profiler.cc
67
+ @@ -87,6 +87,10 @@ class CpuProfiler {
68
+ // Write the data to disk (and continue profiling).
69
+ void FlushTable();
70
+
71
+ +#ifdef BUILD_FOR_RUBY
72
+ + void GcMark(void (*cb)(VALUE));
73
+ +#endif
74
+ +
75
+ bool Enabled();
76
+
77
+ void GetCurrentState(ProfilerState* state);
78
+ @@ -221,6 +225,16 @@ void CpuProfiler::FlushTable() {
79
+ EnableHandler();
80
+ }
81
+
82
+ +#ifdef BUILD_FOR_RUBY
83
+ +void CpuProfiler::GcMark(void (*cb)(VALUE)) {
84
+ + if (!collector_.enabled()) {
85
+ + return;
86
+ + }
87
+ +
88
+ + collector_.GcMark(cb);
89
+ +}
90
+ +#endif
91
+ +
92
+ bool CpuProfiler::Enabled() {
93
+ SpinLockHolder cl(&lock_);
94
+ return collector_.enabled();
95
+ @@ -300,6 +314,12 @@ extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
96
+ CpuProfiler::instance_.FlushTable();
97
+ }
98
+
99
+ +#ifdef BUILD_FOR_RUBY
100
+ +extern "C" PERFTOOLS_DLL_DECL void ProfilerGcMark(void (*cb)(VALUE)) {
101
+ + CpuProfiler::instance_.GcMark(cb);
102
+ +}
103
+ +#endif
104
+ +
105
+ extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
106
+ return CpuProfiler::instance_.Enabled();
107
+ }
@@ -0,0 +1,15 @@
1
+ diff --git a/Makefile.in b/Makefile.in
2
+ index b301f4d..969db5e 100644
3
+ --- a/Makefile.in
4
+ +++ b/Makefile.in
5
+ @@ -65,9 +65,7 @@ host_triplet = @host@
6
+ @ENABLE_FRAME_POINTERS_TRUE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@am__append_3 = -fno-omit-frame-pointer
7
+ @ENABLE_FRAME_POINTERS_FALSE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@am__append_4 = -DNO_FRAME_POINTER
8
+ @MINGW_TRUE@am__append_5 = -Wl,-u__tcmalloc
9
+ -noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
10
+ - $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
11
+ - $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_23)
12
+ +noinst_PROGRAMS =
13
+ bin_PROGRAMS =
14
+ @MINGW_TRUE@am__append_6 = libwindows.la libspinlock.la
15
+
@@ -0,0 +1,85 @@
1
+ diff --git a/src/profile-handler.cc b/src/profile-handler.cc
2
+ index 5df5054..2335617 100644
3
+ --- a/src/profile-handler.cc
4
+ +++ b/src/profile-handler.cc
5
+ @@ -395,6 +395,8 @@ void ProfileHandler::GetState(ProfileHandlerState* state) {
6
+ }
7
+
8
+ void ProfileHandler::StartTimer() {
9
+ + if (getenv("CPUPROFILE_OBJECTS") || getenv("CPUPROFILE_METHODS")) return;
10
+ +
11
+ struct itimerval timer;
12
+ timer.it_interval.tv_sec = 0;
13
+ timer.it_interval.tv_usec = 1000000 / frequency_;
14
+ @@ -403,12 +405,16 @@ void ProfileHandler::StartTimer() {
15
+ }
16
+
17
+ void ProfileHandler::StopTimer() {
18
+ + if (getenv("CPUPROFILE_OBJECTS") || getenv("CPUPROFILE_METHODS")) return;
19
+ +
20
+ struct itimerval timer;
21
+ memset(&timer, 0, sizeof timer);
22
+ setitimer(timer_type_, &timer, 0);
23
+ }
24
+
25
+ bool ProfileHandler::IsTimerRunning() {
26
+ + if (getenv("CPUPROFILE_OBJECTS") || getenv("CPUPROFILE_METHODS")) return false;
27
+ +
28
+ struct itimerval current_timer;
29
+ RAW_CHECK(0 == getitimer(timer_type_, &current_timer), "getitimer");
30
+ return (current_timer.it_value.tv_sec != 0 ||
31
+ @@ -416,6 +422,8 @@ bool ProfileHandler::IsTimerRunning() {
32
+ }
33
+
34
+ void ProfileHandler::EnableHandler() {
35
+ + if (getenv("CPUPROFILE_OBJECTS") || getenv("CPUPROFILE_METHODS")) return;
36
+ +
37
+ struct sigaction sa;
38
+ sa.sa_sigaction = SignalHandler;
39
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
40
+ @@ -425,6 +433,8 @@ void ProfileHandler::EnableHandler() {
41
+ }
42
+
43
+ void ProfileHandler::DisableHandler() {
44
+ + if (getenv("CPUPROFILE_OBJECTS") || getenv("CPUPROFILE_METHODS")) return;
45
+ +
46
+ struct sigaction sa;
47
+ sa.sa_handler = SIG_IGN;
48
+ sa.sa_flags = SA_RESTART;
49
+ diff --git a/src/profiler.cc b/src/profiler.cc
50
+ index f408cf8..7645c45 100644
51
+ --- a/src/profiler.cc
52
+ +++ b/src/profiler.cc
53
+ @@ -102,6 +102,10 @@ class CpuProfiler {
54
+
55
+ static CpuProfiler instance_;
56
+
57
+ + // Signal handler that records the interrupted pc in the profile data.
58
+ + static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
59
+ + void* cpu_profiler);
60
+ +
61
+ private:
62
+ // This lock implements the locking requirements described in the ProfileData
63
+ // documentation, specifically:
64
+ @@ -130,10 +134,6 @@ class CpuProfiler {
65
+
66
+ // Disables receiving SIGPROF interrupt.
67
+ void DisableHandler();
68
+ -
69
+ - // Signal handler that records the interrupted pc in the profile data.
70
+ - static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
71
+ - void* cpu_profiler);
72
+ };
73
+
74
+ // Profile data structure singleton: Constructor will check to see if
75
+ @@ -323,6 +323,10 @@ extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
76
+ extern "C" PERFTOOLS_DLL_DECL void ProfilerGcMark(void (*cb)(VALUE)) {
77
+ CpuProfiler::instance_.GcMark(cb);
78
+ }
79
+ +
80
+ +extern "C" PERFTOOLS_DLL_DECL void ProfilerRecord(int sig, siginfo_t* info, void* signal_ucontext) {
81
+ + CpuProfiler::prof_handler(sig, info, signal_ucontext, (void*)&CpuProfiler::instance_);
82
+ +}
83
+ #endif
84
+
85
+ extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
@@ -0,0 +1,13 @@
1
+ diff --git a/Makefile.in b/Makefile.in
2
+ index 566d77c..c3bf409 100644
3
+ --- a/Makefile.in
4
+ +++ b/Makefile.in
5
+ @@ -1397,7 +1397,7 @@ INSTALL_DATA = @INSTALL_DATA@
6
+ INSTALL_PROGRAM = @INSTALL_PROGRAM@
7
+ INSTALL_SCRIPT = @INSTALL_SCRIPT@
8
+ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
9
+ -LDFLAGS = @LDFLAGS@
10
+ +LDFLAGS = @LDFLAGS@ -Wl,-flat_namespace,-undefined,dynamic_lookup
11
+ LIBOBJS = @LIBOBJS@
12
+ LIBS = @LIBS@
13
+ LIBSTDCXX_LA_LINKER_FLAG = @LIBSTDCXX_LA_LINKER_FLAG@
@@ -0,0 +1,76 @@
1
+ commit 1828f461a3ea523b7018d03ab83850621cf66ba9
2
+ Author: Aman Gupta <aman@tmm1.net>
3
+ Date: Fri Nov 12 16:33:15 2010 -0600
4
+
5
+ perftools-pprof
6
+
7
+ diff --git a/src/pprof b/src/pprof
8
+ index e67e42e..b04d988 100755
9
+ --- a/src/pprof
10
+ +++ b/src/pprof
11
+ @@ -560,7 +560,8 @@ sub Main() {
12
+ my $symbol_map = {};
13
+
14
+ # Read one profile, pick the last item on the list
15
+ - my $data = ReadProfile($main::prog, pop(@main::profile_files));
16
+ + my $fname = pop(@main::profile_files);
17
+ + my $data = ReadProfile($main::prog, $fname);
18
+ my $profile = $data->{profile};
19
+ my $pcs = $data->{pcs};
20
+ my $libs = $data->{libs}; # Info about main program and shared libraries
21
+ @@ -589,7 +590,18 @@ sub Main() {
22
+
23
+ # Collect symbols
24
+ my $symbols;
25
+ - if ($main::use_symbolized_profile) {
26
+ + if (-e "$fname.symbols") {
27
+ + open(SYMBOLS, "<$fname.symbols");
28
+ + while(<SYMBOLS>){
29
+ + chop;
30
+ + if (m/(.+?)\s*:\s*(.*)/){
31
+ + $symbols->{$1}[0] = $2;
32
+ + $symbols->{$1}[1] = "?";
33
+ + $symbols->{$1}[2] = $2;
34
+ + }
35
+ + }
36
+ + close(SYMBOLS);
37
+ + } elsif ($main::use_symbolized_profile) {
38
+ $symbols = FetchSymbols($pcs, $symbol_map);
39
+ } elsif ($main::use_symbol_page) {
40
+ $symbols = FetchSymbols($pcs);
41
+ @@ -2425,6 +2437,10 @@ sub RemoveUninterestingFrames {
42
+ foreach my $name ('ProfileData::Add', # historical
43
+ 'ProfileData::prof_handler', # historical
44
+ 'CpuProfiler::prof_handler',
45
+ + 'PerfTools::CpuProfiler.start',
46
+ + 'Array#each',
47
+ + 'Proc#call',
48
+ + 'Class#new',
49
+ '__FRAME_END__',
50
+ '__pthread_sighandler',
51
+ '__restore') {
52
+ @@ -2434,6 +2450,7 @@ sub RemoveUninterestingFrames {
53
+ # Nothing skipped for unknown types
54
+ }
55
+
56
+ +=pod
57
+ if ($main::profile_type eq 'cpu') {
58
+ # If all the second-youngest program counters are the same,
59
+ # this STRONGLY suggests that it is an artifact of measurement,
60
+ @@ -2458,6 +2475,7 @@ sub RemoveUninterestingFrames {
61
+ $profile = $result;
62
+ }
63
+ }
64
+ +=cut
65
+
66
+ my $result = {};
67
+ foreach my $k (keys(%{$profile})) {
68
+ @@ -3360,7 +3378,7 @@ sub ReadCPUProfile {
69
+ # file, in which case the subtract-one was done when the file
70
+ # was written.
71
+ if ($j > 0 && !$main::use_symbolized_profile) {
72
+ - $pc--;
73
+ + # $pc--;
74
+ }
75
+ $pc = sprintf("%0*x", $address_length, $pc);
76
+ $pcs->{$pc} = 1;
@@ -0,0 +1,34 @@
1
+ Only in ./: perftools-stddef.patch
2
+ diff -ru .//src/base/vdso_support.h ../google-perftools-1.6-patched/src/base/vdso_support.h
3
+ --- .//src/base/vdso_support.h 2010-08-03 03:32:20.000000000 +0800
4
+ +++ ../google-perftools-1.6-patched/src/base/vdso_support.h 2011-06-16 14:33:10.000000000 +0800
5
+ @@ -38,6 +38,7 @@
6
+ #define HAVE_VDSO_SUPPORT 1
7
+
8
+ #include <stdlib.h> // for NULL
9
+ +#include <stddef.h>
10
+ #include <link.h> // for ElfW
11
+ #include "base/basictypes.h"
12
+
13
+ diff -ru .//src/symbolize.h ../google-perftools-1.6-patched/src/symbolize.h
14
+ --- .//src/symbolize.h 2009-11-11 03:59:46.000000000 +0800
15
+ +++ ../google-perftools-1.6-patched/src/symbolize.h 2011-06-16 14:32:55.000000000 +0800
16
+ @@ -38,6 +38,7 @@
17
+ #include <stdint.h> // for uintptr_t
18
+ #endif
19
+ #include <map>
20
+ +#include <stddef.h>
21
+
22
+ using std::map;
23
+
24
+ diff -ru .//src/system-alloc.h ../google-perftools-1.6-patched/src/system-alloc.h
25
+ --- .//src/system-alloc.h 2010-04-01 07:50:18.000000000 +0800
26
+ +++ ../google-perftools-1.6-patched/src/system-alloc.h 2011-06-16 14:32:38.000000000 +0800
27
+ @@ -38,6 +38,7 @@
28
+
29
+ #include <config.h>
30
+ #include "internal_logging.h"
31
+ +#include <stddef.h>
32
+
33
+ // REQUIRES: "alignment" is a power of two or "0" to indicate default alignment
34
+ //
@@ -0,0 +1,266 @@
1
+ diff --git a/Makefile.in b/Makefile.in
2
+ index 232d2ec..566d77c 100644
3
+ --- a/Makefile.in
4
+ +++ b/Makefile.in
5
+ @@ -1367,13 +1367,13 @@ AUTOMAKE = @AUTOMAKE@
6
+ AWK = @AWK@
7
+ CC = @CC@
8
+ CCDEPMODE = @CCDEPMODE@
9
+ -CFLAGS = @CFLAGS@
10
+ +CFLAGS = @CFLAGS@ -DBUILD_FOR_RUBY -fPIC
11
+ CPP = @CPP@
12
+ CPPFLAGS = @CPPFLAGS@
13
+ CXX = @CXX@
14
+ CXXCPP = @CXXCPP@
15
+ CXXDEPMODE = @CXXDEPMODE@
16
+ -CXXFLAGS = @CXXFLAGS@
17
+ +CXXFLAGS = @CXXFLAGS@ -DBUILD_FOR_RUBY -fPIC
18
+ CYGPATH_W = @CYGPATH_W@
19
+ DEFS = @DEFS@
20
+ DEPDIR = @DEPDIR@
21
+ diff --git a/src/profile-handler.cc b/src/profile-handler.cc
22
+ index e658d30..370d012 100644
23
+ --- a/src/profile-handler.cc
24
+ +++ b/src/profile-handler.cc
25
+ @@ -264,6 +264,11 @@ ProfileHandler::~ProfileHandler() {
26
+ void ProfileHandler::RegisterThread() {
27
+ SpinLockHolder cl(&control_lock_);
28
+
29
+ +#ifdef BUILD_FOR_RUBY
30
+ + timer_sharing_ = TIMERS_SHARED;
31
+ + if (callback_count_ > 0 && !IsTimerRunning())
32
+ + StartTimer();
33
+ +#else
34
+ // We try to detect whether timers are being shared by setting a
35
+ // timer in the first call to this function, then checking whether
36
+ // it's set in the second call.
37
+ @@ -305,6 +310,7 @@ void ProfileHandler::RegisterThread() {
38
+ StartTimer();
39
+ break;
40
+ }
41
+ +#endif
42
+ }
43
+
44
+ ProfileHandlerToken* ProfileHandler::RegisterCallback(
45
+ diff --git a/src/profiledata.cc b/src/profiledata.cc
46
+ index 5f2531b..ea95493 100644
47
+ --- a/src/profiledata.cc
48
+ +++ b/src/profiledata.cc
49
+ @@ -56,6 +56,19 @@ const int ProfileData::kAssociativity;
50
+ const int ProfileData::kBuckets;
51
+ const int ProfileData::kBufferLength;
52
+
53
+ +#ifdef BUILD_FOR_RUBY
54
+ +extern "C" {
55
+ + typedef unsigned long ID;
56
+ + typedef unsigned long VALUE;
57
+ +
58
+ + void rb_gc();
59
+ + const char *rb_id2name(ID);
60
+ + const char *rb_class2name(VALUE);
61
+ +}
62
+ +
63
+ +#include <set>
64
+ +#endif
65
+ +
66
+ ProfileData::Options::Options()
67
+ : frequency_(1) {
68
+ }
69
+ @@ -63,17 +76,33 @@ ProfileData::Options::Options()
70
+ // This function is safe to call from asynchronous signals (but is not
71
+ // re-entrant). However, that's not part of its public interface.
72
+ void ProfileData::Evict(const Entry& entry) {
73
+ +#ifdef BUILD_FOR_RUBY
74
+ + const int d = entry.depth == 1 ? 1 : entry.depth/3;
75
+ +#else
76
+ const int d = entry.depth;
77
+ +#endif
78
+ const int nslots = d + 2; // Number of slots needed in eviction buffer
79
+ +
80
+ if (num_evicted_ + nslots > kBufferLength) {
81
+ FlushEvicted();
82
+ assert(num_evicted_ == 0);
83
+ assert(nslots <= kBufferLength);
84
+ }
85
+ +
86
+ evict_[num_evicted_++] = entry.count;
87
+ evict_[num_evicted_++] = d;
88
+ +
89
+ +#ifdef BUILD_FOR_RUBY
90
+ + if (entry.depth > 1) {
91
+ + for (int n=0; n<entry.depth; n+=3)
92
+ + evict_[num_evicted_++] = entry.stack[n] + entry.stack[n+1] + entry.stack[n+2];
93
+ + } else if (entry.depth == 1) {
94
+ + evict_[num_evicted_++] = entry.stack[0];
95
+ + }
96
+ +#else
97
+ memcpy(&evict_[num_evicted_], entry.stack, d * sizeof(Slot));
98
+ num_evicted_ += d;
99
+ +#endif
100
+ }
101
+
102
+ ProfileData::ProfileData()
103
+ @@ -85,6 +114,7 @@ ProfileData::ProfileData()
104
+ evictions_(0),
105
+ total_bytes_(0),
106
+ fname_(0),
107
+ + sym_fname_(0),
108
+ start_time_(0) {
109
+ }
110
+
111
+ @@ -101,6 +131,13 @@ bool ProfileData::Start(const char* fname,
112
+ return false;
113
+ }
114
+
115
+ +#ifdef BUILD_FOR_RUBY
116
+ + int len = strlen(fname);
117
+ + sym_fname_ = (char*)malloc((len+9) * sizeof(char));
118
+ + strncpy(sym_fname_, fname, len);
119
+ + strcpy(sym_fname_+len, ".symbols");
120
+ +#endif
121
+ +
122
+ start_time_ = time(NULL);
123
+ fname_ = strdup(fname);
124
+
125
+ @@ -166,16 +203,61 @@ void ProfileData::Stop() {
126
+ return;
127
+ }
128
+
129
+ +#ifdef BUILD_FOR_RUBY
130
+ + FILE *symbols;
131
+ + int precision;
132
+ +
133
+ + symbols = fopen(sym_fname_, "w");
134
+ + if (!symbols) {
135
+ + fprintf(stderr, "PROFILER ERROR: Unable to open %s (%s)\n", sym_fname_, strerror(errno));
136
+ + Reset();
137
+ + return;
138
+ + }
139
+ +
140
+ + precision = sizeof(unsigned long)*2;
141
+ + fprintf(symbols, "%0*lx: garbage_collector\n", precision, (ID)rb_gc);
142
+ +
143
+ + std::set<ID> known_symbols;
144
+ +#endif
145
+ +
146
+ // Move data from hash table to eviction buffer
147
+ for (int b = 0; b < kBuckets; b++) {
148
+ Bucket* bucket = &hash_[b];
149
+ for (int a = 0; a < kAssociativity; a++) {
150
+ if (bucket->entry[a].count > 0) {
151
+ - Evict(bucket->entry[a]);
152
+ + Entry e = bucket->entry[a];
153
+ + Evict(e);
154
+ +#ifdef BUILD_FOR_RUBY
155
+ + if (e.depth > 1) {
156
+ + for (int n=0; n<e.depth; n+=3) {
157
+ + VALUE self = e.stack[n];
158
+ + VALUE klass = e.stack[n+1];
159
+ + ID method = e.stack[n+2];
160
+ +
161
+ + ID sym = self + klass + method; // unique identifer
162
+ +
163
+ + if (known_symbols.find(sym) == known_symbols.end()) {
164
+ + fprintf(symbols, "%0*lx: ", precision, sym);
165
+ +
166
+ + if (self) { // class method
167
+ + fprintf(symbols, "%s.%s\n", rb_class2name(self), rb_id2name(method));
168
+ + } else { // instance method
169
+ + fprintf(symbols, "%s#%s\n", rb_class2name(klass), rb_id2name(method));
170
+ + }
171
+ +
172
+ + known_symbols.insert(sym);
173
+ + }
174
+ + }
175
+ + }
176
+ +#endif
177
+ }
178
+ }
179
+ }
180
+
181
+ +#ifdef BUILD_FOR_RUBY
182
+ + fclose(symbols);
183
+ +#endif
184
+ +
185
+ if (num_evicted_ + 3 > kBufferLength) {
186
+ // Ensure there is enough room for end of data marker
187
+ FlushEvicted();
188
+ @@ -211,6 +293,10 @@ void ProfileData::Reset() {
189
+ num_evicted_ = 0;
190
+ free(fname_);
191
+ fname_ = 0;
192
+ +#ifdef BUILD_FOR_RUBY
193
+ + free(sym_fname_);
194
+ + sym_fname_ = 0;
195
+ +#endif
196
+ start_time_ = 0;
197
+
198
+ out_ = -1;
199
+ diff --git a/src/profiledata.h b/src/profiledata.h
200
+ index da7ea9e..67c463d 100644
201
+ --- a/src/profiledata.h
202
+ +++ b/src/profiledata.h
203
+ @@ -169,6 +169,7 @@ class ProfileData {
204
+ int evictions_; // How many evictions
205
+ size_t total_bytes_; // How much output
206
+ char* fname_; // Profile file name
207
+ + char* sym_fname_; // Symbol file name
208
+ time_t start_time_; // Start time, or 0
209
+
210
+ // Move 'entry' to the eviction buffer.
211
+ diff --git a/src/profiler.cc b/src/profiler.cc
212
+ index 183a7c7..d89a53a 100644
213
+ --- a/src/profiler.cc
214
+ +++ b/src/profiler.cc
215
+ @@ -63,6 +63,12 @@ typedef int ucontext_t; // just to quiet the compiler, mostly
216
+ #include "conflict-signal.h" /* used on msvc machines */
217
+ #endif
218
+
219
+ +#ifdef BUILD_FOR_RUBY
220
+ +extern "C" {
221
+ + int rb_stack_trace(void**,int);
222
+ +}
223
+ +#endif
224
+ +
225
+ using std::string;
226
+
227
+ // Collects up all profile data. This is a singleton, which is
228
+ @@ -261,6 +267,9 @@ void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
229
+ (*instance->filter_)(instance->filter_arg_)) {
230
+ void* stack[ProfileData::kMaxStackDepth];
231
+
232
+ +#ifdef BUILD_FOR_RUBY
233
+ + int depth = rb_stack_trace(stack, arraysize(stack));
234
+ +#else
235
+ // The top-most active routine doesn't show up as a normal
236
+ // frame, but as the "pc" value in the signal handler context.
237
+ stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
238
+ @@ -274,8 +283,10 @@ void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
239
+ int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
240
+ 2, signal_ucontext);
241
+ depth++; // To account for pc value in stack[0];
242
+ +#endif
243
+
244
+ - instance->collector_.Add(depth, stack);
245
+ + if (depth > 0)
246
+ + instance->collector_.Add(depth, stack);
247
+ }
248
+ }
249
+
250
+ diff --git a/src/stacktrace.cc b/src/stacktrace.cc
251
+ index d158eea..e8509fe 100644
252
+ --- a/src/stacktrace.cc
253
+ +++ b/src/stacktrace.cc
254
+ @@ -52,6 +52,7 @@
255
+ // correctly when GetStackTrace() is called with max_depth == 0.
256
+ // Some code may do that.
257
+
258
+ +#ifndef BUILD_FOR_RUBY
259
+ #include <config.h>
260
+ #include <google/stacktrace.h>
261
+ #include "stacktrace_config.h"
262
+ @@ -69,3 +70,4 @@
263
+ #else
264
+ # error Cannot calculate stack trace: will need to write for your environment
265
+ #endif
266
+ +#endif