perftools.rb 0.2.5 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +0 -1
- data/ext/extconf.rb +70 -44
- data/ext/perftools.c +138 -56
- data/ext/src/google-perftools-1.4.tar.gz +0 -0
- data/patches/perftools-debug.patch +2 -2
- data/patches/perftools-gc.patch +11 -11
- data/patches/perftools-osx-106.patch +96 -0
- data/patches/perftools-osx.patch +2 -2
- data/patches/perftools-pprof.patch +56 -0
- data/patches/perftools.patch +4 -36
- data/perftools.rb.gemspec +7 -4
- metadata +6 -3
data/README
CHANGED
data/ext/extconf.rb
CHANGED
@@ -1,67 +1,93 @@
|
|
1
|
-
|
1
|
+
CWD = File.expand_path(File.dirname(__FILE__))
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
def sys(cmd)
|
4
|
+
puts " -- #{cmd}"
|
5
|
+
unless ret = xsystem(cmd)
|
6
|
+
raise "#{cmd} failed, please report to perftools@tmm1.net with pastie.org link to #{CWD}/mkmf.log and #{CWD}/src/google-perftools-1.4/config.log"
|
7
|
+
end
|
8
|
+
ret
|
5
9
|
end
|
6
10
|
|
11
|
+
require 'mkmf'
|
7
12
|
require 'fileutils'
|
8
|
-
require 'net/http'
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
if RUBY_VERSION >= "1.9"
|
15
|
+
begin
|
16
|
+
require "ruby_core_source"
|
17
|
+
rescue LoadError
|
18
|
+
STDERR.puts "\n\n"
|
19
|
+
STDERR.puts "***************************************************************************************"
|
20
|
+
STDERR.puts "******************** PLEASE RUN gem install ruby_core_source FIRST ********************"
|
21
|
+
STDERR.puts "***************************************************************************************"
|
22
|
+
exit(1)
|
23
|
+
end
|
24
|
+
end
|
15
25
|
|
16
|
-
|
26
|
+
perftools = File.basename('google-perftools-1.4.tar.gz')
|
27
|
+
dir = File.basename(perftools, '.tar.gz')
|
17
28
|
|
18
|
-
|
19
|
-
proxy_host = proxy.host
|
20
|
-
proxy_port = proxy.port
|
21
|
-
proxy_user, proxy_pass = proxy.userinfo.split(/:/) if proxy.userinfo
|
22
|
-
end
|
29
|
+
puts "(I'm about to compile google-perftools.. this will definitely take a while)"
|
23
30
|
|
24
31
|
Dir.chdir('src') do
|
25
|
-
|
26
|
-
Net::HTTP::Proxy(proxy_host, proxy_port, proxy_user, proxy_pass).get_response(URI(url)) do |res|
|
27
|
-
File.open(perftools, 'wb') do |out|
|
28
|
-
res.read_body do |chunk|
|
29
|
-
out.write(chunk)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
32
|
+
FileUtils.rm_rf(dir) if File.exists?(dir)
|
34
33
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
34
|
+
sys("tar zxvf #{perftools}")
|
35
|
+
Dir.chdir(dir) do
|
36
|
+
sys("patch -p1 < ../../../patches/perftools.patch")
|
37
|
+
sys("patch -p1 < ../../../patches/perftools-pprof.patch")
|
38
|
+
sys("patch -p1 < ../../../patches/perftools-gc.patch")
|
39
|
+
sys("patch -p1 < ../../../patches/perftools-osx.patch") if RUBY_PLATFORM =~ /darwin/
|
40
|
+
sys("patch -p1 < ../../../patches/perftools-osx-106.patch") if RUBY_PLATFORM =~ /darwin10/
|
41
|
+
sys("patch -p1 < ../../../patches/perftools-debug.patch")
|
43
42
|
end
|
44
43
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
44
|
+
Dir.chdir(dir) do
|
45
|
+
FileUtils.cp 'src/pprof', '../../../bin/'
|
46
|
+
FileUtils.chmod 0755, '../../../bin/pprof'
|
49
47
|
end
|
50
48
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
xsystem("make")
|
55
|
-
FileUtils.cp '.libs/libprofiler.a', '../../librubyprofiler.a'
|
49
|
+
Dir.chdir(dir) do
|
50
|
+
if RUBY_PLATFORM =~ /darwin10/
|
51
|
+
ENV['CFLAGS'] = ENV['CXXFLAGS'] = '-D_XOPEN_SOURCE'
|
56
52
|
end
|
53
|
+
sys("./configure --disable-heap-profiler --disable-heap-checker --disable-shared")
|
54
|
+
sys("make")
|
55
|
+
FileUtils.cp '.libs/libprofiler.a', '../../librubyprofiler.a'
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
59
|
+
$LIBPATH << CWD
|
60
|
+
$libs = append_library($libs, 'rubyprofiler')
|
61
|
+
def add_define(name)
|
62
|
+
$defs.push("-D#{name}")
|
63
|
+
end
|
64
|
+
|
60
65
|
case RUBY_PLATFORM
|
61
66
|
when /darwin/, /linux/
|
62
67
|
CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ')
|
63
68
|
end
|
64
69
|
|
65
|
-
|
66
|
-
|
67
|
-
|
70
|
+
if RUBY_VERSION >= "1.9"
|
71
|
+
add_define 'RUBY19'
|
72
|
+
|
73
|
+
hdrs = proc {
|
74
|
+
have_header("vm_core.h") and
|
75
|
+
have_header("iseq.h") and
|
76
|
+
have_header("insns.inc") and
|
77
|
+
have_header("insns_info.inc")
|
78
|
+
}
|
79
|
+
have_func('rb_during_gc', 'ruby.h')
|
80
|
+
|
81
|
+
unless Ruby_core_source::create_makefile_with_core(hdrs, "perftools")
|
82
|
+
STDERR.puts "\n\n"
|
83
|
+
STDERR.puts "***************************************************************************************"
|
84
|
+
STDERR.puts "********************** Ruby_core_source::create_makefile FAILED ***********************"
|
85
|
+
STDERR.puts "***************************************************************************************"
|
86
|
+
exit(1)
|
87
|
+
end
|
88
|
+
else
|
89
|
+
add_define 'RUBY18'
|
90
|
+
|
91
|
+
have_func('rb_during_gc', 'ruby.h')
|
92
|
+
create_makefile 'perftools'
|
93
|
+
end
|
data/ext/perftools.c
CHANGED
@@ -1,78 +1,160 @@
|
|
1
1
|
#include <ruby.h>
|
2
|
-
#include <node.h>
|
3
|
-
#include <env.h>
|
4
|
-
|
5
2
|
static VALUE Iallocate;
|
6
3
|
static VALUE I__send__;
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
if (FL_TEST(klass, FL_SINGLETON) &&
|
20
|
-
(BUILTIN_TYPE(frame->self) == T_CLASS || BUILTIN_TYPE(frame->self) == T_MODULE))
|
21
|
-
result[(*depth)++] = (void*) frame->self;
|
22
|
-
else
|
23
|
-
result[(*depth)++] = 0;
|
24
|
-
|
25
|
-
result[(*depth)++] = (void*) klass;
|
26
|
-
result[(*depth)++] = (void*) (frame->last_func == ID_ALLOCATOR ? Iallocate : frame->last_func);
|
27
|
-
}
|
5
|
+
#define SAVE_FRAME() \
|
6
|
+
if (method != I__send__) { \
|
7
|
+
if (FL_TEST(klass, FL_SINGLETON) && (BUILTIN_TYPE(self) == T_CLASS || BUILTIN_TYPE(self) == T_MODULE)) \
|
8
|
+
result[depth++] = (void*) self; \
|
9
|
+
else \
|
10
|
+
result[depth++] = 0; \
|
11
|
+
\
|
12
|
+
result[depth++] = (void*) klass; \
|
13
|
+
result[depth++] = (void*) (method == ID_ALLOCATOR ? Iallocate : method); \
|
14
|
+
}
|
28
15
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
16
|
+
#ifdef RUBY18
|
17
|
+
#include <node.h>
|
18
|
+
#include <env.h>
|
19
|
+
|
20
|
+
int
|
21
|
+
rb_stack_trace(void** result, int max_depth)
|
22
|
+
{
|
23
|
+
struct FRAME *frame = ruby_frame;
|
24
|
+
NODE *n;
|
25
|
+
|
26
|
+
VALUE klass, self;
|
27
|
+
ID method;
|
28
|
+
int depth = 0;
|
29
|
+
|
30
|
+
if (max_depth == 0)
|
31
|
+
return 0;
|
35
32
|
|
36
|
-
|
37
|
-
|
33
|
+
#ifdef HAVE_RB_DURING_GC
|
34
|
+
if (rb_during_gc()) {
|
35
|
+
result[0] = rb_gc;
|
36
|
+
return 1;
|
37
|
+
}
|
38
|
+
#endif
|
39
|
+
|
40
|
+
/*
|
41
|
+
// XXX does it make sense to track allocations or not?
|
42
|
+
if (frame->last_func == ID_ALLOCATOR) {
|
43
|
+
frame = frame->prev;
|
44
|
+
}
|
45
|
+
|
46
|
+
// XXX SIGPROF can come in while ruby_frame is in an inconsistent state (rb_call0), so we ignore the top-most frame
|
47
|
+
if (frame->last_func) {
|
48
|
+
self = frame->self;
|
49
|
+
klass = frame->last_class;
|
50
|
+
method = frame->last_func;
|
51
|
+
SAVE_FRAME();
|
52
|
+
}
|
53
|
+
*/
|
54
|
+
|
55
|
+
for (; frame && (n = frame->node); frame = frame->prev) {
|
56
|
+
if (frame->prev && frame->prev->last_func) {
|
57
|
+
if (frame->prev->node == n) {
|
58
|
+
if (frame->prev->last_func == frame->last_func) continue;
|
59
|
+
}
|
38
60
|
|
39
|
-
|
40
|
-
|
61
|
+
if (depth+3 > max_depth)
|
62
|
+
break;
|
63
|
+
|
64
|
+
self = frame->prev->self;
|
65
|
+
klass = frame->prev->last_class;
|
66
|
+
method = frame->prev->last_func;
|
67
|
+
SAVE_FRAME();
|
68
|
+
}
|
69
|
+
}
|
41
70
|
|
42
|
-
|
43
|
-
if (rb_during_gc()) {
|
44
|
-
result[0] = rb_gc;
|
45
|
-
return 1;
|
71
|
+
return depth;
|
46
72
|
}
|
47
73
|
#endif
|
48
74
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
if (frame->last_func == ID_ALLOCATOR) {
|
53
|
-
frame = frame->prev;
|
54
|
-
}
|
75
|
+
#ifdef RUBY19
|
76
|
+
#include <vm_core.h>
|
77
|
+
#include <iseq.h>
|
55
78
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
79
|
+
int
|
80
|
+
rb_stack_trace(void** result, int max_depth)
|
81
|
+
{
|
82
|
+
rb_thread_t *th = GET_THREAD();
|
83
|
+
rb_control_frame_t *cfp = th->cfp;
|
84
|
+
rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th);
|
85
|
+
|
86
|
+
VALUE klass, self;
|
87
|
+
ID method;
|
88
|
+
int depth = 0;
|
89
|
+
|
90
|
+
if (max_depth == 0)
|
91
|
+
return 0;
|
92
|
+
|
93
|
+
#ifdef HAVE_RB_DURING_GC
|
94
|
+
if (rb_during_gc()) {
|
95
|
+
result[0] = rb_gc;
|
96
|
+
return 1;
|
97
|
+
}
|
98
|
+
#endif
|
99
|
+
|
100
|
+
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp) && depth+3 < max_depth) {
|
101
|
+
rb_iseq_t *iseq = cfp->iseq;
|
60
102
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
103
|
+
if (iseq && iseq->type == ISEQ_TYPE_METHOD) {
|
104
|
+
self = iseq->self;
|
105
|
+
klass = iseq->klass;
|
106
|
+
method = iseq->defined_method_id;
|
107
|
+
SAVE_FRAME();
|
65
108
|
}
|
66
109
|
|
67
|
-
|
68
|
-
|
110
|
+
switch(VM_FRAME_TYPE(cfp)) {
|
111
|
+
case VM_FRAME_MAGIC_METHOD:
|
112
|
+
case VM_FRAME_MAGIC_CFUNC:
|
113
|
+
self = cfp->self;
|
114
|
+
klass = cfp->method_class;
|
115
|
+
method = cfp->method_id;
|
116
|
+
SAVE_FRAME();
|
117
|
+
break;
|
118
|
+
}
|
69
119
|
|
70
|
-
|
120
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
71
121
|
}
|
122
|
+
|
123
|
+
return depth;
|
72
124
|
}
|
73
125
|
|
74
|
-
|
75
|
-
|
126
|
+
#if 0
|
127
|
+
void
|
128
|
+
rb_dump_stack()
|
129
|
+
{
|
130
|
+
rb_thread_t *th = GET_THREAD();
|
131
|
+
rb_control_frame_t *cfp = th->cfp;
|
132
|
+
rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th);
|
133
|
+
ID func;
|
134
|
+
|
135
|
+
printf("\n\n*********************\n");
|
136
|
+
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
|
137
|
+
printf("cfp (%p):\n", cfp);
|
138
|
+
printf(" type: 0x%x\n", VM_FRAME_TYPE(cfp));
|
139
|
+
printf(" pc: %p\n", cfp->pc);
|
140
|
+
printf(" iseq: %p\n", cfp->iseq);
|
141
|
+
if (cfp->iseq) {
|
142
|
+
printf(" type: %d\n", FIX2INT(cfp->iseq->type));
|
143
|
+
printf(" self: %p\n", cfp->iseq->self);
|
144
|
+
printf(" klass: %p (%s)\n", cfp->iseq->klass, cfp->iseq->klass ? rb_class2name(cfp->iseq->klass) : "");
|
145
|
+
printf(" method: %p (%s)\n", cfp->iseq->defined_method_id, cfp->iseq->defined_method_id ? rb_id2name(cfp->iseq->defined_method_id) : "");
|
146
|
+
}
|
147
|
+
printf(" self: %p\n", cfp->self);
|
148
|
+
printf(" klass: %p (%s)\n", cfp->method_class, cfp->method_class ? rb_class2name(cfp->method_class) : "");
|
149
|
+
printf(" method: %p (%s)\n", cfp->method_id, cfp->method_id ? rb_id2name(cfp->method_id) : "");
|
150
|
+
|
151
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
152
|
+
printf("\n");
|
153
|
+
}
|
154
|
+
printf("*********************\n\n");
|
155
|
+
}
|
156
|
+
#endif
|
157
|
+
#endif
|
76
158
|
|
77
159
|
static VALUE cPerfTools;
|
78
160
|
static VALUE cCpuProfiler;
|
Binary file
|
@@ -1,8 +1,8 @@
|
|
1
1
|
diff --git a/Makefile.in b/Makefile.in
|
2
|
-
index
|
2
|
+
index c3bf409..c613939 100644
|
3
3
|
--- a/Makefile.in
|
4
4
|
+++ b/Makefile.in
|
5
|
-
@@ -
|
5
|
+
@@ -1367,13 +1367,13 @@ AUTOMAKE = @AUTOMAKE@
|
6
6
|
AWK = @AWK@
|
7
7
|
CC = @CC@
|
8
8
|
CCDEPMODE = @CCDEPMODE@
|
data/patches/perftools-gc.patch
CHANGED
@@ -33,7 +33,7 @@ index e6240d9..b901ee8 100644
|
|
33
33
|
if (!enabled()) {
|
34
34
|
return;
|
35
35
|
diff --git a/src/profiledata.h b/src/profiledata.h
|
36
|
-
index 67c463d..
|
36
|
+
index 67c463d..a68e12f 100644
|
37
37
|
--- a/src/profiledata.h
|
38
38
|
+++ b/src/profiledata.h
|
39
39
|
@@ -40,6 +40,12 @@
|
@@ -54,14 +54,14 @@ index 67c463d..1df79c2 100644
|
|
54
54
|
void GetCurrentState(State* state) const;
|
55
55
|
|
56
56
|
+#ifdef BUILD_FOR_RUBY
|
57
|
-
+
|
57
|
+
+ void GcMark(void (*cb)(VALUE));
|
58
58
|
+#endif
|
59
59
|
+
|
60
60
|
private:
|
61
61
|
static const int kAssociativity = 4; // For hashtable
|
62
62
|
static const int kBuckets = 1 << 10; // For hashtable
|
63
63
|
diff --git a/src/profiler.cc b/src/profiler.cc
|
64
|
-
index
|
64
|
+
index d89a53a..37234b2 100644
|
65
65
|
--- a/src/profiler.cc
|
66
66
|
+++ b/src/profiler.cc
|
67
67
|
@@ -87,6 +87,10 @@ class CpuProfiler {
|
@@ -69,7 +69,7 @@ index 21c7669..b7277c7 100644
|
|
69
69
|
void FlushTable();
|
70
70
|
|
71
71
|
+#ifdef BUILD_FOR_RUBY
|
72
|
-
+
|
72
|
+
+ void GcMark(void (*cb)(VALUE));
|
73
73
|
+#endif
|
74
74
|
+
|
75
75
|
bool Enabled();
|
@@ -81,27 +81,27 @@ index 21c7669..b7277c7 100644
|
|
81
81
|
|
82
82
|
+#ifdef BUILD_FOR_RUBY
|
83
83
|
+void CpuProfiler::GcMark(void (*cb)(VALUE)) {
|
84
|
-
+
|
85
|
-
+
|
86
|
-
+
|
84
|
+
+ if (!collector_.enabled()) {
|
85
|
+
+ return;
|
86
|
+
+ }
|
87
87
|
+
|
88
|
-
+
|
88
|
+
+ collector_.GcMark(cb);
|
89
89
|
+}
|
90
90
|
+#endif
|
91
91
|
+
|
92
92
|
bool CpuProfiler::Enabled() {
|
93
93
|
SpinLockHolder cl(&lock_);
|
94
94
|
return collector_.enabled();
|
95
|
-
@@ -300,6 +314,12 @@ extern "C" void ProfilerFlush() {
|
95
|
+
@@ -300,6 +314,12 @@ extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
|
96
96
|
CpuProfiler::instance_.FlushTable();
|
97
97
|
}
|
98
98
|
|
99
99
|
+#ifdef BUILD_FOR_RUBY
|
100
|
-
+extern "C" void ProfilerGcMark(void (*cb)(VALUE)) {
|
100
|
+
+extern "C" PERFTOOLS_DLL_DECL void ProfilerGcMark(void (*cb)(VALUE)) {
|
101
101
|
+ CpuProfiler::instance_.GcMark(cb);
|
102
102
|
+}
|
103
103
|
+#endif
|
104
104
|
+
|
105
|
-
extern "C" int ProfilingIsEnabledForAllThreads() {
|
105
|
+
extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
|
106
106
|
return CpuProfiler::instance_.Enabled();
|
107
107
|
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
diff --git a/Makefile.in b/Makefile.in
|
2
|
+
index c613939..1a901d5 100644
|
3
|
+
--- a/Makefile.in
|
4
|
+
diff --git a/src/base/sysinfo.cc b/src/base/sysinfo.cc
|
5
|
+
index a2bc2a9..10b8886 100644
|
6
|
+
--- a/src/base/sysinfo.cc
|
7
|
+
+++ b/src/base/sysinfo.cc
|
8
|
+
@@ -728,26 +728,59 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags,
|
9
|
+
|
10
|
+
// We start with the next load command (we've already looked at this one).
|
11
|
+
for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) {
|
12
|
+
- const char* lc = ((const char *)hdr + sizeof(struct mach_header));
|
13
|
+
+ const char* lc;
|
14
|
+
+ uint32_t seg_marker;
|
15
|
+
+ #if defined(MH_MAGIC_64)
|
16
|
+
+ if (hdr->magic == MH_MAGIC_64) {
|
17
|
+
+ lc = ((const char *)hdr + sizeof(struct mach_header_64));
|
18
|
+
+ seg_marker = LC_SEGMENT_64;
|
19
|
+
+ } else {
|
20
|
+
+ #endif
|
21
|
+
+ lc = ((const char *)hdr + sizeof(struct mach_header));
|
22
|
+
+ seg_marker = LC_SEGMENT;
|
23
|
+
+ #if defined(MH_MAGIC_64)
|
24
|
+
+ }
|
25
|
+
+ #endif
|
26
|
+
// TODO(csilvers): make this not-quadradic (increment and hold state)
|
27
|
+
for (int j = 0; j < current_load_cmd_; j++) // advance to *our* load_cmd
|
28
|
+
lc += ((const load_command *)lc)->cmdsize;
|
29
|
+
- if (((const load_command *)lc)->cmd == LC_SEGMENT) {
|
30
|
+
+ if (((const load_command *)lc)->cmd == seg_marker) {
|
31
|
+
const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image_);
|
32
|
+
- const segment_command* sc = (const segment_command *)lc;
|
33
|
+
- if (start) *start = sc->vmaddr + dlloff;
|
34
|
+
- if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
|
35
|
+
- if (flags) *flags = kDefaultPerms; // can we do better?
|
36
|
+
- if (offset) *offset = sc->fileoff;
|
37
|
+
- if (inode) *inode = 0;
|
38
|
+
- if (filename)
|
39
|
+
- *filename = const_cast<char*>(_dyld_get_image_name(current_image_));
|
40
|
+
- if (file_mapping) *file_mapping = 0;
|
41
|
+
- if (file_pages) *file_pages = 0; // could we use sc->filesize?
|
42
|
+
- if (anon_mapping) *anon_mapping = 0;
|
43
|
+
- if (anon_pages) *anon_pages = 0;
|
44
|
+
- if (dev) *dev = 0;
|
45
|
+
- return true;
|
46
|
+
+ #if defined(MH_MAGIC_64)
|
47
|
+
+ if (hdr->magic == MH_MAGIC_64) {
|
48
|
+
+ const segment_command_64* sc = (const segment_command_64 *)lc;
|
49
|
+
+ if (start) *start = sc->vmaddr + dlloff;
|
50
|
+
+ if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
|
51
|
+
+ if (flags) *flags = kDefaultPerms; // can we do better?
|
52
|
+
+ if (offset) *offset = sc->fileoff;
|
53
|
+
+ if (inode) *inode = 0;
|
54
|
+
+ if (filename)
|
55
|
+
+ *filename = const_cast<char*>(_dyld_get_image_name(current_image_));
|
56
|
+
+ if (file_mapping) *file_mapping = 0;
|
57
|
+
+ if (file_pages) *file_pages = 0; // could we use sc->filesize?
|
58
|
+
+ if (anon_mapping) *anon_mapping = 0;
|
59
|
+
+ if (anon_pages) *anon_pages = 0;
|
60
|
+
+ if (dev) *dev = 0;
|
61
|
+
+ return true;
|
62
|
+
+ } else {
|
63
|
+
+ #endif
|
64
|
+
+ const segment_command* sc = (const segment_command *)lc;
|
65
|
+
+ if (start) *start = sc->vmaddr + dlloff;
|
66
|
+
+ if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
|
67
|
+
+ if (flags) *flags = kDefaultPerms; // can we do better?
|
68
|
+
+ if (offset) *offset = sc->fileoff;
|
69
|
+
+ if (inode) *inode = 0;
|
70
|
+
+ if (filename)
|
71
|
+
+ *filename = const_cast<char*>(_dyld_get_image_name(current_image_));
|
72
|
+
+ if (file_mapping) *file_mapping = 0;
|
73
|
+
+ if (file_pages) *file_pages = 0; // could we use sc->filesize?
|
74
|
+
+ if (anon_mapping) *anon_mapping = 0;
|
75
|
+
+ if (anon_pages) *anon_pages = 0;
|
76
|
+
+ if (dev) *dev = 0;
|
77
|
+
+ return true;
|
78
|
+
+ #if defined(MH_MAGIC_64)
|
79
|
+
+ }
|
80
|
+
+ #endif
|
81
|
+
}
|
82
|
+
}
|
83
|
+
// If we get here, no more load_cmd's in this image talk about
|
84
|
+
diff --git a/src/pprof b/src/pprof
|
85
|
+
index 3531300..b256ed2 100755
|
86
|
+
--- a/src/pprof
|
87
|
+
+++ b/src/pprof
|
88
|
+
@@ -3193,7 +3193,7 @@ sub ParseTextSectionHeaderFromOtool {
|
89
|
+
$sectname = $1;
|
90
|
+
} elsif ($line =~ /segname (\w+)/) {
|
91
|
+
$segname = $1;
|
92
|
+
- } elsif (!($cmd eq "LC_SEGMENT" &&
|
93
|
+
+ } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") &&
|
94
|
+
$sectname eq "__text" &&
|
95
|
+
$segname eq "__TEXT")) {
|
96
|
+
next;
|
data/patches/perftools-osx.patch
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
diff --git a/Makefile.in b/Makefile.in
|
2
|
-
index
|
2
|
+
index 566d77c..c3bf409 100644
|
3
3
|
--- a/Makefile.in
|
4
4
|
+++ b/Makefile.in
|
5
|
-
@@ -
|
5
|
+
@@ -1397,7 +1397,7 @@ INSTALL_DATA = @INSTALL_DATA@
|
6
6
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
7
7
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
8
8
|
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
@@ -0,0 +1,56 @@
|
|
1
|
+
diff --git a/src/pprof b/src/pprof
|
2
|
+
index b5ef29a..25b956d 100755
|
3
|
+
--- a/src/pprof
|
4
|
+
+++ b/src/pprof
|
5
|
+
@@ -530,7 +530,8 @@ sub Main() {
|
6
|
+
my $symbol_map = {};
|
7
|
+
|
8
|
+
# Read one profile, pick the last item on the list
|
9
|
+
- my $data = ReadProfile($main::prog, pop(@main::profile_files));
|
10
|
+
+ my $fname = pop(@main::profile_files);
|
11
|
+
+ my $data = ReadProfile($main::prog, $fname);
|
12
|
+
my $profile = $data->{profile};
|
13
|
+
my $pcs = $data->{pcs};
|
14
|
+
my $libs = $data->{libs}; # Info about main program and shared libraries
|
15
|
+
@@ -567,6 +568,17 @@ sub Main() {
|
16
|
+
$symbols = ExtractSymbols($libs, $pcs);
|
17
|
+
}
|
18
|
+
|
19
|
+
+ if (-e "$fname.symbols") {
|
20
|
+
+ open(SYMBOLS, "<$fname.symbols");
|
21
|
+
+ while(<SYMBOLS>){
|
22
|
+
+ chop;
|
23
|
+
+ if (m/(.+?)\s*:\s*(.*)/){
|
24
|
+
+ $symbols->{$1}[0] = $2;
|
25
|
+
+ }
|
26
|
+
+ }
|
27
|
+
+ close(SYMBOLS);
|
28
|
+
+ }
|
29
|
+
+
|
30
|
+
# Remove uniniteresting stack items
|
31
|
+
$profile = RemoveUninterestingFrames($symbols, $profile);
|
32
|
+
|
33
|
+
@@ -1927,6 +1927,7 @@ sub RemoveUninterestingFrames {
|
34
|
+
'ProfileData::prof_handler', # historical
|
35
|
+
'CpuProfiler::prof_handler',
|
36
|
+
'__FRAME_END__',
|
37
|
+
+ 'PerfTools::CpuProfiler.start',
|
38
|
+
'__pthread_sighandler',
|
39
|
+
'__restore') {
|
40
|
+
$skip{$name} = 1;
|
41
|
+
@@ -1935,6 +1936,7 @@ sub RemoveUninterestingFrames {
|
42
|
+
# Nothing skipped for unknown types
|
43
|
+
}
|
44
|
+
|
45
|
+
+=pod
|
46
|
+
if ($main::profile_type eq 'cpu') {
|
47
|
+
# If all the second-youngest program counters are the same,
|
48
|
+
# this STRONGLY suggests that it is an artifact of measurement,
|
49
|
+
@@ -1959,6 +1961,7 @@ sub RemoveUninterestingFrames {
|
50
|
+
$profile = $result;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
+=cut
|
54
|
+
|
55
|
+
my $result = {};
|
56
|
+
foreach my $k (keys(%{$profile})) {
|
data/patches/perftools.patch
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
diff --git a/Makefile.in b/Makefile.in
|
2
|
-
index
|
2
|
+
index 232d2ec..566d77c 100644
|
3
3
|
--- a/Makefile.in
|
4
4
|
+++ b/Makefile.in
|
5
|
-
@@ -
|
5
|
+
@@ -1367,13 +1367,13 @@ AUTOMAKE = @AUTOMAKE@
|
6
6
|
AWK = @AWK@
|
7
7
|
CC = @CC@
|
8
8
|
CCDEPMODE = @CCDEPMODE@
|
@@ -18,38 +18,6 @@ index 8ba85fb..e3690b2 100644
|
|
18
18
|
CYGPATH_W = @CYGPATH_W@
|
19
19
|
DEFS = @DEFS@
|
20
20
|
DEPDIR = @DEPDIR@
|
21
|
-
diff --git a/src/pprof b/src/pprof
|
22
|
-
index 9d4d0e8..a41fcb1 100755
|
23
|
-
--- a/src/pprof
|
24
|
-
+++ b/src/pprof
|
25
|
-
@@ -504,7 +504,8 @@ sub Main() {
|
26
|
-
FetchDynamicProfiles();
|
27
|
-
|
28
|
-
# Read one profile, pick the last item on the list
|
29
|
-
- my $data = ReadProfile($main::prog, pop(@main::profile_files));
|
30
|
-
+ my $fname = pop(@main::profile_files);
|
31
|
-
+ my $data = ReadProfile($main::prog, $fname);
|
32
|
-
my $profile = $data->{profile};
|
33
|
-
my $pcs = $data->{pcs};
|
34
|
-
my $libs = $data->{libs}; # Info about main program and shared libraries
|
35
|
-
@@ -549,6 +550,17 @@ sub Main() {
|
36
|
-
$profile = IgnoreProfile($symbols, $profile, $main::opt_ignore);
|
37
|
-
}
|
38
|
-
|
39
|
-
+ if (-e "$fname.symbols") {
|
40
|
-
+ open(SYMBOLS, "<$fname.symbols");
|
41
|
-
+ while(<SYMBOLS>){
|
42
|
-
+ chop;
|
43
|
-
+ if (m/(.+?)\s*:\s*(.*)/){
|
44
|
-
+ $symbols->{$1}[0] = $2;
|
45
|
-
+ }
|
46
|
-
+ }
|
47
|
-
+ close(SYMBOLS);
|
48
|
-
+ }
|
49
|
-
+
|
50
|
-
my $calls = ExtractCalls($symbols, $profile);
|
51
|
-
|
52
|
-
# Reduce profiles to required output granularity, and also clean
|
53
21
|
diff --git a/src/profile-handler.cc b/src/profile-handler.cc
|
54
22
|
index e658d30..370d012 100644
|
55
23
|
--- a/src/profile-handler.cc
|
@@ -227,7 +195,7 @@ index da7ea9e..67c463d 100644
|
|
227
195
|
|
228
196
|
// Move 'entry' to the eviction buffer.
|
229
197
|
diff --git a/src/profiler.cc b/src/profiler.cc
|
230
|
-
index
|
198
|
+
index 183a7c7..d89a53a 100644
|
231
199
|
--- a/src/profiler.cc
|
232
200
|
+++ b/src/profiler.cc
|
233
201
|
@@ -63,6 +63,12 @@ typedef int ucontext_t; // just to quiet the compiler, mostly
|
@@ -283,7 +251,7 @@ index d158eea..e8509fe 100644
|
|
283
251
|
#endif
|
284
252
|
+#endif
|
285
253
|
diff --git a/src/stacktrace_with_context.cc b/src/stacktrace_with_context.cc
|
286
|
-
index
|
254
|
+
index ed7bfe3..a90c070 100644
|
287
255
|
--- a/src/stacktrace_with_context.cc
|
288
256
|
+++ b/src/stacktrace_with_context.cc
|
289
257
|
@@ -41,6 +41,7 @@
|
data/perftools.rb.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
spec = Gem::Specification.new do |s|
|
2
2
|
s.name = 'perftools.rb'
|
3
|
-
s.version = '0.
|
4
|
-
s.date = '2009-
|
3
|
+
s.version = '0.3.1'
|
4
|
+
s.date = '2009-10-10'
|
5
5
|
s.rubyforge_project = 'perftools-rb'
|
6
6
|
s.summary = 'google-perftools for ruby code'
|
7
7
|
s.description = 'A sampling profiler for ruby code based on patches to google-perftools'
|
@@ -9,22 +9,25 @@ spec = Gem::Specification.new do |s|
|
|
9
9
|
s.homepage = "http://github.com/tmm1/perftools.rb"
|
10
10
|
|
11
11
|
s.authors = ["Aman Gupta"]
|
12
|
-
s.email = "
|
12
|
+
s.email = "perftools@tmm1.net"
|
13
13
|
|
14
14
|
s.has_rdoc = false
|
15
15
|
s.extensions = 'ext/extconf.rb'
|
16
16
|
s.bindir = 'bin'
|
17
17
|
s.executables << 'pprof.rb'
|
18
18
|
|
19
|
-
# ruby -rpp -e' pp `git ls-files | grep -v examples`.split("\n") '
|
19
|
+
# ruby -rpp -e' pp `git ls-files | grep -v examples`.split("\n").sort '
|
20
20
|
s.files = [
|
21
21
|
"README",
|
22
22
|
"bin/pprof.rb",
|
23
23
|
"ext/extconf.rb",
|
24
24
|
"ext/perftools.c",
|
25
|
+
"ext/src/google-perftools-1.4.tar.gz",
|
25
26
|
"patches/perftools-debug.patch",
|
26
27
|
"patches/perftools-gc.patch",
|
28
|
+
"patches/perftools-osx-106.patch",
|
27
29
|
"patches/perftools-osx.patch",
|
30
|
+
"patches/perftools-pprof.patch",
|
28
31
|
"patches/perftools.patch",
|
29
32
|
"perftools.rb.gemspec"
|
30
33
|
]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perftools.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
@@ -9,12 +9,12 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-10-10 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
16
|
description: A sampling profiler for ruby code based on patches to google-perftools
|
17
|
-
email:
|
17
|
+
email: perftools@tmm1.net
|
18
18
|
executables:
|
19
19
|
- pprof.rb
|
20
20
|
extensions:
|
@@ -26,9 +26,12 @@ files:
|
|
26
26
|
- bin/pprof.rb
|
27
27
|
- ext/extconf.rb
|
28
28
|
- ext/perftools.c
|
29
|
+
- ext/src/google-perftools-1.4.tar.gz
|
29
30
|
- patches/perftools-debug.patch
|
30
31
|
- patches/perftools-gc.patch
|
32
|
+
- patches/perftools-osx-106.patch
|
31
33
|
- patches/perftools-osx.patch
|
34
|
+
- patches/perftools-pprof.patch
|
32
35
|
- patches/perftools.patch
|
33
36
|
- perftools.rb.gemspec
|
34
37
|
has_rdoc: true
|