perftools.rb 0.1.8 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README +4 -4
- data/ext/extconf.rb +2 -1
- data/ext/perftools.c +19 -1
- data/patches/perftools-gc.patch +107 -0
- data/perftools.rb.gemspec +3 -2
- metadata +3 -2
data/README
CHANGED
@@ -114,11 +114,11 @@ google-perftools for ruby code
|
|
114
114
|
|
115
115
|
To profile C code, download and build an unpatched perftools (libunwind or ./configure --enable-frame-pointers required on x86_64):
|
116
116
|
|
117
|
-
wget http://google-perftools.googlecode.com/files/google-perftools-1.
|
118
|
-
tar zxvf google-perftools-1.
|
119
|
-
cd google-perftools-1.
|
117
|
+
wget http://google-perftools.googlecode.com/files/google-perftools-1.3.tar.gz
|
118
|
+
tar zxvf google-perftools-1.3.tar.gz
|
119
|
+
cd google-perftools-1.3
|
120
120
|
|
121
|
-
./configure --prefix=/opt
|
121
|
+
./configure --prefix=/opt
|
122
122
|
make
|
123
123
|
sudo make install
|
124
124
|
|
data/ext/extconf.rb
CHANGED
@@ -36,6 +36,7 @@ Dir.chdir('src') do
|
|
36
36
|
xsystem("tar zxvf #{perftools}")
|
37
37
|
Dir.chdir(dir) do
|
38
38
|
xsystem("patch -p1 < ../../../patches/perftools.patch")
|
39
|
+
xsystem("patch -p1 < ../../../patches/perftools-gc.patch")
|
39
40
|
xsystem("patch -p1 < ../../../patches/perftools-osx.patch") if RUBY_PLATFORM =~ /darwin/
|
40
41
|
xsystem("patch -p1 < ../../../patches/perftools-debug.patch")# if ENV['DEBUG']
|
41
42
|
end
|
@@ -63,4 +64,4 @@ end
|
|
63
64
|
|
64
65
|
$libs = append_library($libs, 'rubyprofiler')
|
65
66
|
have_func('rb_during_gc', 'ruby.h')
|
66
|
-
create_makefile 'perftools'
|
67
|
+
create_makefile 'perftools'
|
data/ext/perftools.c
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
#include <env.h>
|
4
4
|
|
5
5
|
static VALUE Iallocate;
|
6
|
+
static VALUE I__send__;
|
6
7
|
|
7
8
|
static inline void
|
8
9
|
save_frame(struct FRAME *frame, void** result, int *depth)
|
@@ -12,6 +13,9 @@ save_frame(struct FRAME *frame, void** result, int *depth)
|
|
12
13
|
// if (BUILTIN_TYPE(klass) == T_ICLASS)
|
13
14
|
// klass = RBASIC(klass)->klass;
|
14
15
|
|
16
|
+
if (frame->last_func == I__send__)
|
17
|
+
return;
|
18
|
+
|
15
19
|
if (FL_TEST(klass, FL_SINGLETON) &&
|
16
20
|
(BUILTIN_TYPE(frame->self) == T_CLASS || BUILTIN_TYPE(frame->self) == T_MODULE))
|
17
21
|
result[(*depth)++] = (void*) frame->self;
|
@@ -42,6 +46,8 @@ rb_stack_trace(void** result, int max_depth)
|
|
42
46
|
}
|
43
47
|
#endif
|
44
48
|
|
49
|
+
// XXX SIGPROF can come in while ruby_frame is in an inconsistent state (rb_call0), so we ignore the top-most frame
|
50
|
+
/*
|
45
51
|
// XXX does it make sense to track allocations or not?
|
46
52
|
if (frame->last_func == ID_ALLOCATOR) {
|
47
53
|
frame = frame->prev;
|
@@ -50,6 +56,7 @@ rb_stack_trace(void** result, int max_depth)
|
|
50
56
|
if (frame->last_func) {
|
51
57
|
save_frame(frame, result, &depth);
|
52
58
|
}
|
59
|
+
*/
|
53
60
|
|
54
61
|
for (; frame && (n = frame->node); frame = frame->prev) {
|
55
62
|
if (frame->prev && frame->prev->last_func) {
|
@@ -70,6 +77,7 @@ rb_stack_trace(void** result, int max_depth)
|
|
70
77
|
static VALUE cPerfTools;
|
71
78
|
static VALUE cCpuProfiler;
|
72
79
|
static VALUE bProfilerRunning;
|
80
|
+
static VALUE gc_hook;
|
73
81
|
|
74
82
|
VALUE
|
75
83
|
cpuprofiler_running_p(VALUE self)
|
@@ -108,6 +116,12 @@ cpuprofiler_start(VALUE self, VALUE filename)
|
|
108
116
|
return Qtrue;
|
109
117
|
}
|
110
118
|
|
119
|
+
static void
|
120
|
+
cpuprofiler_gc_mark()
|
121
|
+
{
|
122
|
+
ProfilerGcMark(rb_gc_mark);
|
123
|
+
}
|
124
|
+
|
111
125
|
void
|
112
126
|
Init_perftools()
|
113
127
|
{
|
@@ -115,8 +129,12 @@ Init_perftools()
|
|
115
129
|
cCpuProfiler = rb_define_class_under(cPerfTools, "CpuProfiler", rb_cObject);
|
116
130
|
bProfilerRunning = Qfalse;
|
117
131
|
Iallocate = rb_intern("allocate");
|
132
|
+
I__send__ = rb_intern("__send__");
|
118
133
|
|
119
134
|
rb_define_singleton_method(cCpuProfiler, "running?", cpuprofiler_running_p, 0);
|
120
135
|
rb_define_singleton_method(cCpuProfiler, "start", cpuprofiler_start, 1);
|
121
136
|
rb_define_singleton_method(cCpuProfiler, "stop", cpuprofiler_stop, 0);
|
122
|
-
|
137
|
+
|
138
|
+
gc_hook = Data_Wrap_Struct(cCpuProfiler, cpuprofiler_gc_mark, NULL, NULL);
|
139
|
+
rb_global_variable(&gc_hook);
|
140
|
+
}
|
@@ -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..1df79c2 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 21c7669..b7277c7 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" void ProfilerFlush() {
|
96
|
+
CpuProfiler::instance_.FlushTable();
|
97
|
+
}
|
98
|
+
|
99
|
+
+#ifdef BUILD_FOR_RUBY
|
100
|
+
+extern "C" void ProfilerGcMark(void (*cb)(VALUE)) {
|
101
|
+
+ CpuProfiler::instance_.GcMark(cb);
|
102
|
+
+}
|
103
|
+
+#endif
|
104
|
+
+
|
105
|
+
extern "C" int ProfilingIsEnabledForAllThreads() {
|
106
|
+
return CpuProfiler::instance_.Enabled();
|
107
|
+
}
|
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.2.5'
|
4
|
+
s.date = '2009-09-16'
|
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'
|
@@ -23,6 +23,7 @@ spec = Gem::Specification.new do |s|
|
|
23
23
|
"ext/extconf.rb",
|
24
24
|
"ext/perftools.c",
|
25
25
|
"patches/perftools-debug.patch",
|
26
|
+
"patches/perftools-gc.patch",
|
26
27
|
"patches/perftools-osx.patch",
|
27
28
|
"patches/perftools.patch",
|
28
29
|
"perftools.rb.gemspec"
|
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.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -27,6 +27,7 @@ files:
|
|
27
27
|
- ext/extconf.rb
|
28
28
|
- ext/perftools.c
|
29
29
|
- patches/perftools-debug.patch
|
30
|
+
- patches/perftools-gc.patch
|
30
31
|
- patches/perftools-osx.patch
|
31
32
|
- patches/perftools.patch
|
32
33
|
- perftools.rb.gemspec
|