rack-mini-profiler 0.1.15.pre → 0.1.20
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.
Potentially problematic release.
This version of rack-mini-profiler might be problematic. Click here for more details.
- data/CHANGELOG +22 -0
- data/lib/html/includes.tmpl +1 -1
- data/lib/mini_profiler/profiler.rb +89 -12
- data/lib/mini_profiler/profiling_methods.rb +32 -4
- data/lib/mini_profiler/storage/memory_store.rb +1 -1
- data/rack-mini-profiler.gemspec +1 -1
- metadata +9 -6
data/CHANGELOG
CHANGED
@@ -69,3 +69,25 @@
|
|
69
69
|
* 1.15.pre
|
70
70
|
* fixed annoying bug where client settings were not sticking
|
71
71
|
* fixed long standing issue with Rack::ConditionalGet stopping MiniProfiler from working properly
|
72
|
+
|
73
|
+
5-September-2012 - Sam
|
74
|
+
|
75
|
+
* 1.16
|
76
|
+
* fixed long standing problem specs (issue with memory store)
|
77
|
+
* fixed issue where profiler would be dumped when you got a 404 in production (and any time rails is bypassed)
|
78
|
+
* implemented stacktrace properly
|
79
|
+
|
80
|
+
9-September-2012 - Sam
|
81
|
+
|
82
|
+
* 1.17
|
83
|
+
* pp=sample was bust unless stacktrace was installed
|
84
|
+
|
85
|
+
10-September-2012 - Sam
|
86
|
+
|
87
|
+
* 1.19
|
88
|
+
* fix compat issue with 1.8.7
|
89
|
+
|
90
|
+
12-September-2012 - Sam
|
91
|
+
|
92
|
+
* 1.20
|
93
|
+
* Added pp=profile-gc , it allows you to profile the GC in Ruby 1.9.3
|
data/lib/html/includes.tmpl
CHANGED
@@ -138,7 +138,7 @@
|
|
138
138
|
</td>
|
139
139
|
|
140
140
|
{{if HasSqlTimings}}
|
141
|
-
<td class="profiler-duration {{if HasDuplicateSqlTimings}}profiler-warning{{/if}}" title="{{if HasDuplicateSqlTimings}}duplicate queries detected - {{/if}}${ExecutedReaders} reader, ${ExecutedScalars} scalar, ${ExecutedNonQueries} non-query statements executed">
|
141
|
+
<td class="profiler-duration {{if HasDuplicateSqlTimings}}profiler-warning{{/if}}" title="{{if HasDuplicateSqlTimings}}duplicate queries detected - {{/if}}{{if ExecutedReaders > 0 || ExecutedScalars > 0 || ExecutedNonQueries > 0}}${ExecutedReaders} reader, ${ExecutedScalars} scalar, ${ExecutedNonQueries} non-query statements executed{{/if}}">
|
142
142
|
<a class="profiler-queries-show">
|
143
143
|
{{if HasDuplicateSqlTimings}}<span class="profiler-nuclear">!</span>{{/if}}
|
144
144
|
${SqlTimings.length} <span class="profiler-unit">sql</span>
|
@@ -19,7 +19,7 @@ module Rack
|
|
19
19
|
|
20
20
|
class MiniProfiler
|
21
21
|
|
22
|
-
VERSION = '
|
22
|
+
VERSION = '107'.freeze
|
23
23
|
|
24
24
|
class << self
|
25
25
|
|
@@ -167,6 +167,7 @@ module Rack
|
|
167
167
|
|
168
168
|
|
169
169
|
def call(env)
|
170
|
+
|
170
171
|
client_settings = ClientSettings.new(env)
|
171
172
|
|
172
173
|
status = headers = body = nil
|
@@ -207,6 +208,10 @@ module Rack
|
|
207
208
|
return [status,headers,body]
|
208
209
|
end
|
209
210
|
|
211
|
+
if query_string =~ /pp=profile-gc/
|
212
|
+
return profile_gc(env)
|
213
|
+
end
|
214
|
+
|
210
215
|
MiniProfiler.create_current(env, @config)
|
211
216
|
MiniProfiler.deauthorize_request if @config.authorization_mode == :whitelist
|
212
217
|
if query_string =~ /pp=normal-backtrace/
|
@@ -224,17 +229,30 @@ module Rack
|
|
224
229
|
done_sampling = false
|
225
230
|
quit_sampler = false
|
226
231
|
backtraces = nil
|
227
|
-
|
232
|
+
stacktrace_installed = true
|
228
233
|
if query_string =~ /pp=sample/
|
234
|
+
skip_frames = 0
|
229
235
|
backtraces = []
|
230
236
|
t = Thread.current
|
237
|
+
|
238
|
+
begin
|
239
|
+
require 'stacktrace'
|
240
|
+
skip_frames = stacktrace.length
|
241
|
+
rescue LoadError
|
242
|
+
stacktrace_installed = false
|
243
|
+
end
|
244
|
+
|
231
245
|
Thread.new {
|
232
246
|
begin
|
233
247
|
i = 10000 # for sanity never grab more than 10k samples
|
234
248
|
while i > 0
|
235
249
|
break if done_sampling
|
236
250
|
i -= 1
|
237
|
-
|
251
|
+
if stacktrace_installed
|
252
|
+
backtraces << t.stacktrace(0,-(1+skip_frames), StackFrame::Flags::METHOD | StackFrame::Flags::KLASS)
|
253
|
+
else
|
254
|
+
backtraces << t.backtrace
|
255
|
+
end
|
238
256
|
sleep 0.001
|
239
257
|
end
|
240
258
|
ensure
|
@@ -263,10 +281,14 @@ module Rack
|
|
263
281
|
|
264
282
|
skip_it = current.discard
|
265
283
|
if (config.authorization_mode == :whitelist && !MiniProfiler.request_authorized?)
|
266
|
-
|
284
|
+
# this is non-obvious, don't kill the profiling cookie on errors or short requests
|
285
|
+
# this ensures that stuff that never reaches the rails stack does not kill profiling
|
286
|
+
if status == 200 && ((Time.now - start) > 0.1)
|
287
|
+
client_settings.discard_cookie!(headers)
|
288
|
+
end
|
267
289
|
skip_it = true
|
268
290
|
end
|
269
|
-
|
291
|
+
|
270
292
|
return [status,headers,body] if skip_it
|
271
293
|
|
272
294
|
# we must do this here, otherwise current[:discard] is not being properly treated
|
@@ -277,7 +299,7 @@ module Rack
|
|
277
299
|
|
278
300
|
if query_string =~ /pp=help/
|
279
301
|
body.close if body.respond_to? :close
|
280
|
-
return help(
|
302
|
+
return help(client_settings)
|
281
303
|
end
|
282
304
|
|
283
305
|
page_struct = current.page_struct
|
@@ -285,7 +307,6 @@ module Rack
|
|
285
307
|
|
286
308
|
if backtraces
|
287
309
|
body.close if body.respond_to? :close
|
288
|
-
return help(:stacktrace, client_settings) if missing_stacktrace
|
289
310
|
return analyze(backtraces, page_struct)
|
290
311
|
end
|
291
312
|
|
@@ -355,7 +376,7 @@ module Rack
|
|
355
376
|
[200, headers, [body]]
|
356
377
|
end
|
357
378
|
|
358
|
-
def help(
|
379
|
+
def help(client_settings)
|
359
380
|
headers = {'Content-Type' => 'text/plain'}
|
360
381
|
body = "Append the following to your query string:
|
361
382
|
|
@@ -365,18 +386,73 @@ module Rack
|
|
365
386
|
pp=no-backtrace #{"(*) " if client_settings.backtrace_none?}: don't collect stack traces from all the SQL executed (sticky, use pp=normal-backtrace to enable)
|
366
387
|
pp=normal-backtrace #{"(*) " if client_settings.backtrace_default?}: collect stack traces from all the SQL executed and filter normally
|
367
388
|
pp=full-backtrace #{"(*) " if client_settings.backtrace_full?}: enable full backtraces for SQL executed (use pp=normal-backtrace to disable)
|
368
|
-
pp=sample : sample stack traces and return a report isolating heavy usage (experimental)
|
389
|
+
pp=sample : sample stack traces and return a report isolating heavy usage (experimental works best with the stacktrace gem)
|
369
390
|
pp=disable : disable profiling for this session
|
370
391
|
pp=enable : enable profiling for this session (if previously disabled)
|
392
|
+
pp=profile-gc: perform gc profiling on this request (ruby 1.9.3 only)
|
371
393
|
"
|
372
|
-
if (category == :stacktrace)
|
373
|
-
body = "pp=stacktrace requires the stacktrace gem - add gem 'stacktrace' to your Gemfile"
|
374
|
-
end
|
375
394
|
|
376
395
|
client_settings.write!(headers)
|
377
396
|
[200, headers, [body]]
|
378
397
|
end
|
379
398
|
|
399
|
+
|
400
|
+
def object_space_stats
|
401
|
+
stats = {}
|
402
|
+
ObjectSpace.each_object { |o|
|
403
|
+
stats[o.class] ||= 1
|
404
|
+
stats[o.class] += 1
|
405
|
+
}
|
406
|
+
stats
|
407
|
+
end
|
408
|
+
|
409
|
+
def diff_object_stats(before,after)
|
410
|
+
diff = {}
|
411
|
+
after.each do |k,v|
|
412
|
+
diff[k] = v - (before[k] || 0)
|
413
|
+
end
|
414
|
+
before.each do |k,v|
|
415
|
+
diff[k] = 0 - v unless after[k]
|
416
|
+
end
|
417
|
+
|
418
|
+
diff
|
419
|
+
end
|
420
|
+
|
421
|
+
def profile_gc(env)
|
422
|
+
|
423
|
+
body = "";
|
424
|
+
|
425
|
+
stat_before = object_space_stats
|
426
|
+
begin
|
427
|
+
GC::Profiler.clear
|
428
|
+
GC::Profiler.enable
|
429
|
+
@app.call(env)
|
430
|
+
body << GC::Profiler.result
|
431
|
+
ensure
|
432
|
+
GC::Profiler.disable
|
433
|
+
end
|
434
|
+
stat_after = object_space_stats
|
435
|
+
|
436
|
+
diff = diff_object_stats(stat_before,stat_after)
|
437
|
+
|
438
|
+
body << "
|
439
|
+
ObjectSpace delta caused by request:
|
440
|
+
--------------------------------------------\n"
|
441
|
+
diff.to_a.reject{|k,v| v == 0}.sort{|x,y| y[1] <=> x[1]}.each do |k,v|
|
442
|
+
body << "#{k} : #{v}\n" if v != 0
|
443
|
+
end
|
444
|
+
|
445
|
+
body << "\n
|
446
|
+
ObjectSpace stats:
|
447
|
+
-----------------\n"
|
448
|
+
|
449
|
+
stat_after.to_a.sort{|x,y| y[1] <=> x[1]}.each do |k,v|
|
450
|
+
body << "#{k} : #{v}\n"
|
451
|
+
end
|
452
|
+
|
453
|
+
return [200, {'Content-Type' => 'text/plain'}, body]
|
454
|
+
end
|
455
|
+
|
380
456
|
def analyze(traces, page_struct)
|
381
457
|
headers = {'Content-Type' => 'text/plain'}
|
382
458
|
body = "Collected: #{traces.count} stack traces. Duration(ms): #{page_struct.duration_ms}"
|
@@ -387,6 +463,7 @@ module Rack
|
|
387
463
|
fulldump << "\n\n"
|
388
464
|
distinct = {}
|
389
465
|
trace.each do |frame|
|
466
|
+
frame = "#{frame.klass}::#{frame.method}" unless String === frame
|
390
467
|
unless distinct[frame]
|
391
468
|
distinct[frame] = true
|
392
469
|
seen[frame] ||= 0
|
@@ -8,6 +8,22 @@ module Rack
|
|
8
8
|
c.current_timer.add_sql(query, elapsed_ms, c.page_struct, c.skip_backtrace, c.full_backtrace) if (c && c.current_timer)
|
9
9
|
end
|
10
10
|
|
11
|
+
def start_step(name)
|
12
|
+
if current
|
13
|
+
parent_timer = current.current_timer
|
14
|
+
current.current_timer = current_timer = current.current_timer.add_child(name)
|
15
|
+
[current_timer,parent_timer]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def finish_step(obj)
|
20
|
+
if obj && current
|
21
|
+
current_timer, parent_timer = obj
|
22
|
+
current_timer.record_time
|
23
|
+
current.current_timer = parent_timer
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
11
27
|
# perform a profiling step on given block
|
12
28
|
def step(name, opts = nil)
|
13
29
|
if current
|
@@ -26,8 +42,11 @@ module Rack
|
|
26
42
|
end
|
27
43
|
|
28
44
|
def unprofile_method(klass, method)
|
29
|
-
|
30
|
-
|
45
|
+
|
46
|
+
clean = clean_method_name(method)
|
47
|
+
|
48
|
+
with_profiling = ("#{clean}_with_mini_profiler").intern
|
49
|
+
without_profiling = ("#{clean}_without_mini_profiler").intern
|
31
50
|
|
32
51
|
if klass.send :method_defined?, with_profiling
|
33
52
|
klass.send :alias_method, method, without_profiling
|
@@ -38,8 +57,10 @@ module Rack
|
|
38
57
|
|
39
58
|
def profile_method(klass, method, &blk)
|
40
59
|
default_name = klass.to_s + " " + method.to_s
|
41
|
-
|
42
|
-
|
60
|
+
clean = clean_method_name(method)
|
61
|
+
|
62
|
+
with_profiling = ("#{clean}_with_mini_profiler").intern
|
63
|
+
without_profiling = ("#{clean}_without_mini_profiler").intern
|
43
64
|
|
44
65
|
if klass.send :method_defined?, with_profiling
|
45
66
|
return # dont double profile
|
@@ -67,6 +88,13 @@ module Rack
|
|
67
88
|
end
|
68
89
|
klass.send :alias_method, method, with_profiling
|
69
90
|
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def clean_method_name(method)
|
95
|
+
method.to_s.gsub(/[\?\!]/, "")
|
96
|
+
end
|
97
|
+
|
70
98
|
end
|
71
99
|
end
|
72
100
|
end
|
@@ -55,7 +55,7 @@ module Rack
|
|
55
55
|
def cleanup_cache
|
56
56
|
expire_older_than = ((Time.now.to_f - MiniProfiler::MemoryStore::EXPIRE_TIMER_CACHE) * 1000).to_i
|
57
57
|
@timer_struct_lock.synchronize {
|
58
|
-
@timer_struct_cache.delete_if { |k, v| v['
|
58
|
+
@timer_struct_cache.delete_if { |k, v| v['Started'] < expire_older_than }
|
59
59
|
}
|
60
60
|
end
|
61
61
|
end
|
data/rack-mini-profiler.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "rack-mini-profiler"
|
3
|
-
s.version = "0.1.
|
3
|
+
s.version = "0.1.20"
|
4
4
|
s.summary = "Profiles loading speed for rack applications."
|
5
5
|
s.authors = ["Aleks Totic","Sam Saffron", "Robin Ward"]
|
6
6
|
s.description = "Page loading speed displayed on every page. Optimize while you develop, performance is a feature."
|
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-mini-profiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.20
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Aleks Totic
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-09-
|
14
|
+
date: 2012-09-11 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rack
|
@@ -131,13 +131,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
131
|
version: '0'
|
132
132
|
segments:
|
133
133
|
- 0
|
134
|
-
hash:
|
134
|
+
hash: -250357363
|
135
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
136
|
none: false
|
137
137
|
requirements:
|
138
|
-
- - ! '
|
138
|
+
- - ! '>='
|
139
139
|
- !ruby/object:Gem::Version
|
140
|
-
version:
|
140
|
+
version: '0'
|
141
|
+
segments:
|
142
|
+
- 0
|
143
|
+
hash: -250357363
|
141
144
|
requirements: []
|
142
145
|
rubyforge_project:
|
143
146
|
rubygems_version: 1.8.24
|