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