easy-prof 1.0.0 → 1.1.0

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.
data/.gitignore CHANGED
@@ -1,3 +1,6 @@
1
1
  doc
2
2
  rdoc
3
3
  .yardoc
4
+ pkg
5
+ *.gem
6
+ Gemfile.lock
@@ -0,0 +1,9 @@
1
+ rvm:
2
+ - ree
3
+ - 1.8.7
4
+ - 1.9.3
5
+ - 2.0.0
6
+
7
+ notifications:
8
+ recipients:
9
+ - kpumuk@kpumuk.info
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in meta-tags.gemspec
4
+ gemspec
@@ -0,0 +1,239 @@
1
+ # easy-prof
2
+
3
+ [![Travis-CI build status](https://secure.travis-ci.org/kpumuk/easy-prof.png)](http://travis-ci.org/kpumuk/easy-prof)
4
+
5
+ Simple and easy to use Ruby code profiler, which could be used
6
+ as a Rails plugin.
7
+
8
+ ## Installation
9
+
10
+ Add the "easy-prof" gem to your `Gemfile`.
11
+
12
+ gem "easy-prof"
13
+
14
+ And run `bundle install` command.
15
+
16
+ ## Description
17
+
18
+ The main idea behind the easy-prof is creating check points and your
19
+ code and measuring time needed to execute code blocks. Here is the
20
+ example of easy-prof output:
21
+
22
+ [home#index] Benchmark results:
23
+ [home#index] debug: Logged in user home page
24
+ [home#index] progress: 0.7002 s [find top videos]
25
+ [home#index] progress: 0.0452 s [build categories list]
26
+ [home#index] progress: 0.0019 s [build tag cloud]
27
+ [home#index] progress: 0.0032 s [find featured videos]
28
+ [home#index] progress: 0.0324 s [find latest videos]
29
+ [home#index] debug: VIEW STARTED
30
+ [home#index] progress: 0.0649 s [top videos render]
31
+ [home#index] progress: 0.0014 s [categories render]
32
+ [home#index] progress: 2.5887 s [tag cloud render]
33
+ [home#index] progress: 0.0488 s [latest videos render]
34
+ [home#index] progress: 0.1053 s [featured video render]
35
+ [home#index] results: 3.592 s
36
+
37
+ From this output you can see what checkpoints takes longer to reach,
38
+ and what code fragments are pretty fast.
39
+
40
+ ## Usage
41
+
42
+ The library extends `Kernel` with a method `easy_profiler`.
43
+ By default profiling is disabled globally, so you should pass `:enabled`
44
+ parameter to enable profiling of particular code. Also there is a time
45
+ `:limit` option which could be used to skip logging of blocks which are
46
+ fast enough.
47
+
48
+ For more details see the options description below.
49
+
50
+ easy_profiler('sleep', :enabled => true) do |p|
51
+ sleep 1
52
+ p.progress('sleep 1')
53
+ p.debug('checkpoint reached')
54
+ sleep 2
55
+ p.progress('sleep 2')
56
+ end
57
+
58
+ Method accepts two parameters: profiling session name and a hash of
59
+ options:
60
+
61
+ * `:enabled` — value indicating whether profiling is enabled.
62
+ * `:limit` — minimum time period which should be reached to
63
+ print profiling log.
64
+ * `:count_ar_instances` — indicating whether profiler should
65
+ log an approximate number of instantiated ActiveRecord objects.
66
+ * `:count_memory_usage` — indicating whether profiler should
67
+ log an approximate amount of memory used.
68
+ * `:logger` — a `Logger` instance.
69
+
70
+ ## Configuration
71
+
72
+ There are some global configuration options exists:
73
+
74
+ EasyProfiler.configure do |config|
75
+ config.enable_profiling = false
76
+ config.print_limit = 0.01
77
+ config.count_ar_instances = false
78
+ config.count_memory_usage = false
79
+ config.logger = nil # or Rails.logger or whatever
80
+ config.colorize_logging = true
81
+ config.live_logging = false
82
+ end
83
+
84
+ * `enable_profiling` — used to enable or disable profiling
85
+ globalle (`false` by default).
86
+ * `print_limit` — used to set a minimum time period in seconds
87
+ which should be reached to dump profile to the log (`0.01`
88
+ by default).
89
+ * `count_ar_instances` — indicating whether profiler should
90
+ log an approximate number of instantiated ActiveRecord objects.
91
+ * `count_memory_usage` — indicating whether profiler should
92
+ log an approximate amount of memory used.
93
+ * `logger` — a `Logger` instance to dump logs to.
94
+ * `colorize_logging` — when `true`, output will be
95
+ colorized (useful when dumping profiling information into the
96
+ Rails log).
97
+ * `live_logging` — when `true`, every profiling info
98
+ will be pushed to the log immediately (by default everything will
99
+ be dumped in the end of profiling session).
100
+
101
+ ## Active Record instances number profiling
102
+
103
+ easy-prof can log a number of instantiated ActiveRecord instances.
104
+ To enable this kind of profiling, use a `:count_ar_instances`
105
+ option or global setting with the same name.
106
+
107
+ Please note, that easy-prof completely disables garbage collector
108
+ during this kind of profiling. It could hurt your overall application
109
+ performance, so do not use it on production boxes. Also I can't
110
+ guaranty 100% precision, but it is about this value in almost all
111
+ cases.
112
+
113
+ Further reading:
114
+ * [That’s Not a Memory Leak, It’s Bloat](http://www.engineyard.com/blog/2009/thats-not-a-memory-leak-its-bloat)
115
+
116
+ ## Memory usage profiling
117
+
118
+ The plugin is able to log an amount of memory used by current Ruby
119
+ process. To enable this kind of profiling, use a `:count_memory_usage`
120
+ option or global setting with the same name.
121
+
122
+ Please note, that easy-prof completely disables garbage collector
123
+ during this kind of profiling. It could hurt your overall application
124
+ performance, so do not use it on production boxes. Also I can't
125
+ guaranty 100% precision, but it is about this value in almost all
126
+ cases.
127
+
128
+ ## Dumping results to the Firebug console
129
+
130
+ If you are profiling a Ruby on Rails application, it could be useful
131
+ to get profiling results from production server sometimes. To achieve
132
+ this you can use a `FirebugLogger`, bundled with this plugin.
133
+ In any controller you have a helper called `firebug_logger`,
134
+ so you can pass it to EasyProfiler using `:logger` option:
135
+
136
+ easy_profiler('home#index', :logger => firebug_logger, :limit => 2) do |p|
137
+ end
138
+
139
+ The idea behind this logger is pretty simple (as everything in this
140
+ plugin): there is an `after_filter` named `dump_firebug_profile`,
141
+ which dumps profiling information after your action finished its work.
142
+ Please note: it will not output any line when profiling session is
143
+ disabled or time limit is not reached.
144
+
145
+ Do not forget to protect firebug output: it is a bad idea to allow
146
+ anyone to see your profiling session dump. You can allow admin
147
+ users only to use firebug, or restrict this feature by IP address.
148
+
149
+ BTW, you can use Firebug Console Lite (http://getfirebug.com/lite.html)
150
+ to get this feature working in any browser! By default it works
151
+ perfectly in Firefox with Firebug installed, and in Safari 4.
152
+
153
+ ## Ruby on Rails application profiling
154
+
155
+ Here is a complete example of a Rails action profiling:
156
+
157
+ class HomeController < ApplicationController
158
+ def index
159
+ easy_profiler('home#index', :enabled => profile_request?, :limit => 2) do |p|
160
+ p.progress 'logged in user home page'
161
+
162
+ @top_videos = Video.top(:limit => 10)
163
+ p.progress 'find top videos'
164
+
165
+ @categories = Category.all(:order => 'name DESC')
166
+ p.progress 'build categories list'
167
+
168
+ @tag_cloud = Tag.tag_cloud(:limit => 200)
169
+ p.progress 'build tag cloud'
170
+
171
+ @featured_videos = Video.featured(limit => 5)
172
+ p.progress 'find featured videos'
173
+
174
+ @latest_videos = Video.latest(:limit => 5)
175
+ p.progress 'find latest videos'
176
+
177
+ @profiler = p
178
+ p.debug 'VIEW STARTED'
179
+ end
180
+ end
181
+
182
+ private
183
+
184
+ # Method returns +true+ if current request should ouput profiling information
185
+ def profile_request?
186
+ params['_with_profiling'] == 'yes'
187
+ end
188
+ end
189
+
190
+ And a view:
191
+
192
+ <div id="top_videos">
193
+ <%= render :partial => 'top_videos' %>
194
+ <% @profiler.progress 'top videos render' %>
195
+ </div>
196
+
197
+ <div class="tabs">
198
+ <ul id="taxonomy">
199
+ <li><a href="#" id="categories" class="current">Categories</a></li>
200
+ <li><a href="#" id="tags">Tags</a></li>
201
+ </ul>
202
+ <div class="categories_panel">
203
+ <%= render :partial => 'categories' %>
204
+ <% @profiler.progress 'categories render' %>
205
+ </div>
206
+ <div class="categories_panel hidden">
207
+ <%= render :partial => 'tag_cloud' %>
208
+ <% @profiler.progress 'tag cloud render' %>
209
+ </div>
210
+ </div>
211
+
212
+ <div class="box">
213
+ <div id="latest">
214
+ <%= render :partial => 'videos', :videos => @latest_videos %>
215
+ <% @profiler.progress 'latest videos render' %>
216
+ </div>
217
+ <div id="featured">
218
+ <%= render :partial => 'videos', :videos => @featured_videos %>
219
+ <% @profiler.progress 'featured video render' %>
220
+ </div>
221
+ </div>
222
+
223
+ As you can see from this example, profiler will be enabled only when
224
+ you pass a _with_profiling parameter with value yes:
225
+
226
+ http://example.com/home?_with_profiling=yes
227
+
228
+ ## Who are the authors?
229
+
230
+ This plugin has been created in Scribd.com for our internal use
231
+ and then the sources were opened for other people to use. All the
232
+ code in this package has been developed by Dmytro Shteflyuk for
233
+ Scribd.com and is released under the MIT license. For more details,
234
+ see the MIT-LICENSE file.
235
+
236
+ ## Credits
237
+
238
+ * Dmytro Shteflyuk (author) <kpumuk@kpumuk.info> http://kpumuk.info
239
+ * Alexey Kovyrin (contributor) <alexey@kovyrin.net> http://kovyrin.net
data/Rakefile CHANGED
@@ -1,36 +1,11 @@
1
- require 'rake'
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
2
3
 
3
- begin
4
- require 'jeweler'
5
- Jeweler::Tasks.new do |gemspec|
6
- gemspec.name = 'easy-prof'
7
- gemspec.summary = 'Simple and easy to use Ruby code profiler'
8
- gemspec.description = 'Simple Ruby code profiler to use both in Rails applications and generic Ruby scripts.'
9
- gemspec.email = 'kpumuk@kpumuk.info'
10
- gemspec.homepage = 'http://github.com/kpumuk/easy-prof'
11
- gemspec.authors = ['Dmytro Shteflyuk']
12
- end
13
- Jeweler::GemcutterTasks.new
14
- rescue LoadError
15
- puts 'Jeweler not available. Install it with: sudo gem install jeweler'
16
- end
17
-
18
- begin
19
- require 'spec/rake/spectask'
20
-
21
- desc 'Default: run unit tests.'
22
- task :default => :spec
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
23
6
 
24
- desc 'Test the easy-prof plugin.'
25
- Spec::Rake::SpecTask.new(:spec) do |t|
26
- t.libs << 'lib'
27
- t.pattern = 'spec/**/*_spec.rb'
28
- t.verbose = true
29
- t.spec_opts = ['-cfs']
30
- end
31
- rescue LoadError
32
- puts 'RSpec not available. Install it with: sudo gem install rspec'
33
- end
7
+ task :test => :spec
8
+ task :default => :spec
34
9
 
35
10
  begin
36
11
  require 'yard'
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'easy_prof/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'easy-prof'
7
+ s.version = EasyProfiler::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Dmytro Shteflyuk']
10
+ s.email = ['kpumuk@kpumuk.info']
11
+ s.homepage = 'http://github.com/kpumuk/easy-prof'
12
+ s.summary = %q{Simple and easy to use Ruby code profiler.}
13
+ s.description = %q{Simple Ruby code profiler to use both in Rails applications and generic Ruby scripts.}
14
+
15
+ s.add_development_dependency 'activerecord', '~> 3.2.15'
16
+ s.add_development_dependency 'rake'
17
+ s.add_development_dependency 'rspec'
18
+ s.add_development_dependency 'yard'
19
+ s.add_development_dependency 'bluecloth'
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.extra_rdoc_files = ['README.md']
25
+ s.rdoc_options = ['--charset=UTF-8']
26
+ s.require_paths = ['lib']
27
+ end
@@ -0,0 +1 @@
1
+ require 'easy_prof'
@@ -1,13 +1,13 @@
1
1
  require 'logger'
2
2
 
3
3
  module EasyProfiler
4
- autoload :Configuration, 'easy_profiler/configuration'
5
- autoload :Profile, 'easy_profiler/profile'
6
- autoload :ProfileInstanceBase, 'easy_profiler/profile_instance_base'
7
- autoload :ProfileInstance, 'easy_profiler/profile_instance'
8
- autoload :NoProfileInstance, 'easy_profiler/no_profile_instance'
9
- autoload :FirebugLogger, 'easy_profiler/firebug_logger'
10
- autoload :ActionControllerExtensions, 'easy_profiler/action_controller_extensions'
4
+ autoload :Configuration, 'easy_prof/configuration'
5
+ autoload :Profile, 'easy_prof/profile'
6
+ autoload :ProfileInstanceBase, 'easy_prof/profile_instance_base'
7
+ autoload :ProfileInstance, 'easy_prof/profile_instance'
8
+ autoload :NoProfileInstance, 'easy_prof/no_profile_instance'
9
+ autoload :FirebugLogger, 'easy_prof/firebug_logger'
10
+ autoload :ActionControllerExtensions, 'easy_prof/action_controller_extensions'
11
11
 
12
12
  module ClassMethods
13
13
  def configure(force = false)
@@ -2,7 +2,7 @@ module EasyProfiler
2
2
  class Configuration
3
3
  # Value indicating whether profiling is globally enabled.
4
4
  attr_reader :enable_profiling
5
-
5
+
6
6
  # Minimum time period which should be reached to dump
7
7
  # profile to the log.
8
8
  attr_reader :print_limit
@@ -32,10 +32,10 @@ module EasyProfiler
32
32
  @count_ar_instances = false
33
33
  @count_memory_usage = false
34
34
  @logger = nil
35
- @colorize_logging = true
35
+ @colorize_logging = false
36
36
  @live_logging = false
37
37
  end
38
-
38
+
39
39
  # Sets a value indicating whether profiling is globally enabled.
40
40
  def enable_profiling=(value)
41
41
  @enable_profiling = !!value
@@ -55,10 +55,10 @@ module EasyProfiler
55
55
 
56
56
  # Sets a value indicating whether profiler should log an
57
57
  # approximate amount of memory used.
58
- #
58
+ #
59
59
  # @param Boolean value
60
60
  # identifies whether memory profiling should be enabled.
61
- #
61
+ #
62
62
  def count_memory_usage=(value)
63
63
  @count_memory_usage = !!value
64
64
  end
@@ -69,7 +69,7 @@ module EasyProfiler
69
69
 
70
70
  # Sets a value indicating whether profiler should flush
71
71
  # logs on every checkpoint.
72
- #
72
+ #
73
73
  def live_logging=(value)
74
74
  @live_logging = !!value
75
75
  end
@@ -82,7 +82,7 @@ module EasyProfiler
82
82
  # information directly to STDOUT. You can use
83
83
  # <tt>EasyProfiler.configuration.logger</tt> to set another
84
84
  # logger.
85
- #
85
+ #
86
86
  def logger
87
87
  unless @logger
88
88
  @logger = if Object.const_defined?(:Rails)
@@ -105,16 +105,26 @@ module EasyProfiler
105
105
  config.logger = options[:logger] if options.has_key?(:logger)
106
106
  config.colorize_logging = options[:colorize_logging] if options.has_key?(:colorize_logging)
107
107
  config.live_logging = options[:live_logging] if options.has_key?(:live_logging)
108
-
109
108
  config
110
109
  end
111
-
110
+
111
+ def self.parse(config)
112
+ case config
113
+ when Hash
114
+ EasyProfiler.configuration.merge(config)
115
+ when EasyProfiler::Configuration
116
+ config
117
+ else
118
+ EasyProfiler.configuration
119
+ end
120
+ end
121
+
112
122
  def disable_gc?
113
123
  count_ar_instances or count_memory_usage
114
124
  end
115
-
125
+
116
126
  def enabled?
117
127
  enable_profiling
118
128
  end
119
129
  end
120
- end
130
+ end
@@ -21,20 +21,22 @@ module EasyProfiler
21
21
  #
22
22
  # Returns:
23
23
  # * an instance of profiler (descendant of the <tt>EasyProfiler::ProfileInstanceBase</tt> class).
24
- def self.start(name, options = {})
24
+ def self.start(name, config = nil)
25
25
  if @@profile_results[name]
26
26
  raise ArgumentError.new("EasyProfiler::Profile.start() collision! '#{name}' is already started.")
27
27
  end
28
28
 
29
- config = EasyProfiler.configuration.merge(options)
30
-
31
- # Disable garbage collector to get more precise results
32
- GC.disable if config.disable_gc?
29
+ config = Configuration.parse(config)
33
30
 
34
31
  klass = config.enabled? ? ProfileInstance : NoProfileInstance
35
32
  instance = klass.new(name, config)
36
33
 
37
34
  @@profile_results[name] = instance
35
+
36
+ # Disable garbage collector to get more precise results
37
+ GC.disable if instance.config.disable_gc?
38
+
39
+ instance
38
40
  end
39
41
 
40
42
  # Finishes a profiling session and dumps results to the log.
@@ -53,7 +55,7 @@ module EasyProfiler
53
55
  end
54
56
 
55
57
  def self.reset!
56
- @@profile_results = {}
58
+ @@profile_results = {}
57
59
  end
58
60
  end
59
- end
61
+ end
@@ -1,6 +1,8 @@
1
1
  module EasyProfiler
2
2
  # Class used when profiling is disabled.
3
3
  class ProfileInstance < ProfileInstanceBase
4
+ @@groups_stack = []
5
+
4
6
  # Sets a profiling checkpoint (block execution time will be printed).
5
7
  #
6
8
  # Parameters:
@@ -33,15 +35,32 @@ module EasyProfiler
33
35
  buffer_checkpoint("debug: #{message}")
34
36
  end
35
37
 
38
+ # Start a group with a specified name.
39
+ #
40
+ # Parameters:
41
+ # * name -- a name of the group.
42
+ #
43
+ def group(name)
44
+ progress "Before group '#{name}'"
45
+ debug 'Started group'
46
+ @@groups_stack << name
47
+ end
48
+
49
+ def end_group
50
+ debug "Finished group"
51
+ @@groups_stack.pop
52
+ end
53
+
36
54
  # Dumps results to the log.
37
55
  def dump_results
56
+ self.end_group while @@groups_stack.any?
57
+
38
58
  progress('END')
39
- t = total
40
59
 
41
- if config.live_logging || false === config.print_limit || t > config.print_limit.to_f
42
- log_header(true)
43
- @buffer.each { |message| log_line(message) }
44
- log_footer(t)
60
+ t = total
61
+ log_footer(t)
62
+ if false === config.print_limit || t > config.print_limit.to_f
63
+ @buffer.each { |message| log_line(*message) }
45
64
  end
46
65
  end
47
66
 
@@ -64,20 +83,22 @@ module EasyProfiler
64
83
 
65
84
  # Buffers a profiling checkpoint.
66
85
  def buffer_checkpoint(message)
67
- log_header
86
+ log_header unless @header_printed
87
+
88
+ group_name = @@groups_stack.last
89
+ name = group_name ? "#{@name}: #{group_name}" : @name
90
+
68
91
  if config.live_logging
69
- log_line(message)
92
+ log_line(message, name)
70
93
  else
71
- @buffer << message
94
+ @buffer << [message, name]
72
95
  end
73
96
  end
74
97
 
75
98
  # Write a header to the log.
76
- def log_header(force = false)
77
- if (config.live_logging && !@header_printed) || (!config.live_logging && force)
78
- log_line("Benchmark results:")
79
- @header_printed = true
80
- end
99
+ def log_header
100
+ @header_printed = true
101
+ buffer_checkpoint("Benchmark results:")
81
102
  end
82
103
 
83
104
  # Write a footer with summary stats to the log.
@@ -90,11 +111,13 @@ module EasyProfiler
90
111
  ", #{format_memory_size(total_memory_usage)}"
91
112
  end
92
113
 
93
- log_line("results: %0.4f s#{ar_instances_count}#{memory_usage_value}" % total_time)
114
+ buffer_checkpoint("results: %0.4f s#{ar_instances_count}#{memory_usage_value}" % total_time)
94
115
  end
95
116
 
96
117
  # Write a log line.
97
- def log_line(line)
118
+ def log_line(line, name = nil)
119
+ name ||= @name
120
+
98
121
  if config.colorize_logging
99
122
  @@row_even, message_color = if @@row_even
100
123
  [false, '4;32;1']
@@ -102,10 +125,10 @@ module EasyProfiler
102
125
  [true, '4;33;1']
103
126
  end
104
127
 
105
- config.logger.info(" [\e[#{message_color}m%s\e[0m] %s" % [@name, line])
128
+ config.logger.info("[\e[#{message_color}m%s\e[0m] %s" % [name, line])
106
129
  else
107
- config.logger.info("[%s] %s" % [@name, line])
130
+ config.logger.info("[%s] %s" % [name, line])
108
131
  end
109
132
  end
110
133
  end
111
- end
134
+ end
@@ -1,7 +1,7 @@
1
1
  module EasyProfiler
2
2
  # Base class for profilers.
3
3
  class ProfileInstanceBase
4
- attr_reader :name, :config
4
+ attr_reader :name, :config, :buffer
5
5
 
6
6
  @@row_even = true
7
7
 
@@ -12,11 +12,7 @@ module EasyProfiler
12
12
  # * options -- a +Hash+ of options (see <tt>EasyProfiler::Profile.start</tt> for details).
13
13
  def initialize(name, config = nil)
14
14
  @name = name
15
- @config = case config
16
- when Hash: EasyProfiler.configuration.merge(config)
17
- when EasyProfiler::Configuration: config
18
- else EasyProfiler.configuration
19
- end
15
+ @config = Configuration.parse(config)
20
16
 
21
17
  @start = @progress = Time.now.to_f
22
18
 
@@ -52,6 +48,18 @@ module EasyProfiler
52
48
  def debug(message)
53
49
  end
54
50
 
51
+ # Start a group with a specified name.
52
+ #
53
+ # Parameters:
54
+ # * name -- a name of the group.
55
+ #
56
+ def group(name, options = {}, &block)
57
+ self
58
+ end
59
+
60
+ def end_group
61
+ end
62
+
55
63
  # Dumps results to the log.
56
64
  def dump_results
57
65
  end
@@ -0,0 +1,4 @@
1
+ module EasyProfiler
2
+ VERSION = '1.1.0'
3
+ end
4
+
@@ -6,7 +6,7 @@ describe EasyProfiler::ProfileInstance do
6
6
  profiler.name.should == 'myprofiler1'
7
7
  profiler.config.should be(EasyProfiler.configuration)
8
8
 
9
- profiler = EasyProfiler::ProfileInstance.new('myprofiler2', { :print_limit => 100 })
9
+ profiler = EasyProfiler::ProfileInstance.new('myprofiler2', :print_limit => 100)
10
10
  profiler.name.should == 'myprofiler2'
11
11
  profiler.config.print_limit.should == 100
12
12
 
@@ -17,14 +17,23 @@ describe EasyProfiler::ProfileInstance do
17
17
  profiler.config.should be(config)
18
18
  end
19
19
 
20
+ it 'should not change global configuration options' do
21
+ EasyProfiler.config.print_limit = 10
22
+
23
+ profiler = EasyProfiler::ProfileInstance.new('myprofiler1', :print_limit => 100)
24
+ profiler.config.print_limit.should == 100
25
+
26
+ EasyProfiler.config.print_limit.should == 10
27
+ end
28
+
20
29
  it 'should respond to :progress' do
21
30
  profiler = EasyProfiler::ProfileInstance.new('myprofiler')
22
31
  profiler.should respond_to(:progress)
23
32
  lambda {
24
33
  profiler.progress('message')
25
- buffer = profiler.instance_variable_get(:@buffer)
26
- buffer.should have(1).item
27
- buffer.first.should match(/progress: \d+\.\d+ s \[message\]/)
34
+ profiler.buffer.should have(2).items
35
+ profiler.buffer[1][0].should match(/progress: \d+\.\d+ s \[message\]/)
36
+ profiler.buffer[1][1].should == 'myprofiler'
28
37
  }.should_not raise_error
29
38
  end
30
39
 
@@ -33,14 +42,14 @@ describe EasyProfiler::ProfileInstance do
33
42
  profiler.should respond_to(:debug)
34
43
  lambda {
35
44
  profiler.debug('message')
36
- buffer = profiler.instance_variable_get(:@buffer)
37
- buffer.should have(1).item
38
- buffer.first.should match(/debug: message/)
45
+ profiler.buffer.should have(2).item
46
+ profiler.buffer[1][0].should match(/debug: message/)
47
+ profiler.buffer[1][1].should == 'myprofiler'
39
48
  }.should_not raise_error
40
49
  end
41
50
 
42
51
  it 'should respond to :dump_results' do
43
- logger = mock('MockLogger')
52
+ logger = double('MockLogger')
44
53
  profiler = EasyProfiler::ProfileInstance.new('myprofiler', :logger => logger, :enabled => true, :limit => false, :colorize_logging => false)
45
54
  profiler.should respond_to(:dump_results)
46
55
 
@@ -57,7 +66,7 @@ describe EasyProfiler::ProfileInstance do
57
66
  end
58
67
 
59
68
  it 'should render nothing when time limit not reached' do
60
- logger = mock('MockLogger')
69
+ logger = double('MockLogger')
61
70
  profiler = EasyProfiler::ProfileInstance.new('myprofiler', :logger => logger, :enabled => true, :limit => 20)
62
71
  logger.should_not_receive(:info)
63
72
  profiler.dump_results
@@ -65,7 +74,7 @@ describe EasyProfiler::ProfileInstance do
65
74
 
66
75
  context 'when live logging is enabled' do
67
76
  before :each do
68
- @logger = mock('MockLogger').as_null_object
77
+ @logger = double('MockLogger').as_null_object
69
78
  @profiler = EasyProfiler::ProfileInstance.new('myprofiler', :logger => @logger, :enabled => true, :live_logging => true, :colorize_logging => false)
70
79
  end
71
80
 
@@ -110,4 +119,4 @@ describe EasyProfiler::ProfileInstance do
110
119
  @profiler.dump_results
111
120
  end
112
121
  end
113
- end
122
+ end
@@ -7,10 +7,13 @@ describe EasyProfiler::Profile do
7
7
  config.print_limit = 0.01
8
8
  config.count_ar_instances = false
9
9
  config.count_memory_usage = false
10
+ config.logger = nil
11
+ config.colorize_logging = false
12
+ config.live_logging = false
10
13
  end
11
14
  EasyProfiler::Profile.reset!
12
15
  end
13
-
16
+
14
17
  context '.start' do
15
18
  it 'should pass name to profile instance' do
16
19
  EasyProfiler::Profile.start('myprofiler').name.should == 'myprofiler'
@@ -21,6 +24,15 @@ describe EasyProfiler::Profile do
21
24
  EasyProfiler::Profile.start('myprofiler', options).config.print_limit.should == 100
22
25
  end
23
26
 
27
+ it 'should not change global configuration options' do
28
+ EasyProfiler.config.print_limit = 10
29
+
30
+ profiler = EasyProfiler::Profile.start('myprofiler', :print_limit => 100)
31
+ profiler.config.print_limit.should == 100
32
+
33
+ EasyProfiler.config.print_limit.should == 10
34
+ end
35
+
24
36
  it 'should create a ProfileInstance object when enabled' do
25
37
  options = { :enabled => true }
26
38
  EasyProfiler::Profile.start('myprofiler', options).class.should == EasyProfiler::ProfileInstance
@@ -63,7 +75,7 @@ describe EasyProfiler::Profile do
63
75
  end
64
76
 
65
77
  it 'should use global :logger value' do
66
- logger = mock('MockLogger')
78
+ logger = double('MockLogger')
67
79
  EasyProfiler.config.logger = logger
68
80
  EasyProfiler::Profile.start('myprofiler2').config.logger.should be(logger)
69
81
  end
@@ -73,7 +85,7 @@ describe EasyProfiler::Profile do
73
85
  EasyProfiler.config.live_logging = true
74
86
  EasyProfiler::Profile.start('myprofiler2').config.live_logging.should be_true
75
87
  end
76
-
88
+
77
89
  it 'should disable garbage collector when needed' do
78
90
  options = { :enabled => true, :count_ar_instances => true }
79
91
  GC.should_receive(:disable)
@@ -100,14 +112,14 @@ describe EasyProfiler::Profile do
100
112
 
101
113
  it 'should enable back garbage collector when needed' do
102
114
  profiler = mock_profile_start('myprofiler1', :enabled => true, :count_ar_instances => true)
103
- profiler.stub!(:dump_results)
115
+ profiler.stub(:dump_results)
104
116
  GC.should_receive(:enable)
105
117
  EasyProfiler::Profile.stop('myprofiler1')
106
118
 
107
119
  profiler = mock_profile_start('myprofiler2', :enabled => true, :count_memory_usage => true)
108
- profiler.stub!(:dump_results)
120
+ profiler.stub(:dump_results)
109
121
  GC.should_receive(:enable)
110
122
  EasyProfiler::Profile.stop('myprofiler2')
111
123
  end
112
124
  end
113
- end
125
+ end
@@ -4,6 +4,6 @@ require File.join(File.dirname(__FILE__), "../lib/easy_prof")
4
4
 
5
5
  def mock_profile_start(name, options = {})
6
6
  config = EasyProfiler.configuration.merge(options)
7
- profiler = mock 'MockProfiler', :name => name, :config => config
7
+ profiler = double('MockProfiler', :name => name, :config => config)
8
8
  EasyProfiler::Profile.send(:class_variable_get, :@@profile_results)[name] = profiler
9
- end
9
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy-prof
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
4
+ hash: 19
5
+ prerelease:
5
6
  segments:
6
7
  - 1
8
+ - 1
7
9
  - 0
8
- - 0
9
- version: 1.0.0
10
+ version: 1.1.0
10
11
  platform: ruby
11
12
  authors:
12
13
  - Dmytro Shteflyuk
@@ -14,33 +15,109 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-02-23 00:00:00 +02:00
18
+ date: 2013-11-13 00:00:00 -05:00
18
19
  default_executable:
19
- dependencies: []
20
-
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 17
30
+ segments:
31
+ - 3
32
+ - 2
33
+ - 15
34
+ version: 3.2.15
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: rspec
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: yard
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ type: :development
78
+ version_requirements: *id004
79
+ - !ruby/object:Gem::Dependency
80
+ name: bluecloth
81
+ prerelease: false
82
+ requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ type: :development
92
+ version_requirements: *id005
21
93
  description: Simple Ruby code profiler to use both in Rails applications and generic Ruby scripts.
22
- email: kpumuk@kpumuk.info
94
+ email:
95
+ - kpumuk@kpumuk.info
23
96
  executables: []
24
97
 
25
98
  extensions: []
26
99
 
27
100
  extra_rdoc_files:
28
- - README.rdoc
101
+ - README.md
29
102
  files:
30
103
  - .gitignore
104
+ - .travis.yml
105
+ - Gemfile
106
+ - Gemfile.lock
31
107
  - MIT-LICENSE
32
- - README.rdoc
108
+ - README.md
33
109
  - Rakefile
34
- - VERSION.yml
35
- - init.rb
110
+ - easy-prof.gemspec
111
+ - lib/easy-prof.rb
36
112
  - lib/easy_prof.rb
37
- - lib/easy_profiler/action_controller_extensions.rb
38
- - lib/easy_profiler/configuration.rb
39
- - lib/easy_profiler/firebug_logger.rb
40
- - lib/easy_profiler/no_profile_instance.rb
41
- - lib/easy_profiler/profile.rb
42
- - lib/easy_profiler/profile_instance.rb
43
- - lib/easy_profiler/profile_instance_base.rb
113
+ - lib/easy_prof/action_controller_extensions.rb
114
+ - lib/easy_prof/configuration.rb
115
+ - lib/easy_prof/firebug_logger.rb
116
+ - lib/easy_prof/no_profile_instance.rb
117
+ - lib/easy_prof/profile.rb
118
+ - lib/easy_prof/profile_instance.rb
119
+ - lib/easy_prof/profile_instance_base.rb
120
+ - lib/easy_prof/version.rb
44
121
  - spec/easy_profiler_spec.rb
45
122
  - spec/no_profile_instance_spec.rb
46
123
  - spec/profile_instance_spec.rb
@@ -56,29 +133,29 @@ rdoc_options:
56
133
  require_paths:
57
134
  - lib
58
135
  required_ruby_version: !ruby/object:Gem::Requirement
136
+ none: false
59
137
  requirements:
60
138
  - - ">="
61
139
  - !ruby/object:Gem::Version
140
+ hash: 3
62
141
  segments:
63
142
  - 0
64
143
  version: "0"
65
144
  required_rubygems_version: !ruby/object:Gem::Requirement
145
+ none: false
66
146
  requirements:
67
147
  - - ">="
68
148
  - !ruby/object:Gem::Version
149
+ hash: 3
69
150
  segments:
70
151
  - 0
71
152
  version: "0"
72
153
  requirements: []
73
154
 
74
155
  rubyforge_project:
75
- rubygems_version: 1.3.6
156
+ rubygems_version: 1.5.2
76
157
  signing_key:
77
158
  specification_version: 3
78
- summary: Simple and easy to use Ruby code profiler
79
- test_files:
80
- - spec/easy_profiler_spec.rb
81
- - spec/no_profile_instance_spec.rb
82
- - spec/profile_instance_spec.rb
83
- - spec/profile_spec.rb
84
- - spec/spec_helper.rb
159
+ summary: Simple and easy to use Ruby code profiler.
160
+ test_files: []
161
+
@@ -1,248 +0,0 @@
1
- = easy-prof
2
-
3
- Simple and easy to use Ruby code profiler, which could be used
4
- as a Rails plugin.
5
-
6
- == Installation
7
-
8
- There are two options when approaching easy-prof installation:
9
-
10
- * using the gem (recommended)
11
- * install as a Rails plugin
12
-
13
- To install as a gem, add this to your environment.rb:
14
-
15
- config.gem 'easy-prof', :lib => 'easy_prof'
16
-
17
- And then run the command:
18
-
19
- sudo rake gems:install
20
-
21
- To install meta-tags as a Rails plugin use this:
22
-
23
- script/plugin install git://github.com/kpumuk/easy-prof.git
24
-
25
- == Description
26
-
27
- The main idea behind the easy-prof is creating check points and your
28
- code and measuring time needed to execute code blocks. Here is the
29
- example of easy-prof output:
30
-
31
- [home#index] Benchmark results:
32
- [home#index] debug: Logged in user home page
33
- [home#index] progress: 0.7002 s [find top videos]
34
- [home#index] progress: 0.0452 s [build categories list]
35
- [home#index] progress: 0.0019 s [build tag cloud]
36
- [home#index] progress: 0.0032 s [find featured videos]
37
- [home#index] progress: 0.0324 s [find latest videos]
38
- [home#index] debug: VIEW STARTED
39
- [home#index] progress: 0.0649 s [top videos render]
40
- [home#index] progress: 0.0014 s [categories render]
41
- [home#index] progress: 2.5887 s [tag cloud render]
42
- [home#index] progress: 0.0488 s [latest videos render]
43
- [home#index] progress: 0.1053 s [featured video render]
44
- [home#index] results: 3.592 s
45
-
46
- From this output you can see what checkpoints takes longer to reach,
47
- and what code fragments are pretty fast.
48
-
49
- == Usage
50
-
51
- The library extends <tt>Kernel</tt> with a method <tt>easy_profiler</tt>.
52
- By default profiling is disabled globally, so you should pass :enabled
53
- parameter to enable profiling of particular code. Also there is a time
54
- :limit option which could be used to skip logging of blocks which are
55
- fast enough.
56
-
57
- For more details see the options description below.
58
-
59
- easy_profiler('sleep', :enabled => true) do |p|
60
- sleep 1
61
- p.progress('sleep 1')
62
- p.debug('checkpoint reached')
63
- sleep 2
64
- p.progress('sleep 2')
65
- end
66
-
67
- Method accepts two parameters: profiling session name and a hash of
68
- options:
69
-
70
- * <tt>:enabled</tt> -- value indicating whether profiling is enabled.
71
- * <tt>:limit</tt> -- minimum time period which should be reached to
72
- print profiling log.
73
- * <tt>:count_ar_instances</tt> -- indicating whether profiler should
74
- log an approximate number of instantiated ActiveRecord objects.
75
- * <tt>:count_memory_usage</tt> -- indicating whether profiler should
76
- log an approximate amount of memory used.
77
- * <tt>:logger</tt> -- a +Logger+ instance.
78
-
79
- == Configuration
80
-
81
- There are some global configuration options exists:
82
-
83
- EasyProfiler.configure do |config|
84
- config.enable_profiling = false
85
- config.print_limit = 0.01
86
- config.count_ar_instances = false
87
- config.count_memory_usage = false
88
- config.logger = nil # or Rails.logger or whatever
89
- config.colorize_logging = true
90
- config.live_logging = false
91
- end
92
-
93
- * <tt>enable_profiling</tt> -- used to enable or disable profiling
94
- globalle (<tt>false</tt> by default).
95
- * <tt>print_limit</tt> -- used to set a minimum time period in seconds
96
- which should be reached to dump profile to the log (<tt>0.01</tt>
97
- by default).
98
- * <tt>count_ar_instances</tt> -- indicating whether profiler should
99
- log an approximate number of instantiated ActiveRecord objects.
100
- * <tt>count_memory_usage</tt> -- indicating whether profiler should
101
- log an approximate amount of memory used.
102
- * <tt>logger</tt> -- a <tt>Logger</tt> instance to dump logs to.
103
- * <tt>colorize_logging</tt> -- when <tt>true</tt>, output will be
104
- colorized (useful when dumping profiling information into the
105
- Rails log).
106
- * <tt>live_logging</tt> -- when <tt>true</tt>, every profiling info
107
- will be pushed to the log immediately (by default everything will
108
- be dumped in the end of profiling session).
109
-
110
- == Active Record instances number profiling
111
-
112
- easy-prof can log a number of instantiated ActiveRecord instances.
113
- To enable this kind of profiling, use a <tt>:count_ar_instances</tt>
114
- option or global setting with the same name.
115
-
116
- Please note, that easy-prof completely disables garbage collector
117
- during this kind of profiling. It could hurt your overall application
118
- performance, so do not use it on production boxes. Also I can't
119
- guaranty 100% precision, but it is about this value in almost all
120
- cases.
121
-
122
- Further reading:
123
- * That’s Not a Memory Leak, It’s Bloat http://www.engineyard.com/blog/2009/thats-not-a-memory-leak-its-bloat/
124
-
125
- == Memory usage profiling
126
-
127
- The plugin is able to log an amount of memory used by current Ruby
128
- process. To enable this kind of profiling, use a <tt>:count_memory_usage</tt>
129
- option or global setting with the same name.
130
-
131
- Please note, that easy-prof completely disables garbage collector
132
- during this kind of profiling. It could hurt your overall application
133
- performance, so do not use it on production boxes. Also I can't
134
- guaranty 100% precision, but it is about this value in almost all
135
- cases.
136
-
137
- == Dumping results to the Firebug console
138
-
139
- If you are profiling a Ruby on Rails application, it could be useful
140
- to get profiling results from production server sometimes. To achieve
141
- this you can use a <tt>FirebugLogger</tt>, bundled with this plugin.
142
- In any controller you have a helper called <tt>firebug_logger</tt>,
143
- so you can pass it to EasyProfiler using <tt>:logger</tt> option:
144
-
145
- easy_profiler('home#index', :logger => firebug_logger, :limit => 2) do |p|
146
- end
147
-
148
- The idea behind this logger is pretty simple (as everything in this
149
- plugin): there is an <tt>after_filter</tt> named <tt>dump_firebug_profile</tt>,
150
- which dumps profiling information after your action finished its work.
151
- Please note: it will not output any line when profiling session is
152
- disabled or time limit is not reached.
153
-
154
- Do not forget to protect firebug output: it is a bad idea to allow
155
- anyone to see your profiling session dump. You can allow admin
156
- users only to use firebug, or restrict this feature by IP address.
157
-
158
- BTW, you can use Firebug Console Lite (http://getfirebug.com/lite.html)
159
- to get this feature working in any browser! By default it works
160
- perfectly in Firefox with Firebug installed, and in Safari 4.
161
-
162
- == Ruby on Rails application profiling
163
-
164
- Here is the complete example of a Rails action profiling:
165
-
166
- class HomeController < ApplicationController
167
- def index
168
- easy_profiler('home#index', :enabled => profile_request?, :limit => 2) do |p|
169
- p.progress 'logged in user home page'
170
-
171
- @top_videos = Video.top(:limit => 10)
172
- p.progress 'find top videos'
173
-
174
- @categories = Category.all(:order => 'name DESC')
175
- p.progress 'build categories list'
176
-
177
- @tag_cloud = Tag.tag_cloud(:limit => 200)
178
- p.progress 'build tag cloud'
179
-
180
- @featured_videos = Video.featured(limit => 5)
181
- p.progress 'find featured videos'
182
-
183
- @latest_videos = Video.latest(:limit => 5)
184
- p.progress 'find latest videos'
185
-
186
- @profiler = p
187
- p.debug 'VIEW STARTED'
188
- end
189
- end
190
-
191
- private
192
-
193
- # Method returns +true+ if current request should ouput profiling information
194
- def profile_request?
195
- params['_with_profiling'] == 'yes'
196
- end
197
- end
198
-
199
- And view:
200
-
201
- <div id="top_videos">
202
- <%= render :partial => 'top_videos' %>
203
- <% @profiler.progress 'top videos render' %>
204
- </div>
205
-
206
- <div class="tabs">
207
- <ul id="taxonomy">
208
- <li><a href="#" id="categories" class="current">Categories</a></li>
209
- <li><a href="#" id="tags">Tags</a></li>
210
- </ul>
211
- <div class="categories_panel">
212
- <%= render :partial => 'categories' %>
213
- <% @profiler.progress 'categories render' %>
214
- </div>
215
- <div class="categories_panel hidden">
216
- <%= render :partial => 'tag_cloud' %>
217
- <% @profiler.progress 'tag cloud render' %>
218
- </div>
219
- </div>
220
-
221
- <div class="box">
222
- <div id="latest">
223
- <%= render :partial => 'videos', :videos => @latest_videos %>
224
- <% @profiler.progress 'latest videos render' %>
225
- </div>
226
- <div id="featured">
227
- <%= render :partial => 'videos', :videos => @featured_videos %>
228
- <% @profiler.progress 'featured video render' %>
229
- </div>
230
- </div>
231
-
232
- As you can see from this example, profiler will be enabled only when
233
- you pass a _with_profiling parameter with value yes:
234
-
235
- http://example.com/home?_with_profiling=yes
236
-
237
- == Who are the authors?
238
-
239
- This plugin has been created in Scribd.com for our internal use
240
- and then the sources were opened for other people to use. All the
241
- code in this package has been developed by Dmytro Shteflyuk for
242
- Scribd.com and is released under the MIT license. For more details,
243
- see the MIT-LICENSE file.
244
-
245
- == Credits
246
-
247
- * Dmytro Shteflyuk (author) <kpumuk@kpumuk.info> http://kpumuk.info
248
- * Alexey Kovyrin (contributor) <alexey@kovyrin.net> http://kovyrin.net
@@ -1,5 +0,0 @@
1
- ---
2
- :patch: 0
3
- :build:
4
- :major: 1
5
- :minor: 0
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require 'easy_prof'