perftools.rb 0.2.5 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|