rack-mini-profiler 0.1.31 → 0.9.0.pre
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.
- checksums.yaml +4 -4
- data/{Ruby/CHANGELOG → CHANGELOG} +13 -0
- data/{Ruby/README.md → README.md} +51 -31
- data/{Ruby/lib → lib}/html/includes.css +0 -0
- data/{Ruby/lib → lib}/html/includes.js +9 -8
- data/{Ruby/lib → lib}/html/includes.less +0 -0
- data/{Ruby/lib → lib}/html/includes.tmpl +1 -1
- data/{Ruby/lib → lib}/html/jquery.1.7.1.js +0 -0
- data/{Ruby/lib → lib}/html/jquery.tmpl.js +0 -0
- data/{Ruby/lib → lib}/html/list.css +2 -2
- data/{Ruby/lib → lib}/html/list.js +1 -1
- data/{Ruby/lib → lib}/html/list.tmpl +2 -2
- data/lib/html/profile_handler.js +1 -0
- data/{Ruby/lib → lib}/html/share.html +2 -2
- data/{Ruby/lib → lib}/mini_profiler/client_settings.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/client_timer_struct.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/config.rb +11 -4
- data/{Ruby/lib → lib}/mini_profiler/context.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/custom_timer_struct.rb +0 -0
- data/lib/mini_profiler/gc_profiler.rb +181 -0
- data/{Ruby/lib → lib}/mini_profiler/page_timer_struct.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/profiler.rb +81 -39
- data/{Ruby/lib → lib}/mini_profiler/profiling_methods.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/request_timer_struct.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/sql_timer_struct.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/storage/abstract_store.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/storage/file_store.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/storage/memcache_store.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/storage/memory_store.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/storage/redis_store.rb +0 -0
- data/{Ruby/lib → lib}/mini_profiler/timer_struct.rb +0 -0
- data/lib/mini_profiler/version.rb +5 -0
- data/{Ruby/lib → lib}/mini_profiler_rails/railtie.rb +6 -2
- data/{Ruby/lib → lib}/patches/net_patches.rb +0 -0
- data/{Ruby/lib → lib}/patches/sql_patches.rb +0 -0
- data/{Ruby/lib → lib}/rack-mini-profiler.rb +0 -0
- data/rack-mini-profiler.gemspec +5 -5
- metadata +43 -44
- data/Ruby/lib/html/profile_handler.js +0 -1
- data/Ruby/lib/mini_profiler/gc_profiler.rb +0 -107
- data/Ruby/lib/mini_profiler/gc_profiler_ruby_head.rb +0 -40
- data/Ruby/lib/mini_profiler/version.rb +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5b9507bf24483a76c136680a0bbcc6e4a4363471
|
|
4
|
+
data.tar.gz: 9e99da2d17e0f35e76673adb60f3fcf72324340b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9eb3a4c161db91bff011f00bd5ed425ffe29d567dece26006ebc0aa08135b5177d495c4d222122254aa024cd66fa3b4edcb79a2383dda5eabac43b6a26a41d8f
|
|
7
|
+
data.tar.gz: 7115cedbc00272f16e3e3b2321a8c40b7c1ed4e21338d8ab0c1111470c1e87074decd7eae21aed95cde07eea2563f31241f4a8bc31e85c1bc43a925ae23d2311
|
|
@@ -159,3 +159,16 @@
|
|
|
159
159
|
* Ripped out flamegraph so it can be isolated into a gem
|
|
160
160
|
* Flamegraph now has much increased fidelity
|
|
161
161
|
* Ripped out pp=sample it just was never really used
|
|
162
|
+
|
|
163
|
+
17-September-2013 - Ross Wilson
|
|
164
|
+
* Instead of supressing all "/assets/" requests we now check the configured
|
|
165
|
+
config.assets.prefix path since developers can rename the path to serve Asset Pipeline
|
|
166
|
+
files from
|
|
167
|
+
|
|
168
|
+
12-December-2013 - Sam Saffron
|
|
169
|
+
* Version 0.9.0.pre (bumped up to reflect the stability of the project)
|
|
170
|
+
* Improved reports for pp=profile-gc
|
|
171
|
+
* pp=flamegraph&flamegraph_sample_rate=1 , allow you to specify sampling rates
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
# rack-mini-profiler
|
|
2
2
|
|
|
3
|
+
[](https://codeclimate.com/github/MiniProfiler/rack-mini-profiler) [](https://travis-ci.org/MiniProfiler/rack-mini-profiler)
|
|
4
|
+
|
|
3
5
|
Middleware that displays speed badge for every html page. Designed to work both in production and in development.
|
|
4
6
|
|
|
5
|
-
##
|
|
7
|
+
## rack-mini-profiler needs your help
|
|
8
|
+
|
|
9
|
+
We have decided to restructure our repository so there is a central UI repo and the various language implementation have their own.
|
|
10
|
+
|
|
11
|
+
The new home for rack-mini-profiler is https://github.com/MiniProfiler/rack-mini-profiler
|
|
12
|
+
|
|
13
|
+
**WE NEED HELP.**
|
|
14
|
+
|
|
15
|
+
- Setting up a build that reuses https://github.com/MiniProfiler/ui
|
|
16
|
+
- Migrating the internal data structures [per the spec](https://github.com/MiniProfiler/ui)
|
|
17
|
+
- Cleaning up the [horrendous class structure that is using strings as keys and crazy non-objects](https://github.com/MiniProfiler/rack-mini-profiler/blob/master/lib/mini_profiler/sql_timer_struct.rb#L36-L44)
|
|
18
|
+
- Add travis-ci testing at least MRI 1.9.3, JRuby and MRI 2.0
|
|
19
|
+
|
|
20
|
+
If you feel like taking on any of this start an issue and update us on your progress.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
6
23
|
|
|
7
24
|
Install/add to Gemfile
|
|
8
25
|
|
|
9
26
|
```ruby
|
|
10
27
|
gem 'rack-mini-profiler'
|
|
11
28
|
```
|
|
12
|
-
Using Rails:
|
|
13
29
|
|
|
14
|
-
|
|
30
|
+
NOTE: Be sure to require rack_mini_profiler below the `pg` and `mysql` gems in your Gemfile. rack_mini_profiler will identify these gems if they are loaded to insert instrumentation. If included too early no SQL will show up.
|
|
15
31
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Using Rails:
|
|
19
|
-
|
|
20
|
-
```ruby
|
|
21
|
-
# A hook in your ApplicationController
|
|
22
|
-
def authorize
|
|
23
|
-
if current_user.is_admin?
|
|
24
|
-
Rack::MiniProfiler.authorize_request
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
````
|
|
32
|
+
#### Rails
|
|
28
33
|
|
|
34
|
+
All you have to do is include the Gem and you're good to go in development. See notes below for use in production.
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
#### Rack Builder
|
|
31
37
|
|
|
32
38
|
```ruby
|
|
33
39
|
require 'rack-mini-profiler'
|
|
@@ -38,7 +44,7 @@ builder = Rack::Builder.new do
|
|
|
38
44
|
end
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
#### Sinatra
|
|
42
48
|
|
|
43
49
|
```ruby
|
|
44
50
|
require 'rack-mini-profiler'
|
|
@@ -47,6 +53,19 @@ class MyApp < Sinatra::Base
|
|
|
47
53
|
end
|
|
48
54
|
```
|
|
49
55
|
|
|
56
|
+
## Using rack-mini-profiler in your app
|
|
57
|
+
|
|
58
|
+
rack-mini-profiler is designed with production profiling in mind. To enable that just run `Rack::MiniProfiler.authorize_request` once you know a request is allowed to profile.
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
# A hook in your ApplicationController
|
|
62
|
+
def authorize
|
|
63
|
+
if current_user.is_admin?
|
|
64
|
+
Rack::MiniProfiler.authorize_request
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
```
|
|
68
|
+
|
|
50
69
|
## Database profiling
|
|
51
70
|
|
|
52
71
|
Currently supports Mysql2, Postgres, and Mongoid3 (with fallback support to ActiveRecord)
|
|
@@ -61,7 +80,7 @@ There are 4 storage options: `MemoryStore`, `RedisStore`, `MemcacheStore`, and `
|
|
|
61
80
|
|
|
62
81
|
To change the default you can create a file in `config/initializers/mini_profiler.rb`
|
|
63
82
|
|
|
64
|
-
```ruby
|
|
83
|
+
```ruby
|
|
65
84
|
# set MemoryStore
|
|
66
85
|
Rack::MiniProfiler.config.storage = Rack::MiniProfiler::MemoryStore
|
|
67
86
|
|
|
@@ -73,24 +92,24 @@ if Rails.env.production?
|
|
|
73
92
|
end
|
|
74
93
|
```
|
|
75
94
|
|
|
76
|
-
MemoryStore stores results in a processes heap - something that does not work well in a multi process environment.
|
|
77
|
-
FileStore stores results in the file system - something that may not work well in a multi machine environment.
|
|
95
|
+
MemoryStore stores results in a processes heap - something that does not work well in a multi process environment.
|
|
96
|
+
FileStore stores results in the file system - something that may not work well in a multi machine environment.
|
|
78
97
|
RedisStore/MemcacheStore work in multi process and multi machine environments (RedisStore only saves results for up to 24 hours so it won't continue to fill up Redis).
|
|
79
98
|
|
|
80
|
-
Additionally you may implement an AbstractStore for your own provider.
|
|
99
|
+
Additionally you may implement an AbstractStore for your own provider.
|
|
81
100
|
|
|
82
101
|
## User result segregation
|
|
83
102
|
|
|
84
|
-
MiniProfiler will attempt to keep all user results isolated, out-of-the-box the user provider uses the ip address:
|
|
103
|
+
MiniProfiler will attempt to keep all user results isolated, out-of-the-box the user provider uses the ip address:
|
|
85
104
|
|
|
86
105
|
```ruby
|
|
87
|
-
Rack::MiniProfiler.config.user_provider = Proc.new{|env| Rack::Request.new(env).ip}
|
|
106
|
+
Rack::MiniProfiler.config.user_provider = Proc.new{|env| Rack::Request.new(env).ip}
|
|
88
107
|
```
|
|
89
108
|
|
|
90
|
-
You can override (something that is very important in a multi-machine production setup):
|
|
109
|
+
You can override (something that is very important in a multi-machine production setup):
|
|
91
110
|
|
|
92
111
|
```ruby
|
|
93
|
-
Rack::MiniProfiler.config.user_provider = Proc.new{ |env| CurrentUser.get(env) }
|
|
112
|
+
Rack::MiniProfiler.config.user_provider = Proc.new{ |env| CurrentUser.get(env) }
|
|
94
113
|
```
|
|
95
114
|
|
|
96
115
|
The string this function returns should be unique for each user on the system (for anonymous you may need to fall back to ip address)
|
|
@@ -113,9 +132,13 @@ You can set configuration options using the configuration accessor on Rack::Mini
|
|
|
113
132
|
Rack::MiniProfiler.config.position = 'right'
|
|
114
133
|
# Have Mini Profiler start in hidden mode - display with short cut (defaulted to 'Alt+P')
|
|
115
134
|
Rack::MiniProfiler.config.start_hidden = true
|
|
135
|
+
# Have Rack::MiniProfiler start disabled - you can use query string option to re-enable later
|
|
136
|
+
Rack::MiniProfiler.config.enabled = false
|
|
116
137
|
# Don't collect backtraces on SQL queries that take less than 5 ms to execute
|
|
117
138
|
# (necessary on Rubies earlier than 2.0)
|
|
118
139
|
Rack::MiniProfiler.config.backtrace_threshold_ms = 5
|
|
140
|
+
# Set the sampling rate for flamegraph, in ms - defaults to 0.5ms
|
|
141
|
+
Rack::MiniProfiler.config.flamegraph_sample_rate = 1
|
|
119
142
|
```
|
|
120
143
|
|
|
121
144
|
|
|
@@ -151,10 +174,6 @@ if JSON.const_defined?(:Pure)
|
|
|
151
174
|
end
|
|
152
175
|
```
|
|
153
176
|
|
|
154
|
-
## Notes
|
|
155
|
-
|
|
156
|
-
- Be sure to require rack_mini_profiler last in your Gemfile, when it is required it will monkey patch pg and mysql gems to insert instrumentation. If included too early no SQL will show up.
|
|
157
|
-
|
|
158
177
|
## Available Options
|
|
159
178
|
|
|
160
179
|
* pre_authorize_cb - A lambda callback you can set to determine whether or not mini_profiler should be visible on a given request. Default in a Rails environment is only on in development mode. If in a Rack app, the default is always on.
|
|
@@ -165,8 +184,9 @@ end
|
|
|
165
184
|
* toggle_shortcut (default Alt+P) - a jquery.hotkeys.js-style keyboard shortcut, used to toggle the mini_profiler's visibility. See http://code.google.com/p/js-hotkeys/ for more info.
|
|
166
185
|
* start_hidden (default false) - Whether or not you want the mini_profiler to be visible when loading a page
|
|
167
186
|
* backtrace_threshold_ms (default zero) - Minimum SQL query elapsed time before a backtrace is recorded. Backtrace recording can take a couple of milliseconds on rubies earlier than 2.0, impacting performance for very small queries.
|
|
187
|
+
* flamegraph_sample_rate (default 0.5ms) - How often fast_stack should get stack trace info to generate flamegraphs
|
|
168
188
|
|
|
169
|
-
## Special query strings
|
|
189
|
+
## Special query strings
|
|
170
190
|
|
|
171
|
-
If you include the query string `pp=help` at the end of your request you will see the various options available. You can use these options to extend or contract the amount of diagnostics rack-mini-profiler gathers.
|
|
191
|
+
If you include the query string `pp=help` at the end of your request you will see the various options available. You can use these options to extend or contract the amount of diagnostics rack-mini-profiler gathers.
|
|
172
192
|
|
|
File without changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
var MiniProfiler = (function () {
|
|
3
3
|
var $;
|
|
4
4
|
|
|
@@ -659,6 +659,14 @@ var MiniProfiler = (function () {
|
|
|
659
659
|
} else {
|
|
660
660
|
doInit();
|
|
661
661
|
}
|
|
662
|
+
|
|
663
|
+
// jquery.hotkeys.js
|
|
664
|
+
// https://github.com/jeresig/jquery.hotkeys/blob/master/jquery.hotkeys.js
|
|
665
|
+
|
|
666
|
+
(function(d){function h(g){if("string"===typeof g.data){var h=g.handler,j=g.data.toLowerCase().split(" ");g.handler=function(b){if(!(this!==b.target&&(/textarea|select/i.test(b.target.nodeName)||"text"===b.target.type))){var c="keypress"!==b.type&&d.hotkeys.specialKeys[b.which],e=String.fromCharCode(b.which).toLowerCase(),a="",f={};b.altKey&&"alt"!==c&&(a+="alt+");b.ctrlKey&&"ctrl"!==c&&(a+="ctrl+");b.metaKey&&(!b.ctrlKey&&"meta"!==c)&&(a+="meta+");b.shiftKey&&"shift"!==c&&(a+="shift+");c?f[a+c]=
|
|
667
|
+
!0:(f[a+e]=!0,f[a+d.hotkeys.shiftNums[e]]=!0,"shift+"===a&&(f[d.hotkeys.shiftNums[e]]=!0));c=0;for(e=j.length;c<e;c++)if(f[j[c]])return h.apply(this,arguments)}}}}d.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",
|
|
668
|
+
109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta"},shiftNums:{"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};d.each(["keydown","keyup","keypress"],function(){d.event.special[this]={add:h}})})(MiniProfiler.jQuery);
|
|
669
|
+
|
|
662
670
|
};
|
|
663
671
|
|
|
664
672
|
var major, minor;
|
|
@@ -901,13 +909,6 @@ var MiniProfiler = (function () {
|
|
|
901
909
|
|
|
902
910
|
MiniProfiler.init();
|
|
903
911
|
|
|
904
|
-
// jquery.hotkeys.js
|
|
905
|
-
// https://github.com/jeresig/jquery.hotkeys/blob/master/jquery.hotkeys.js
|
|
906
|
-
|
|
907
|
-
(function(d){function h(g){if("string"===typeof g.data){var h=g.handler,j=g.data.toLowerCase().split(" ");g.handler=function(b){if(!(this!==b.target&&(/textarea|select/i.test(b.target.nodeName)||"text"===b.target.type))){var c="keypress"!==b.type&&d.hotkeys.specialKeys[b.which],e=String.fromCharCode(b.which).toLowerCase(),a="",f={};b.altKey&&"alt"!==c&&(a+="alt+");b.ctrlKey&&"ctrl"!==c&&(a+="ctrl+");b.metaKey&&(!b.ctrlKey&&"meta"!==c)&&(a+="meta+");b.shiftKey&&"shift"!==c&&(a+="shift+");c?f[a+c]=
|
|
908
|
-
!0:(f[a+e]=!0,f[a+d.hotkeys.shiftNums[e]]=!0,"shift+"===a&&(f[d.hotkeys.shiftNums[e]]=!0));c=0;for(e=j.length;c<e;c++)if(f[j[c]])return h.apply(this,arguments)}}}}d.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",
|
|
909
|
-
109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta"},shiftNums:{"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};d.each(["keydown","keyup","keypress"],function(){d.event.special[this]={add:h}})})(jQuery);
|
|
910
|
-
|
|
911
912
|
if (typeof prettyPrint === "undefined") {
|
|
912
913
|
|
|
913
914
|
// prettify.js
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
tbody tr:nth-child(odd) { background-color:#eee; }
|
|
2
2
|
tbody tr:nth-child(even) { background-color:#fff; }
|
|
3
3
|
table { border: 0; border-spacing:0;}
|
|
4
4
|
tr {border: 0;}
|
|
@@ -6,4 +6,4 @@ tr {border: 0;}
|
|
|
6
6
|
td {padding: 8px;}
|
|
7
7
|
.time {text-align:center;}
|
|
8
8
|
thead tr {background-color: #bbb; color: #444; font-size: 12px;}
|
|
9
|
-
thead tr th { padding: 5px 15px;}
|
|
9
|
+
thead tr th { padding: 5px 15px;}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<script async type="text/javascript" id="mini-profiler" src="{path}includes.js?v={version}" data-version="{version}" data-path="{path}" data-current-id="{currentId}" data-ids="{ids}" data-position="{position}" data-trivial="{showTrivial}" data-children="{showChildren}" data-max-traces="{maxTracesToShow}" data-controls="{showControls}" data-authorized="{authorized}" data-toggle-shortcut="{toggleShortcut}" data-start-hidden="{startHidden}"></script>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
<html>
|
|
2
2
|
<head>
|
|
3
3
|
<title>{name} ({duration} ms) - Profiling Results</title>
|
|
4
4
|
<script type='text/javascript' src='{path}jquery.1.7.1.js?v={version}'></script>
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
<body>
|
|
9
9
|
<div class='profiler-result-full'></div>
|
|
10
10
|
</body>
|
|
11
|
-
</html>
|
|
11
|
+
</html>
|
|
File without changes
|
|
File without changes
|
|
@@ -12,10 +12,10 @@ module Rack
|
|
|
12
12
|
@attributes
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
attr_accessor :auto_inject, :
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
attr_accessor :authorization_mode, :auto_inject, :backtrace_ignores, :backtrace_includes, :backtrace_remove,
|
|
16
|
+
:backtrace_threshold_ms, :base_url_path, :enabled, :flamegraph_sample_rate, :logger, :position,
|
|
17
|
+
:pre_authorize_cb, :skip_paths, :skip_schema_queries, :start_hidden, :storage, :storage_failure,
|
|
18
|
+
:storage_instance, :storage_options, :toggle_shortcut, :user_provider
|
|
19
19
|
|
|
20
20
|
# Deprecated options
|
|
21
21
|
attr_accessor :use_existing_jquery
|
|
@@ -37,6 +37,13 @@ module Rack
|
|
|
37
37
|
@toggle_shortcut = 'Alt+P'
|
|
38
38
|
@start_hidden = false
|
|
39
39
|
@backtrace_threshold_ms = 0
|
|
40
|
+
@flamegraph_sample_rate = 0.5
|
|
41
|
+
@storage_failure = Proc.new do |exception|
|
|
42
|
+
if @logger
|
|
43
|
+
@logger.warn("MiniProfiler storage failure: #{exception.message}")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
@enabled = true
|
|
40
47
|
self
|
|
41
48
|
}
|
|
42
49
|
end
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
class Rack::MiniProfiler::GCProfiler
|
|
2
|
+
|
|
3
|
+
def initialize
|
|
4
|
+
@ignore = []
|
|
5
|
+
@ignore << @ignore.__id__
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def object_space_stats
|
|
9
|
+
stats = {}
|
|
10
|
+
ids = {}
|
|
11
|
+
|
|
12
|
+
@ignore << stats.__id__
|
|
13
|
+
@ignore << ids.__id__
|
|
14
|
+
|
|
15
|
+
i=0
|
|
16
|
+
ObjectSpace.each_object { |o|
|
|
17
|
+
begin
|
|
18
|
+
i = stats[o.class] || 0
|
|
19
|
+
i += 1
|
|
20
|
+
stats[o.class] = i
|
|
21
|
+
ids[o.__id__] = o if Integer === o.__id__
|
|
22
|
+
rescue NoMethodError
|
|
23
|
+
# protect against BasicObject
|
|
24
|
+
end
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@ignore.each do |id|
|
|
28
|
+
if ids.delete(id)
|
|
29
|
+
klass = ObjectSpace._id2ref(id).class
|
|
30
|
+
stats[klass] -= 1
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
result = {:stats => stats, :ids => ids}
|
|
35
|
+
@ignore << result.__id__
|
|
36
|
+
|
|
37
|
+
result
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def diff_object_stats(before,after)
|
|
41
|
+
diff = {}
|
|
42
|
+
after.each do |k,v|
|
|
43
|
+
diff[k] = v - (before[k] || 0)
|
|
44
|
+
end
|
|
45
|
+
before.each do |k,v|
|
|
46
|
+
diff[k] = 0 - v unless after[k]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
diff
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def analyze_strings(ids_before,ids_after)
|
|
53
|
+
result = {}
|
|
54
|
+
ids_after.each do |id,_|
|
|
55
|
+
obj = ObjectSpace._id2ref(id)
|
|
56
|
+
if String === obj && !ids_before.include?(obj.object_id)
|
|
57
|
+
result[obj] ||= 0
|
|
58
|
+
result[obj] += 1
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
result
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def analyze_growth(ids_before, ids_after)
|
|
65
|
+
new_objects = 0
|
|
66
|
+
memory_allocated = 0
|
|
67
|
+
|
|
68
|
+
ids_after.each do |id,_|
|
|
69
|
+
if !ids_before.include?(id) && obj=ObjectSpace._id2ref(id)
|
|
70
|
+
# this is going to be version specific (may change in 2.1)
|
|
71
|
+
size = ObjectSpace.memsize_of(obj)
|
|
72
|
+
memory_allocated += size
|
|
73
|
+
new_objects += 1
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
[new_objects, memory_allocated]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def analyze_initial_state(ids_before)
|
|
81
|
+
memory_allocated = 0
|
|
82
|
+
objects = 0
|
|
83
|
+
|
|
84
|
+
ids_before.each do |id,_|
|
|
85
|
+
if obj=ObjectSpace._id2ref(id)
|
|
86
|
+
# this is going to be version specific (may change in 2.1)
|
|
87
|
+
memory_allocated += ObjectSpace.memsize_of(obj)
|
|
88
|
+
objects += 1
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
[objects,memory_allocated]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def profile_gc_time(app,env)
|
|
96
|
+
body = []
|
|
97
|
+
|
|
98
|
+
begin
|
|
99
|
+
GC::Profiler.clear
|
|
100
|
+
prev_profiler_state = GC::Profiler.enabled?
|
|
101
|
+
prev_gc_state = GC.enable
|
|
102
|
+
GC::Profiler.enable
|
|
103
|
+
b = app.call(env)[2]
|
|
104
|
+
b.close if b.respond_to? :close
|
|
105
|
+
body << "GC Profiler ran during this request, if it fired you will see the cost below:\n\n"
|
|
106
|
+
body << GC::Profiler.result
|
|
107
|
+
ensure
|
|
108
|
+
prev_gc_state ? GC.disable : GC.enable
|
|
109
|
+
GC::Profiler.disable unless prev_profiler_state
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
return [200, {'Content-Type' => 'text/plain'}, body]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def profile_gc(app,env)
|
|
116
|
+
|
|
117
|
+
# for memsize_of
|
|
118
|
+
require 'objspace'
|
|
119
|
+
|
|
120
|
+
body = [];
|
|
121
|
+
|
|
122
|
+
stat_before,stat_after,diff,string_analysis,
|
|
123
|
+
new_objects, memory_allocated, stat, memory_before, objects_before = nil
|
|
124
|
+
|
|
125
|
+
# clean up before
|
|
126
|
+
GC.start
|
|
127
|
+
stat = GC.stat
|
|
128
|
+
prev_gc_state = GC.disable
|
|
129
|
+
stat_before = object_space_stats
|
|
130
|
+
b = app.call(env)[2]
|
|
131
|
+
b.close if b.respond_to? :close
|
|
132
|
+
stat_after = object_space_stats
|
|
133
|
+
# so we don't blow out on memory
|
|
134
|
+
prev_gc_state ? GC.disable : GC.enable
|
|
135
|
+
|
|
136
|
+
diff = diff_object_stats(stat_before[:stats],stat_after[:stats])
|
|
137
|
+
string_analysis = analyze_strings(stat_before[:ids], stat_after[:ids])
|
|
138
|
+
new_objects, memory_allocated = analyze_growth(stat_before[:ids], stat_after[:ids])
|
|
139
|
+
objects_before, memory_before = analyze_initial_state(stat_before[:ids])
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
body << "
|
|
143
|
+
Overview
|
|
144
|
+
------------------------------------
|
|
145
|
+
Initial state: object count - #{objects_before} , memory allocated outside heap (bytes) #{memory_before}
|
|
146
|
+
|
|
147
|
+
GC Stats: #{stat.map{|k,v| "#{k} : #{v}" }.join(", ")}
|
|
148
|
+
|
|
149
|
+
New bytes allocated outside of Ruby heaps: #{memory_allocated}
|
|
150
|
+
New objects: #{new_objects}
|
|
151
|
+
"
|
|
152
|
+
|
|
153
|
+
body << "
|
|
154
|
+
ObjectSpace delta caused by request:
|
|
155
|
+
--------------------------------------------\n"
|
|
156
|
+
diff.to_a.reject{|k,v| v == 0}.sort{|x,y| y[1] <=> x[1]}.each do |k,v|
|
|
157
|
+
body << "#{k} : #{v}\n" if v != 0
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
body << "\n
|
|
161
|
+
ObjectSpace stats:
|
|
162
|
+
-----------------\n"
|
|
163
|
+
|
|
164
|
+
stat_after[:stats].to_a.sort{|x,y| y[1] <=> x[1]}.each do |k,v|
|
|
165
|
+
body << "#{k} : #{v}\n"
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
body << "\n
|
|
170
|
+
String stats:
|
|
171
|
+
------------\n"
|
|
172
|
+
|
|
173
|
+
string_analysis.to_a.sort{|x,y| y[1] <=> x[1] }.take(1000).each do |string,count|
|
|
174
|
+
body << "#{count} : #{string}\n"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
return [200, {'Content-Type' => 'text/plain'}, body]
|
|
178
|
+
ensure
|
|
179
|
+
prev_gc_state ? GC.disable : GC.enable
|
|
180
|
+
end
|
|
181
|
+
end
|
|
File without changes
|
|
@@ -138,7 +138,9 @@ module Rack
|
|
|
138
138
|
|
|
139
139
|
def serve_html(env)
|
|
140
140
|
file_name = env['PATH_INFO'][(@config.base_url_path.length)..1000]
|
|
141
|
+
|
|
141
142
|
return serve_results(env) if file_name.eql?('results')
|
|
143
|
+
|
|
142
144
|
full_path = ::File.expand_path("../html/#{file_name}", ::File.dirname(__FILE__))
|
|
143
145
|
return [404, {}, ["Not found"]] unless ::File.exists? full_path
|
|
144
146
|
f = Rack::File.new nil
|
|
@@ -204,9 +206,10 @@ module Rack
|
|
|
204
206
|
|
|
205
207
|
if query_string =~ /pp=enable/
|
|
206
208
|
skip_it = false
|
|
209
|
+
config.enabled = true
|
|
207
210
|
end
|
|
208
211
|
|
|
209
|
-
if skip_it
|
|
212
|
+
if skip_it || !config.enabled
|
|
210
213
|
status,headers,body = @app.call(env)
|
|
211
214
|
client_settings.disable_profiling = true
|
|
212
215
|
client_settings.write!(headers)
|
|
@@ -216,8 +219,18 @@ module Rack
|
|
|
216
219
|
end
|
|
217
220
|
|
|
218
221
|
if query_string =~ /pp=profile-gc/
|
|
222
|
+
current.measure = false if current
|
|
223
|
+
|
|
219
224
|
if query_string =~ /pp=profile-gc-time/
|
|
220
225
|
return Rack::MiniProfiler::GCProfiler.new.profile_gc_time(@app, env)
|
|
226
|
+
elsif query_string =~ /pp=profile-gc-ruby-head/
|
|
227
|
+
result = StringIO.new
|
|
228
|
+
report = MemoryProfiler.report do
|
|
229
|
+
_,_,body = @app.call(env)
|
|
230
|
+
body.close if body.respond_to? :close
|
|
231
|
+
end
|
|
232
|
+
report.pretty_print(result)
|
|
233
|
+
return text_result(result.string)
|
|
221
234
|
else
|
|
222
235
|
return Rack::MiniProfiler::GCProfiler.new.profile_gc(@app, env)
|
|
223
236
|
end
|
|
@@ -268,9 +281,14 @@ module Rack
|
|
|
268
281
|
else
|
|
269
282
|
# do not sully our profile with mini profiler timings
|
|
270
283
|
current.measure = false
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
284
|
+
match_data = query_string.match(/flamegraph_sample_rate=(?<rate>[\d\.]+)/)
|
|
285
|
+
|
|
286
|
+
if match_data && !match_data[:rate].to_f.zero?
|
|
287
|
+
sample_rate = match_data[:rate].to_f
|
|
288
|
+
else
|
|
289
|
+
sample_rate = config.flamegraph_sample_rate
|
|
290
|
+
end
|
|
291
|
+
flamegraph = Flamegraph.generate(nil, fidelity: sample_rate, embed_resources: query_string =~ /embed/) do
|
|
274
292
|
status,headers,body = @app.call(env)
|
|
275
293
|
end
|
|
276
294
|
end
|
|
@@ -321,16 +339,21 @@ module Rack
|
|
|
321
339
|
end
|
|
322
340
|
|
|
323
341
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
# inject headers, script
|
|
329
|
-
if headers['Content-Type'] && status == 200
|
|
330
|
-
client_settings.write!(headers)
|
|
342
|
+
begin
|
|
343
|
+
# no matter what it is, it should be unviewed, otherwise we will miss POST
|
|
344
|
+
@storage.set_unviewed(page_struct['User'], page_struct['Id'])
|
|
345
|
+
@storage.save(page_struct)
|
|
331
346
|
|
|
332
|
-
|
|
333
|
-
|
|
347
|
+
# inject headers, script
|
|
348
|
+
if headers['Content-Type'] && status == 200
|
|
349
|
+
client_settings.write!(headers)
|
|
350
|
+
result = inject_profiler(env,status,headers,body)
|
|
351
|
+
return result if result
|
|
352
|
+
end
|
|
353
|
+
rescue Exception => e
|
|
354
|
+
if @config.storage_failure != nil
|
|
355
|
+
@config.storage_failure.call(e)
|
|
356
|
+
end
|
|
334
357
|
end
|
|
335
358
|
|
|
336
359
|
client_settings.write!(headers)
|
|
@@ -338,7 +361,7 @@ module Rack
|
|
|
338
361
|
|
|
339
362
|
ensure
|
|
340
363
|
# Make sure this always happens
|
|
341
|
-
current = nil
|
|
364
|
+
self.current = nil
|
|
342
365
|
end
|
|
343
366
|
|
|
344
367
|
def inject_profiler(env,status,headers,body)
|
|
@@ -383,9 +406,9 @@ module Rack
|
|
|
383
406
|
regex = /<\/html>/i
|
|
384
407
|
close_tag = '</html>'
|
|
385
408
|
else
|
|
386
|
-
# implicit </body> and </html>.
|
|
409
|
+
# implicit </body> and </html>. Don't do anything.
|
|
387
410
|
|
|
388
|
-
return fragment
|
|
411
|
+
return fragment
|
|
389
412
|
end
|
|
390
413
|
|
|
391
414
|
matches = fragment.scan(regex).length
|
|
@@ -419,7 +442,6 @@ module Rack
|
|
|
419
442
|
end
|
|
420
443
|
|
|
421
444
|
def dump_env(env)
|
|
422
|
-
headers = {'Content-Type' => 'text/plain'}
|
|
423
445
|
body = "Rack Environment\n---------------\n"
|
|
424
446
|
env.each do |k,v|
|
|
425
447
|
body << "#{k}: #{v}\n"
|
|
@@ -438,6 +460,11 @@ module Rack
|
|
|
438
460
|
body << "User #{user(env)}\n"
|
|
439
461
|
body << config.storage_instance.diagnostics(user(env)) rescue "no diagnostics implemented for storage"
|
|
440
462
|
|
|
463
|
+
text_result(body)
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
def text_result(body)
|
|
467
|
+
headers = {'Content-Type' => 'text/plain'}
|
|
441
468
|
[200, headers, [body]]
|
|
442
469
|
end
|
|
443
470
|
|
|
@@ -455,7 +482,10 @@ module Rack
|
|
|
455
482
|
pp=enable : enable profiling for this session (if previously disabled)
|
|
456
483
|
pp=profile-gc: perform gc profiling on this request, analyzes ObjectSpace generated by request (ruby 1.9.3 only)
|
|
457
484
|
pp=profile-gc-time: perform built-in gc profiling on this request (ruby 1.9.3 only)
|
|
485
|
+
pp=profile-gc-ruby-head: requires the memory_profiler gem, new location based report
|
|
458
486
|
pp=flamegraph: works best on Ruby 2.0, a graph representing sampled activity (requires the flamegraph gem).
|
|
487
|
+
pp=flamegraph&flamegraph_sample_rate=1: creates a flamegraph with the specified sample rate (in ms). Overrides value set in config
|
|
488
|
+
pp=flamegraph_embed: works best on Ruby 2.0, a graph representing sampled activity (requires the flamegraph gem), embedded resources for use on an intranet.
|
|
459
489
|
pp=trace-exceptions: requires Ruby 2.0, will return all the spots where your application raises execptions
|
|
460
490
|
"
|
|
461
491
|
|
|
@@ -468,16 +498,17 @@ module Rack
|
|
|
468
498
|
[200, headers, [graph]]
|
|
469
499
|
end
|
|
470
500
|
|
|
471
|
-
def
|
|
501
|
+
def ids(env)
|
|
472
502
|
# cap at 10 ids, otherwise there is a chance you can blow the header
|
|
473
|
-
|
|
474
|
-
|
|
503
|
+
([current.page_struct["Id"]] + (@storage.get_unviewed_ids(user(env)) || [])[0..8]).uniq
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def ids_json(env)
|
|
507
|
+
::JSON.generate(ids(env))
|
|
475
508
|
end
|
|
476
509
|
|
|
477
510
|
def ids_comma_separated(env)
|
|
478
|
-
|
|
479
|
-
ids = [current.page_struct["Id"]] + (@storage.get_unviewed_ids(user(env)) || [])[0..8]
|
|
480
|
-
ids.join(",")
|
|
511
|
+
ids(env).join(",")
|
|
481
512
|
end
|
|
482
513
|
|
|
483
514
|
# get_profile_script returns script to be injected inside current html page
|
|
@@ -487,26 +518,37 @@ module Rack
|
|
|
487
518
|
# * you have disabled auto append behaviour throught :auto_inject => false flag
|
|
488
519
|
# * you do not want script to be automatically appended for the current page. You can also call cancel_auto_inject
|
|
489
520
|
def get_profile_script(env)
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
521
|
+
|
|
522
|
+
settings = {
|
|
523
|
+
:path => "#{env['SCRIPT_NAME']}#{@config.base_url_path}",
|
|
524
|
+
:version => MiniProfiler::VERSION,
|
|
525
|
+
:position => @config.position,
|
|
526
|
+
:showTrivial => false,
|
|
527
|
+
:showChildren => false,
|
|
528
|
+
:maxTracesToShow => 10,
|
|
529
|
+
:showControls => false,
|
|
530
|
+
:authorized => true,
|
|
531
|
+
:toggleShortcut => @config.toggle_shortcut,
|
|
532
|
+
:startHidden => @config.start_hidden
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if current && current.page_struct
|
|
536
|
+
settings[:ids] = ids_comma_separated(env)
|
|
537
|
+
settings[:currentId] = current.page_struct["Id"]
|
|
538
|
+
else
|
|
539
|
+
settings[:ids] = []
|
|
540
|
+
settings[:currentId] = ""
|
|
541
|
+
end
|
|
542
|
+
|
|
502
543
|
# TODO : cache this snippet
|
|
503
544
|
script = IO.read(::File.expand_path('../html/profile_handler.js', ::File.dirname(__FILE__)))
|
|
504
545
|
# replace the variables
|
|
505
|
-
|
|
506
|
-
regex = Regexp.new("\\{#{
|
|
507
|
-
script.gsub!(regex,
|
|
546
|
+
settings.each do |k,v|
|
|
547
|
+
regex = Regexp.new("\\{#{k.to_s}\\}")
|
|
548
|
+
script.gsub!(regex, v.to_s)
|
|
508
549
|
end
|
|
509
|
-
|
|
550
|
+
|
|
551
|
+
current.inject_js = false if current
|
|
510
552
|
script
|
|
511
553
|
end
|
|
512
554
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -7,14 +7,14 @@ module Rack::MiniProfilerRails
|
|
|
7
7
|
c = Rack::MiniProfiler.config
|
|
8
8
|
|
|
9
9
|
# By default, only show the MiniProfiler in development mode, in production allow profiling if post_authorize_cb is set
|
|
10
|
-
c.pre_authorize_cb
|
|
10
|
+
c.pre_authorize_cb ||= lambda { |env|
|
|
11
11
|
!Rails.env.test?
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
c.skip_paths ||= []
|
|
15
15
|
|
|
16
16
|
if Rails.env.development?
|
|
17
|
-
c.skip_paths <<
|
|
17
|
+
c.skip_paths << app.config.assets.prefix
|
|
18
18
|
c.skip_schema_queries = true
|
|
19
19
|
end
|
|
20
20
|
|
|
@@ -22,6 +22,10 @@ module Rack::MiniProfilerRails
|
|
|
22
22
|
c.authorization_mode = :whitelist
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
if Rails.logger
|
|
26
|
+
c.logger = Rails.logger
|
|
27
|
+
end
|
|
28
|
+
|
|
25
29
|
# The file store is just so much less flaky
|
|
26
30
|
tmp = Rails.root.to_s + "/tmp/miniprofiler"
|
|
27
31
|
FileUtils.mkdir_p(tmp) unless File.exists?(tmp)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
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.
|
|
3
|
+
s.version = "0.9.0.pre"
|
|
4
4
|
s.summary = "Profiles loading speed for rack applications."
|
|
5
5
|
s.authors = ["Sam Saffron", "Robin Ward","Aleks Totic"]
|
|
6
6
|
s.description = "Profiling toolkit for Rack applications with Rails integration. Client Side profiling, DB profiling and Server profiling."
|
|
@@ -9,10 +9,10 @@ Gem::Specification.new do |s|
|
|
|
9
9
|
s.license = "MIT"
|
|
10
10
|
s.files = [
|
|
11
11
|
'rack-mini-profiler.gemspec',
|
|
12
|
-
].concat( Dir.glob('
|
|
12
|
+
].concat( Dir.glob('lib/**/*').reject {|f| File.directory?(f) || f =~ /~$/ } )
|
|
13
13
|
s.extra_rdoc_files = [
|
|
14
|
-
"
|
|
15
|
-
"
|
|
14
|
+
"README.md",
|
|
15
|
+
"CHANGELOG"
|
|
16
16
|
]
|
|
17
17
|
s.add_runtime_dependency 'rack', '>= 1.1.3'
|
|
18
18
|
if RUBY_VERSION < "1.9"
|
|
@@ -23,5 +23,5 @@ Gem::Specification.new do |s|
|
|
|
23
23
|
s.add_development_dependency 'rack-test'
|
|
24
24
|
s.add_development_dependency 'activerecord', '~> 3.0'
|
|
25
25
|
|
|
26
|
-
s.require_paths = ["
|
|
26
|
+
s.require_paths = ["lib"]
|
|
27
27
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rack-mini-profiler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0.pre
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sam Saffron
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2013-
|
|
13
|
+
date: 2013-12-05 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: rack
|
|
@@ -74,46 +74,45 @@ email: sam.saffron@gmail.com
|
|
|
74
74
|
executables: []
|
|
75
75
|
extensions: []
|
|
76
76
|
extra_rdoc_files:
|
|
77
|
-
-
|
|
78
|
-
-
|
|
77
|
+
- README.md
|
|
78
|
+
- CHANGELOG
|
|
79
79
|
files:
|
|
80
80
|
- rack-mini-profiler.gemspec
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
- Ruby/CHANGELOG
|
|
81
|
+
- lib/mini_profiler_rails/railtie.rb
|
|
82
|
+
- lib/html/list.css
|
|
83
|
+
- lib/html/jquery.tmpl.js
|
|
84
|
+
- lib/html/list.tmpl
|
|
85
|
+
- lib/html/share.html
|
|
86
|
+
- lib/html/includes.less
|
|
87
|
+
- lib/html/profile_handler.js
|
|
88
|
+
- lib/html/includes.tmpl
|
|
89
|
+
- lib/html/includes.js
|
|
90
|
+
- lib/html/list.js
|
|
91
|
+
- lib/html/jquery.1.7.1.js
|
|
92
|
+
- lib/html/includes.css
|
|
93
|
+
- lib/mini_profiler/context.rb
|
|
94
|
+
- lib/mini_profiler/page_timer_struct.rb
|
|
95
|
+
- lib/mini_profiler/storage/file_store.rb
|
|
96
|
+
- lib/mini_profiler/storage/memcache_store.rb
|
|
97
|
+
- lib/mini_profiler/storage/memory_store.rb
|
|
98
|
+
- lib/mini_profiler/storage/abstract_store.rb
|
|
99
|
+
- lib/mini_profiler/storage/redis_store.rb
|
|
100
|
+
- lib/mini_profiler/client_settings.rb
|
|
101
|
+
- lib/mini_profiler/profiling_methods.rb
|
|
102
|
+
- lib/mini_profiler/gc_profiler.rb
|
|
103
|
+
- lib/mini_profiler/client_timer_struct.rb
|
|
104
|
+
- lib/mini_profiler/sql_timer_struct.rb
|
|
105
|
+
- lib/mini_profiler/config.rb
|
|
106
|
+
- lib/mini_profiler/custom_timer_struct.rb
|
|
107
|
+
- lib/mini_profiler/version.rb
|
|
108
|
+
- lib/mini_profiler/timer_struct.rb
|
|
109
|
+
- lib/mini_profiler/profiler.rb
|
|
110
|
+
- lib/mini_profiler/request_timer_struct.rb
|
|
111
|
+
- lib/patches/net_patches.rb
|
|
112
|
+
- lib/patches/sql_patches.rb
|
|
113
|
+
- lib/rack-mini-profiler.rb
|
|
114
|
+
- README.md
|
|
115
|
+
- CHANGELOG
|
|
117
116
|
homepage: http://miniprofiler.com
|
|
118
117
|
licenses:
|
|
119
118
|
- MIT
|
|
@@ -121,7 +120,7 @@ metadata: {}
|
|
|
121
120
|
post_install_message:
|
|
122
121
|
rdoc_options: []
|
|
123
122
|
require_paths:
|
|
124
|
-
-
|
|
123
|
+
- lib
|
|
125
124
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
125
|
requirements:
|
|
127
126
|
- - '>='
|
|
@@ -129,12 +128,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
129
128
|
version: '0'
|
|
130
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
130
|
requirements:
|
|
132
|
-
- - '
|
|
131
|
+
- - '>'
|
|
133
132
|
- !ruby/object:Gem::Version
|
|
134
|
-
version:
|
|
133
|
+
version: 1.3.1
|
|
135
134
|
requirements: []
|
|
136
135
|
rubyforge_project:
|
|
137
|
-
rubygems_version: 2.0.
|
|
136
|
+
rubygems_version: 2.0.14
|
|
138
137
|
signing_key:
|
|
139
138
|
specification_version: 4
|
|
140
139
|
summary: Profiles loading speed for rack applications.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<script async type="text/javascript" id="mini-profiler" src="{path}includes.js?v={version}" data-version="{version}" data-path="{path}" data-current-id="{currentId}" data-ids="{ids}" data-position="{position}" data-trivial="{showTrivial}" data-children="{showChildren}" data-max-traces="{maxTracesToShow}" data-controls="{showControls}" data-authorized="{authorized}" data-toggle-shortcut="{toggleShortcut}" data-start-hidden="{startHidden}"></script>
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
class Rack::MiniProfiler::GCProfiler
|
|
2
|
-
|
|
3
|
-
def object_space_stats
|
|
4
|
-
stats = {}
|
|
5
|
-
ids = Set.new
|
|
6
|
-
i=0
|
|
7
|
-
ObjectSpace.each_object { |o|
|
|
8
|
-
begin
|
|
9
|
-
i = stats[o.class] || 0
|
|
10
|
-
i += 1
|
|
11
|
-
stats[o.class] = i
|
|
12
|
-
ids << o.object_id if Integer === o.object_id
|
|
13
|
-
rescue NoMethodError
|
|
14
|
-
# Redis::Future undefines .class and .object_id super weird
|
|
15
|
-
end
|
|
16
|
-
}
|
|
17
|
-
{:stats => stats, :ids => ids}
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def diff_object_stats(before,after)
|
|
21
|
-
diff = {}
|
|
22
|
-
after.each do |k,v|
|
|
23
|
-
diff[k] = v - (before[k] || 0)
|
|
24
|
-
end
|
|
25
|
-
before.each do |k,v|
|
|
26
|
-
diff[k] = 0 - v unless after[k]
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
diff
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def analyze_strings(ids_before,ids_after)
|
|
33
|
-
result = {}
|
|
34
|
-
ids_after.each do |id|
|
|
35
|
-
obj = ObjectSpace._id2ref(id)
|
|
36
|
-
if String === obj && !ids_before.include?(obj.object_id)
|
|
37
|
-
result[obj] ||= 0
|
|
38
|
-
result[obj] += 1
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
result
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def profile_gc_time(app,env)
|
|
45
|
-
body = []
|
|
46
|
-
|
|
47
|
-
begin
|
|
48
|
-
GC::Profiler.clear
|
|
49
|
-
GC::Profiler.enable
|
|
50
|
-
b = app.call(env)[2]
|
|
51
|
-
b.close if b.respond_to? :close
|
|
52
|
-
body << "GC Profiler ran during this request, if it fired you will see the cost below:\n\n"
|
|
53
|
-
body << GC::Profiler.result
|
|
54
|
-
ensure
|
|
55
|
-
GC.enable
|
|
56
|
-
GC::Profiler.disable
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
return [200, {'Content-Type' => 'text/plain'}, body]
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def profile_gc(app,env)
|
|
63
|
-
|
|
64
|
-
body = [];
|
|
65
|
-
|
|
66
|
-
stat_before,stat_after,diff,string_analysis = nil
|
|
67
|
-
begin
|
|
68
|
-
GC.disable
|
|
69
|
-
stat_before = object_space_stats
|
|
70
|
-
b = app.call(env)[2]
|
|
71
|
-
b.close if b.respond_to? :close
|
|
72
|
-
stat_after = object_space_stats
|
|
73
|
-
|
|
74
|
-
diff = diff_object_stats(stat_before[:stats],stat_after[:stats])
|
|
75
|
-
string_analysis = analyze_strings(stat_before[:ids], stat_after[:ids])
|
|
76
|
-
ensure
|
|
77
|
-
GC.enable
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
body << "
|
|
82
|
-
ObjectSpace delta caused by request:
|
|
83
|
-
--------------------------------------------\n"
|
|
84
|
-
diff.to_a.reject{|k,v| v == 0}.sort{|x,y| y[1] <=> x[1]}.each do |k,v|
|
|
85
|
-
body << "#{k} : #{v}\n" if v != 0
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
body << "\n
|
|
89
|
-
ObjectSpace stats:
|
|
90
|
-
-----------------\n"
|
|
91
|
-
|
|
92
|
-
stat_after[:stats].to_a.sort{|x,y| y[1] <=> x[1]}.each do |k,v|
|
|
93
|
-
body << "#{k} : #{v}\n"
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
body << "\n
|
|
98
|
-
String stats:
|
|
99
|
-
------------\n"
|
|
100
|
-
|
|
101
|
-
string_analysis.to_a.sort{|x,y| y[1] <=> x[1] }.take(1000).each do |string,count|
|
|
102
|
-
body << "#{count} : #{string}\n"
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
return [200, {'Content-Type' => 'text/plain'}, body]
|
|
106
|
-
end
|
|
107
|
-
end
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
require 'objspace'
|
|
2
|
-
|
|
3
|
-
class Rack::MiniProfiler::GCProfilerRubyHead
|
|
4
|
-
def profile_rack(app,env)
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def profile(&block)
|
|
8
|
-
GC.start
|
|
9
|
-
GC.disable
|
|
10
|
-
|
|
11
|
-
items = []
|
|
12
|
-
objs = []
|
|
13
|
-
|
|
14
|
-
ObjectSpace.trace_object_allocations do
|
|
15
|
-
block.call
|
|
16
|
-
|
|
17
|
-
ObjectSpace.each_object do |o|
|
|
18
|
-
objs << o
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
objs.each do |o|
|
|
22
|
-
g = ObjectSpace.allocation_generation(o)
|
|
23
|
-
if g
|
|
24
|
-
l = ObjectSpace.allocation_sourceline(o)
|
|
25
|
-
f = ObjectSpace.allocation_sourcefile(o)
|
|
26
|
-
c = ObjectSpace.allocation_class_path(o)
|
|
27
|
-
m = ObjectSpace.allocation_method_id(o)
|
|
28
|
-
items << "Allocated #{c} in #{m} #{f}:#{l}"
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
items.group_by{|x| x}.sort{|a,b| b[1].length <=> a[1].length}.each do |row, group|
|
|
34
|
-
puts "#{row} x #{group.length}"
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
GC.enable
|
|
38
|
-
profile_allocations(name, &block)
|
|
39
|
-
end
|
|
40
|
-
end
|