request_profiler 0.0.1 → 0.0.2

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.
@@ -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