request_profiler 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,8 +5,7 @@ module Rack
5
5
  def initialize(app, options = {})
6
6
  @app = app
7
7
  @printer = options[:printer] || ::RubyProf::GraphHtmlPrinter
8
- @mode = options[:mode] || ::RubyProf::PROCESS_TIME
9
- @eliminations = options[:eliminations]
8
+ @exclusions = options[:exclude]
10
9
 
11
10
  @path = options[:path]
12
11
  @path ||= Rails.root + 'tmp/performance' if defined?(Rails)
@@ -16,15 +15,15 @@ module Rack
16
15
 
17
16
  def call(env)
18
17
  request = Rack::Request.new(env)
19
- profile_request = request.params.delete("profile_request") == "true"
20
-
21
- if profile_request
22
- ::RubyProf.measure_mode = @mode
18
+ mode = profile_mode(request)
19
+
20
+ if mode
21
+ ::RubyProf.measure_mode = mode
23
22
  ::RubyProf.start
24
23
  end
25
24
  status, headers, body = @app.call(env)
26
25
 
27
- if profile_request
26
+ if mode
28
27
  result = ::RubyProf.stop
29
28
  write_result(result, request)
30
29
  end
@@ -32,6 +31,17 @@ module Rack
32
31
  [status, headers, body]
33
32
  end
34
33
 
34
+ def profile_mode(request)
35
+ mode_string = request.params["profile_request"]
36
+ if mode_string
37
+ if mode_string.downcase == "true"
38
+ ::RubyProf::PROCESS_TIME
39
+ else
40
+ ::RubyProf.const_get(mode_string.upcase)
41
+ end
42
+ end
43
+ end
44
+
35
45
  def format(printer)
36
46
  case printer
37
47
  when ::RubyProf::FlatPrinter
@@ -54,15 +64,13 @@ module Rack
54
64
  end
55
65
 
56
66
  def write_result(result, request)
67
+ result.eliminate_methods!(@exclusions) if @exclusions
57
68
  printer = @printer.new(result)
58
69
  Dir.mkdir(@path) unless ::File.exists?(@path)
59
70
  url = request.fullpath.gsub(/[?\/]/, '-')
60
71
  filename = "#{Time.now.strftime('%Y-%m-%d-%H-%M-%S')}-#{url}.#{format(printer)}"
61
72
  ::File.open(@path + filename, 'w+') do |f|
62
- # HACK to keep this from crashing under patched 1.9.2
63
- GC.disable
64
73
  printer.print(f)
65
- GC.enable
66
74
  end
67
75
  end
68
76
  end
@@ -1,3 +1,3 @@
1
1
  module RequestProfiler
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,389 @@
1
+ diff --git a/ChangeLog b/ChangeLog
2
+ index fb1dc55..63cde44 100644
3
+ --- a/ChangeLog
4
+ +++ b/ChangeLog
5
+ @@ -1,3 +1,21 @@
6
+ +Sat Oct 9 11:00:06 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
7
+ +
8
+ + * thread.c (thread_reset_event_flags, exec_event_hooks): ignore
9
+ + hooks marked as removed.
10
+ +
11
+ + * thread.c (thread_exec_event_hooks): remove hooks to be removed.
12
+ +
13
+ + * thread.c (rb_threadptr_remove_event_hook, rb_remove_event_hook):
14
+ + defer removing hooks if running the hooks. [ruby-dev:42350]
15
+ +
16
+ +Sat Oct 9 10:51:00 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
17
+ +
18
+ + * thread.c (rb_threadptr_exec_event_hooks): suppress each event
19
+ + hooks separately.
20
+ +
21
+ + * thread.c (thread_suppress_tracing): split from
22
+ + ruby_suppress_tracing, accepting thread pointer and event mask.
23
+ +
24
+ Wed Aug 18 01:37:49 2010 NARUSE, Yui <naruse@ruby-lang.org>
25
+
26
+ * regcomp.c: revert r26701; it introduces Bug #3681.
27
+ diff --git a/gc.c b/gc.c
28
+ index 25fcc3d..f6d74c3 100644
29
+ --- a/gc.c
30
+ +++ b/gc.c
31
+ @@ -1195,7 +1195,7 @@ ruby_get_stack_grow_direction(volatile VALUE *addr)
32
+ }
33
+ #endif
34
+
35
+ -#define GC_WATER_MARK 512
36
+ +#define GC_WATER_MARK 1024
37
+
38
+ size_t
39
+ ruby_stack_length(VALUE **p)
40
+ diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
41
+ index f885cb0..576b4da 100644
42
+ --- a/test/ruby/test_settracefunc.rb
43
+ +++ b/test/ruby/test_settracefunc.rb
44
+ @@ -354,4 +354,16 @@ class TestSetTraceFunc < Test::Unit::TestCase
45
+ assert_equal([], events[:set])
46
+ assert_equal([], events[:add])
47
+ end
48
+ +
49
+ + def test_remove_in_trace
50
+ + bug3921 = '[ruby-dev:42350]'
51
+ + ok = false
52
+ + func = lambda{|e, f, l, i, b, k|
53
+ + set_trace_func(nil)
54
+ + ok = eval("self", b)
55
+ + }
56
+ +
57
+ + set_trace_func(func)
58
+ + assert_equal(self, ok, bug3921)
59
+ + end
60
+ end
61
+ diff --git a/thread.c b/thread.c
62
+ index aa6eced..a550a9a 100644
63
+ --- a/thread.c
64
+ +++ b/thread.c
65
+ @@ -3700,6 +3700,27 @@ rb_exec_recursive_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
66
+ }
67
+
68
+ /* tracer */
69
+ +#define RUBY_EVENT_REMOVED 0x1000000
70
+ +
71
+ +enum {
72
+ + EVENT_RUNNING_NOTHING,
73
+ + EVENT_RUNNING_TRACE = 1,
74
+ + EVENT_RUNNING_THREAD = 2,
75
+ + EVENT_RUNNING_VM = 4,
76
+ + EVENT_RUNNING_EVENT_MASK = EVENT_RUNNING_VM|EVENT_RUNNING_THREAD
77
+ +};
78
+ +
79
+ +static VALUE thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always);
80
+ +VALUE ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always);
81
+ +
82
+ +struct event_call_args {
83
+ + rb_thread_t *th;
84
+ + VALUE klass;
85
+ + VALUE self;
86
+ + VALUE proc;
87
+ + ID id;
88
+ + rb_event_flag_t event;
89
+ +};
90
+
91
+ static rb_event_hook_t *
92
+ alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
93
+ @@ -3718,7 +3739,8 @@ thread_reset_event_flags(rb_thread_t *th)
94
+ rb_event_flag_t flag = th->event_flags & RUBY_EVENT_VM;
95
+
96
+ while (hook) {
97
+ - flag |= hook->flag;
98
+ + if (!(flag & RUBY_EVENT_REMOVED))
99
+ + flag |= hook->flag;
100
+ hook = hook->next;
101
+ }
102
+ th->event_flags = flag;
103
+ @@ -3771,34 +3793,74 @@ set_threads_event_flags(int flag)
104
+ st_foreach(GET_VM()->living_threads, set_threads_event_flags_i, (st_data_t) flag);
105
+ }
106
+
107
+ -static inline void
108
+ +static inline int
109
+ exec_event_hooks(const rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
110
+ {
111
+ + int removed = 0;
112
+ for (; hook; hook = hook->next) {
113
+ + if (hook->flag & RUBY_EVENT_REMOVED) {
114
+ + removed++;
115
+ + continue;
116
+ + }
117
+ if (flag & hook->flag) {
118
+ (*hook->func)(flag, hook->data, self, id, klass);
119
+ }
120
+ }
121
+ + return removed;
122
+ }
123
+
124
+ -void
125
+ -rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
126
+ -{
127
+ - const VALUE errinfo = th->errinfo;
128
+ +static int remove_defered_event_hook(rb_event_hook_t **root);
129
+ +
130
+ +static VALUE
131
+ +thread_exec_event_hooks(VALUE args, int running)
132
+ +{
133
+ + struct event_call_args *argp = (struct event_call_args *)args;
134
+ + rb_thread_t *th = argp->th;
135
+ + rb_event_flag_t flag = argp->event;
136
+ + VALUE self = argp->self;
137
+ + ID id = argp->id;
138
+ + VALUE klass = argp->klass;
139
+ const rb_event_flag_t wait_event = th->event_flags;
140
+ + int removed;
141
+ +
142
+ + if (self == rb_mRubyVMFrozenCore) return 0;
143
+
144
+ - if (self == rb_mRubyVMFrozenCore) return;
145
+ - if (wait_event & flag) {
146
+ - exec_event_hooks(th->event_hooks, flag, self, id, klass);
147
+ + if ((wait_event & flag) && !(running & EVENT_RUNNING_THREAD)) {
148
+ + th->tracing |= EVENT_RUNNING_THREAD;
149
+ + removed = exec_event_hooks(th->event_hooks, flag, self, id, klass);
150
+ + th->tracing &= ~EVENT_RUNNING_THREAD;
151
+ + if (removed) {
152
+ + remove_defered_event_hook(&th->event_hooks);
153
+ + }
154
+ }
155
+ if (wait_event & RUBY_EVENT_VM) {
156
+ if (th->vm->event_hooks == NULL) {
157
+ th->event_flags &= (~RUBY_EVENT_VM);
158
+ }
159
+ - else {
160
+ - exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
161
+ + else if (!(running & EVENT_RUNNING_VM)) {
162
+ + th->tracing |= EVENT_RUNNING_VM;
163
+ + removed = exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
164
+ + th->tracing &= ~EVENT_RUNNING_VM;
165
+ + if (removed) {
166
+ + remove_defered_event_hook(&th->vm->event_hooks);
167
+ + }
168
+ }
169
+ }
170
+ + return 0;
171
+ +}
172
+ +
173
+ +void
174
+ +rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
175
+ +{
176
+ + const VALUE errinfo = th->errinfo;
177
+ + struct event_call_args args;
178
+ + args.th = th;
179
+ + args.event = flag;
180
+ + args.self = self;
181
+ + args.id = id;
182
+ + args.klass = klass;
183
+ + args.proc = 0;
184
+ + thread_suppress_tracing(th, EVENT_RUNNING_EVENT_MASK, thread_exec_event_hooks, (VALUE)&args, FALSE);
185
+ th->errinfo = errinfo;
186
+ }
187
+
188
+ @@ -3815,23 +3877,49 @@ rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
189
+ }
190
+
191
+ static int
192
+ +defer_remove_event_hook(rb_event_hook_t *hook, rb_event_hook_func_t func)
193
+ +{
194
+ + while (hook) {
195
+ + if (func == 0 || hook->func == func) {
196
+ + hook->flag |= RUBY_EVENT_REMOVED;
197
+ + }
198
+ + hook = hook->next;
199
+ + }
200
+ + return -1;
201
+ +}
202
+ +
203
+ +static int
204
+ remove_event_hook(rb_event_hook_t **root, rb_event_hook_func_t func)
205
+ {
206
+ - rb_event_hook_t *prev = NULL, *hook = *root, *next;
207
+ + rb_event_hook_t *hook = *root, *next;
208
+
209
+ while (hook) {
210
+ next = hook->next;
211
+ - if (func == 0 || hook->func == func) {
212
+ - if (prev) {
213
+ - prev->next = hook->next;
214
+ - }
215
+ - else {
216
+ - *root = hook->next;
217
+ - }
218
+ + if (func == 0 || hook->func == func || (hook->flag & RUBY_EVENT_REMOVED)) {
219
+ + *root = next;
220
+ + xfree(hook);
221
+ + }
222
+ + else {
223
+ + root = &hook->next;
224
+ + }
225
+ + hook = next;
226
+ + }
227
+ + return -1;
228
+ +}
229
+ +
230
+ +static int
231
+ +remove_defered_event_hook(rb_event_hook_t **root)
232
+ +{
233
+ + rb_event_hook_t *hook = *root, *next;
234
+ +
235
+ + while (hook) {
236
+ + next = hook->next;
237
+ + if (hook->flag & RUBY_EVENT_REMOVED) {
238
+ + *root = next;
239
+ xfree(hook);
240
+ }
241
+ else {
242
+ - prev = hook;
243
+ + root = &hook->next;
244
+ }
245
+ hook = next;
246
+ }
247
+ @@ -3841,7 +3929,13 @@ remove_event_hook(rb_event_hook_t **root, rb_event_hook_func_t func)
248
+ static int
249
+ rb_threadptr_revmove_event_hook(rb_thread_t *th, rb_event_hook_func_t func)
250
+ {
251
+ - int ret = remove_event_hook(&th->event_hooks, func);
252
+ + int ret;
253
+ + if (th->tracing & EVENT_RUNNING_THREAD) {
254
+ + ret = defer_remove_event_hook(th->event_hooks, func);
255
+ + }
256
+ + else {
257
+ + ret = remove_event_hook(&th->event_hooks, func);
258
+ + }
259
+ thread_reset_event_flags(th);
260
+ return ret;
261
+ }
262
+ @@ -3852,14 +3946,49 @@ rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func)
263
+ return rb_threadptr_revmove_event_hook(thval2thread_t(thval), func);
264
+ }
265
+
266
+ +static rb_event_hook_t *
267
+ +search_live_hook(rb_event_hook_t *hook)
268
+ +{
269
+ + while (hook) {
270
+ + if (!(hook->flag & RUBY_EVENT_REMOVED))
271
+ + return hook;
272
+ + hook = hook->next;
273
+ + }
274
+ + return NULL;
275
+ +}
276
+ +
277
+ +static int
278
+ +running_vm_event_hooks(st_data_t key, st_data_t val, st_data_t data)
279
+ +{
280
+ + rb_thread_t *th = thval2thread_t((VALUE)key);
281
+ + if (!(th->tracing & EVENT_RUNNING_VM)) return ST_CONTINUE;
282
+ + *(rb_thread_t **)data = th;
283
+ + return ST_STOP;
284
+ +}
285
+ +
286
+ +static rb_thread_t *
287
+ +vm_event_hooks_running_thread(rb_vm_t *vm)
288
+ +{
289
+ + rb_thread_t *found = NULL;
290
+ + st_foreach(vm->living_threads, running_vm_event_hooks, (st_data_t)&found);
291
+ + return found;
292
+ +}
293
+ +
294
+ int
295
+ rb_remove_event_hook(rb_event_hook_func_t func)
296
+ {
297
+ rb_vm_t *vm = GET_VM();
298
+ - rb_event_hook_t *hook = vm->event_hooks;
299
+ - int ret = remove_event_hook(&vm->event_hooks, func);
300
+ + rb_event_hook_t *hook = search_live_hook(vm->event_hooks);
301
+ + int ret;
302
+ +
303
+ + if (vm_event_hooks_running_thread(vm)) {
304
+ + ret = defer_remove_event_hook(vm->event_hooks, func);
305
+ + }
306
+ + else {
307
+ + ret = remove_event_hook(&vm->event_hooks, func);
308
+ + }
309
+
310
+ - if (hook != NULL && vm->event_hooks == NULL) {
311
+ + if (hook && !search_live_hook(vm->event_hooks)) {
312
+ set_threads_event_flags(0);
313
+ }
314
+
315
+ @@ -4020,20 +4149,10 @@ get_event_name(rb_event_flag_t event)
316
+ }
317
+ }
318
+
319
+ -VALUE ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always);
320
+ -
321
+ -struct call_trace_func_args {
322
+ - rb_event_flag_t event;
323
+ - VALUE proc;
324
+ - VALUE self;
325
+ - ID id;
326
+ - VALUE klass;
327
+ -};
328
+ -
329
+ static VALUE
330
+ call_trace_proc(VALUE args, int tracing)
331
+ {
332
+ - struct call_trace_func_args *p = (struct call_trace_func_args *)args;
333
+ + struct event_call_args *p = (struct event_call_args *)args;
334
+ const char *srcfile = rb_sourcefile();
335
+ VALUE eventname = rb_str_new2(get_event_name(p->event));
336
+ VALUE filename = srcfile ? rb_str_new2(srcfile) : Qnil;
337
+ @@ -4048,7 +4167,7 @@ call_trace_proc(VALUE args, int tracing)
338
+ klass = p->klass;
339
+ }
340
+ else {
341
+ - rb_thread_method_id_and_class(GET_THREAD(), &id, &klass);
342
+ + rb_thread_method_id_and_class(p->th, &id, &klass);
343
+ }
344
+ if (id == ID_ALLOCATOR)
345
+ return Qnil;
346
+ @@ -4074,8 +4193,9 @@ call_trace_proc(VALUE args, int tracing)
347
+ static void
348
+ call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
349
+ {
350
+ - struct call_trace_func_args args;
351
+ + struct event_call_args args;
352
+
353
+ + args.th = GET_THREAD();
354
+ args.event = event;
355
+ args.proc = proc;
356
+ args.self = self;
357
+ @@ -4088,22 +4208,28 @@ VALUE
358
+ ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always)
359
+ {
360
+ rb_thread_t *th = GET_THREAD();
361
+ - int state, tracing;
362
+ + return thread_suppress_tracing(th, EVENT_RUNNING_TRACE, func, arg, always);
363
+ +}
364
+ +
365
+ +static VALUE
366
+ +thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always)
367
+ +{
368
+ + int state, tracing = th->tracing, running = tracing & ev;
369
+ volatile int raised;
370
+ VALUE result = Qnil;
371
+
372
+ - if ((tracing = th->tracing) != 0 && !always) {
373
+ + if (running == ev && !always) {
374
+ return Qnil;
375
+ }
376
+ else {
377
+ - th->tracing = 1;
378
+ + th->tracing |= ev;
379
+ }
380
+
381
+ raised = rb_threadptr_reset_raised(th);
382
+
383
+ PUSH_TAG();
384
+ if ((state = EXEC_TAG()) == 0) {
385
+ - result = (*func)(arg, tracing);
386
+ + result = (*func)(arg, running);
387
+ }
388
+
389
+ if (raised) {
@@ -31,6 +31,17 @@ class RequestProfilerTest < Test::Unit::TestCase
31
31
  assert last_response.ok?
32
32
  end
33
33
 
34
+ def test_mode_set_by_param
35
+ self.app = Rack::RequestProfiler.new(FakeApp.new)
36
+ RubyProf.expects(:measure_mode=).with(::RubyProf::PROCESS_TIME)
37
+ get "/?profile_request=true"
38
+ assert last_response.ok?
39
+
40
+ RubyProf.expects(:measure_mode=).with(::RubyProf::WALL_TIME)
41
+ get "/?profile_request=wall_time"
42
+ assert last_response.ok?
43
+ end
44
+
34
45
  def test_file_format
35
46
  self.app = Rack::RequestProfiler.new(FakeApp.new)
36
47
  RubyProf.start
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Justin Weiss
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-15 00:00:00 -08:00
17
+ date: 2010-12-16 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -87,6 +87,7 @@ files:
87
87
  - lib/rack/request_profiler.rb
88
88
  - lib/request_profiler.rb
89
89
  - lib/request_profiler/version.rb
90
+ - patches/set_trace_func_fix192.patch
90
91
  - request_profiler.gemspec
91
92
  - test/fake_app.rb
92
93
  - test/request_profiler_test.rb