perftools.rb 0.1.8 → 0.2.5
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 +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
|