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.

Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/{Ruby/CHANGELOG → CHANGELOG} +13 -0
  3. data/{Ruby/README.md → README.md} +51 -31
  4. data/{Ruby/lib → lib}/html/includes.css +0 -0
  5. data/{Ruby/lib → lib}/html/includes.js +9 -8
  6. data/{Ruby/lib → lib}/html/includes.less +0 -0
  7. data/{Ruby/lib → lib}/html/includes.tmpl +1 -1
  8. data/{Ruby/lib → lib}/html/jquery.1.7.1.js +0 -0
  9. data/{Ruby/lib → lib}/html/jquery.tmpl.js +0 -0
  10. data/{Ruby/lib → lib}/html/list.css +2 -2
  11. data/{Ruby/lib → lib}/html/list.js +1 -1
  12. data/{Ruby/lib → lib}/html/list.tmpl +2 -2
  13. data/lib/html/profile_handler.js +1 -0
  14. data/{Ruby/lib → lib}/html/share.html +2 -2
  15. data/{Ruby/lib → lib}/mini_profiler/client_settings.rb +0 -0
  16. data/{Ruby/lib → lib}/mini_profiler/client_timer_struct.rb +0 -0
  17. data/{Ruby/lib → lib}/mini_profiler/config.rb +11 -4
  18. data/{Ruby/lib → lib}/mini_profiler/context.rb +0 -0
  19. data/{Ruby/lib → lib}/mini_profiler/custom_timer_struct.rb +0 -0
  20. data/lib/mini_profiler/gc_profiler.rb +181 -0
  21. data/{Ruby/lib → lib}/mini_profiler/page_timer_struct.rb +0 -0
  22. data/{Ruby/lib → lib}/mini_profiler/profiler.rb +81 -39
  23. data/{Ruby/lib → lib}/mini_profiler/profiling_methods.rb +0 -0
  24. data/{Ruby/lib → lib}/mini_profiler/request_timer_struct.rb +0 -0
  25. data/{Ruby/lib → lib}/mini_profiler/sql_timer_struct.rb +0 -0
  26. data/{Ruby/lib → lib}/mini_profiler/storage/abstract_store.rb +0 -0
  27. data/{Ruby/lib → lib}/mini_profiler/storage/file_store.rb +0 -0
  28. data/{Ruby/lib → lib}/mini_profiler/storage/memcache_store.rb +0 -0
  29. data/{Ruby/lib → lib}/mini_profiler/storage/memory_store.rb +0 -0
  30. data/{Ruby/lib → lib}/mini_profiler/storage/redis_store.rb +0 -0
  31. data/{Ruby/lib → lib}/mini_profiler/timer_struct.rb +0 -0
  32. data/lib/mini_profiler/version.rb +5 -0
  33. data/{Ruby/lib → lib}/mini_profiler_rails/railtie.rb +6 -2
  34. data/{Ruby/lib → lib}/patches/net_patches.rb +0 -0
  35. data/{Ruby/lib → lib}/patches/sql_patches.rb +0 -0
  36. data/{Ruby/lib → lib}/rack-mini-profiler.rb +0 -0
  37. data/rack-mini-profiler.gemspec +5 -5
  38. metadata +43 -44
  39. data/Ruby/lib/html/profile_handler.js +0 -1
  40. data/Ruby/lib/mini_profiler/gc_profiler.rb +0 -107
  41. data/Ruby/lib/mini_profiler/gc_profiler_ruby_head.rb +0 -40
  42. data/Ruby/lib/mini_profiler/version.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 50a96f45043bb94f118971de9fe539a5af648d9c
4
- data.tar.gz: 2deba7160023f7ae64ec39bdc456bcaf2c77fb45
3
+ metadata.gz: 5b9507bf24483a76c136680a0bbcc6e4a4363471
4
+ data.tar.gz: 9e99da2d17e0f35e76673adb60f3fcf72324340b
5
5
  SHA512:
6
- metadata.gz: 4444d3a819342722b3e27d8de3d9cbf9687fa3d54f9d9f39214ccb405b05973cc68950687227f3ea7caa4d994f0d6f757b4f34122c24a95689f9563b97e844a2
7
- data.tar.gz: 2a9bdaf1850ca648c2569994f680874ce79bd5351553ce4d1c802119923ac375cddf4ba9d67812a2d4db1e06562af5672a9318aff678a84eef5896a3897b3907
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
- ## Using rack-mini-profiler in your app
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
- All you have to do is include the Gem and you're good to go in development.
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
- 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.
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
- Using Builder:
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
- Using Sinatra:
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
- "use strict";
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
@@ -1,4 +1,4 @@
1
- <script id="profilerTemplate" type="text/x-jquery-tmpl">
1
+ <script id="profilerTemplate" type="text/x-jquery-tmpl">
2
2
 
3
3
  <div class="profiler-result">
4
4
 
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- tbody tr:nth-child(odd) { background-color:#eee; }
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;}
@@ -1,4 +1,4 @@
1
- var MiniProfiler = MiniProfiler || {};
1
+ var MiniProfiler = MiniProfiler || {};
2
2
  MiniProfiler.list = {
3
3
  init:
4
4
  function (options) {
@@ -1,4 +1,4 @@
1
- <script id="tableTemplate" type="text/x-jquery-tmpl">
1
+ <script id="tableTemplate" type="text/x-jquery-tmpl">
2
2
  <table>
3
3
  <thead>
4
4
  <tr>
@@ -31,4 +31,4 @@
31
31
  <td colspan="3"></td>
32
32
  {{/if}}
33
33
  </tr>
34
- </script>
34
+ </script>
@@ -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
- <html>
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>
@@ -12,10 +12,10 @@ module Rack
12
12
  @attributes
13
13
  end
14
14
 
15
- attr_accessor :auto_inject, :base_url_path, :pre_authorize_cb, :position,
16
- :backtrace_remove, :backtrace_includes, :backtrace_ignores, :skip_schema_queries,
17
- :storage, :user_provider, :storage_instance, :storage_options, :skip_paths, :authorization_mode,
18
- :toggle_shortcut, :start_hidden, :backtrace_threshold_ms
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
@@ -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
@@ -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
- # first param is the path
272
- # 0.5 means attempt to collect a sample each 0.5 secs
273
- flamegraph = Flamegraph.generate(nil, fidelity: 0.5) do
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
- # no matter what it is, it should be unviewed, otherwise we will miss POST
325
- @storage.set_unviewed(page_struct['User'], page_struct['Id'])
326
- @storage.save(page_struct)
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
- result = inject_profiler(env,status,headers,body)
333
- return result if result
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>. Just append the script.
409
+ # implicit </body> and </html>. Don't do anything.
387
410
 
388
- return fragment + script
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 ids_json(env)
501
+ def ids(env)
472
502
  # cap at 10 ids, otherwise there is a chance you can blow the header
473
- ids = [current.page_struct["Id"]] + (@storage.get_unviewed_ids(user(env)) || [])[0..8]
474
- ::JSON.generate(ids.uniq)
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
- # cap at 10 ids, otherwise there is a chance you can blow the header
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
- ids = ids_comma_separated(env)
491
- path = "#{env['SCRIPT_NAME']}#{@config.base_url_path}"
492
- version = MiniProfiler::VERSION
493
- position = @config.position
494
- showTrivial = false
495
- showChildren = false
496
- maxTracesToShow = 10
497
- showControls = false
498
- currentId = current.page_struct["Id"]
499
- authorized = true
500
- toggleShortcut = @config.toggle_shortcut
501
- startHidden = @config.start_hidden
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
- [:ids, :path, :version, :position, :showTrivial, :showChildren, :maxTracesToShow, :showControls, :currentId, :authorized, :toggleShortcut, :startHidden].each do |v|
506
- regex = Regexp.new("\\{#{v.to_s}\\}")
507
- script.gsub!(regex, eval(v.to_s).to_s)
546
+ settings.each do |k,v|
547
+ regex = Regexp.new("\\{#{k.to_s}\\}")
548
+ script.gsub!(regex, v.to_s)
508
549
  end
509
- current.inject_js = false
550
+
551
+ current.inject_js = false if current
510
552
  script
511
553
  end
512
554
 
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class MiniProfiler
3
+ VERSION = '898a13ca6797c6bc1fee313e17d388b0'.freeze
4
+ end
5
+ end
@@ -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 = lambda { |env|
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 << "/assets/"
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rack-mini-profiler"
3
- s.version = "0.1.31"
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('Ruby/lib/**/*').reject {|f| File.directory?(f) || f =~ /~$/ } )
12
+ ].concat( Dir.glob('lib/**/*').reject {|f| File.directory?(f) || f =~ /~$/ } )
13
13
  s.extra_rdoc_files = [
14
- "Ruby/README.md",
15
- "Ruby/CHANGELOG"
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 = ["Ruby/lib"]
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.1.31
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-09-03 00:00:00.000000000 Z
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
- - Ruby/README.md
78
- - Ruby/CHANGELOG
77
+ - README.md
78
+ - CHANGELOG
79
79
  files:
80
80
  - rack-mini-profiler.gemspec
81
- - Ruby/lib/mini_profiler_rails/railtie.rb
82
- - Ruby/lib/html/list.css
83
- - Ruby/lib/html/jquery.tmpl.js
84
- - Ruby/lib/html/list.tmpl
85
- - Ruby/lib/html/share.html
86
- - Ruby/lib/html/includes.less
87
- - Ruby/lib/html/profile_handler.js
88
- - Ruby/lib/html/includes.tmpl
89
- - Ruby/lib/html/includes.js
90
- - Ruby/lib/html/list.js
91
- - Ruby/lib/html/jquery.1.7.1.js
92
- - Ruby/lib/html/includes.css
93
- - Ruby/lib/mini_profiler/context.rb
94
- - Ruby/lib/mini_profiler/page_timer_struct.rb
95
- - Ruby/lib/mini_profiler/storage/file_store.rb
96
- - Ruby/lib/mini_profiler/storage/memcache_store.rb
97
- - Ruby/lib/mini_profiler/storage/memory_store.rb
98
- - Ruby/lib/mini_profiler/storage/abstract_store.rb
99
- - Ruby/lib/mini_profiler/storage/redis_store.rb
100
- - Ruby/lib/mini_profiler/client_settings.rb
101
- - Ruby/lib/mini_profiler/profiling_methods.rb
102
- - Ruby/lib/mini_profiler/gc_profiler.rb
103
- - Ruby/lib/mini_profiler/client_timer_struct.rb
104
- - Ruby/lib/mini_profiler/sql_timer_struct.rb
105
- - Ruby/lib/mini_profiler/gc_profiler_ruby_head.rb
106
- - Ruby/lib/mini_profiler/config.rb
107
- - Ruby/lib/mini_profiler/custom_timer_struct.rb
108
- - Ruby/lib/mini_profiler/version.rb
109
- - Ruby/lib/mini_profiler/timer_struct.rb
110
- - Ruby/lib/mini_profiler/profiler.rb
111
- - Ruby/lib/mini_profiler/request_timer_struct.rb
112
- - Ruby/lib/patches/net_patches.rb
113
- - Ruby/lib/patches/sql_patches.rb
114
- - Ruby/lib/rack-mini-profiler.rb
115
- - Ruby/README.md
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
- - Ruby/lib
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: '0'
133
+ version: 1.3.1
135
134
  requirements: []
136
135
  rubyforge_project:
137
- rubygems_version: 2.0.3
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
@@ -1,5 +0,0 @@
1
- module Rack
2
- class MiniProfiler
3
- VERSION = '55905d0d15f4dc1e14b29260abce19b2'.freeze
4
- end
5
- end