easy-prof 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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'