rack-mini-profiler 0.1.31 → 0.9.0.pre
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack-mini-profiler might be problematic. Click here for more details.
- 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
|
+
[![Code Climate](https://codeclimate.com/github/MiniProfiler/rack-mini-profiler.png)](https://codeclimate.com/github/MiniProfiler/rack-mini-profiler) [![Build Status](https://travis-ci.org/MiniProfiler/rack-mini-profiler.png)](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
|