rubyperf 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/misc.xml +11 -0
- data/.idea/modules.xml +9 -0
- data/.idea/rubyperf.iml +15 -0
- data/.idea/vcs.xml +7 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +31 -0
- data/README.rdoc +35 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/perf/meter.rb +374 -0
- data/lib/perf/meter_factory.rb +47 -0
- data/lib/perf/no_op_meter.rb +39 -0
- data/lib/perf/noop_measure.rb +39 -0
- data/lib/perf/report_format.rb +130 -0
- data/lib/perf/report_format_html.rb +34 -0
- data/lib/perf/report_format_simple.rb +67 -0
- data/lib/rubyperf.rb +154 -0
- data/test/helper.rb +24 -0
- data/test/perf_test_example.rb +19 -0
- data/test/rubyperf_test_helpers.rb +43 -0
- data/test/test_perf_meter.rb +230 -0
- metadata +150 -0
data/.document
ADDED
data/.idea/encodings.xml
ADDED
data/.idea/misc.xml
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="DependencyValidationManager">
|
4
|
+
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
5
|
+
</component>
|
6
|
+
<component name="ProjectResources">
|
7
|
+
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
8
|
+
</component>
|
9
|
+
<component name="ProjectRootManager" version="2" project-jdk-name="ruby-1.8.7-p174" project-jdk-type="RUBY_SDK" />
|
10
|
+
</project>
|
11
|
+
|
data/.idea/modules.xml
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="ProjectModuleManager">
|
4
|
+
<modules>
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/rubyperf.iml" filepath="$PROJECT_DIR$/.idea/rubyperf.iml" />
|
6
|
+
</modules>
|
7
|
+
</component>
|
8
|
+
</project>
|
9
|
+
|
data/.idea/rubyperf.iml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<module type="RUBY_MODULE" version="4">
|
3
|
+
<component name="NewModuleRootManager">
|
4
|
+
<content url="file://$MODULE_DIR$" />
|
5
|
+
<orderEntry type="inheritedJdk" />
|
6
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
7
|
+
<orderEntry type="library" scope="PROVIDED" name="rcov (v0.9.11, ruby-1.8.7-p174) [gem]" level="application" />
|
8
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v1.0.10, ruby-1.8.7-p174) [gem]" level="application" />
|
9
|
+
<orderEntry type="library" scope="PROVIDED" name="rake (v0.9.2.2, ruby-1.8.7-p174) [gem]" level="application" />
|
10
|
+
<orderEntry type="library" scope="PROVIDED" name="shoulda (v2.11.3, ruby-1.8.7-p174) [gem]" level="application" />
|
11
|
+
<orderEntry type="library" scope="PROVIDED" name="jeweler (v1.6.4, ruby-1.8.7-p174) [gem]" level="application" />
|
12
|
+
<orderEntry type="library" scope="PROVIDED" name="git (v1.2.5, ruby-1.8.7-p174) [gem]" level="application" />
|
13
|
+
</component>
|
14
|
+
</module>
|
15
|
+
|
data/.idea/vcs.xml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "shoulda", ">= 0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.6.4"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.6.4)
|
6
|
+
bundler (~> 1.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
rake (0.9.2.2)
|
10
|
+
rcov (0.9.11)
|
11
|
+
shoulda (2.11.3)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
bundler (~> 1.0.0)
|
18
|
+
jeweler (~> 1.6.4)
|
19
|
+
rcov
|
20
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Copyright (c) 2012 Lorenzo Pasqualis - DreamBox Learning, Inc
|
2
|
+
|
3
|
+
Project home-page git repository:
|
4
|
+
https://github.com/lpasqualis/rubyperf
|
5
|
+
|
6
|
+
Author can be contacted at:
|
7
|
+
lpasqualis@gmail.com
|
8
|
+
|
9
|
+
Author's Blog:
|
10
|
+
http://www.lorenzopasqualis.com
|
11
|
+
|
12
|
+
LICENSE:
|
13
|
+
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
15
|
+
a copy of this software and associated documentation files (the
|
16
|
+
"Software"), to deal in the Software without restriction, including
|
17
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
18
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
19
|
+
permit persons to whom the Software is furnished to do so, subject to
|
20
|
+
the following conditions:
|
21
|
+
|
22
|
+
The above copyright notice and this permission notice shall be
|
23
|
+
included in all copies or substantial portions of the Software.
|
24
|
+
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
26
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
27
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
28
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
29
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
30
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
31
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
= rubyperf
|
2
|
+
|
3
|
+
A gem to measure execution time of blocks of code, methods and expressions.
|
4
|
+
It generates detailed reports in various formats showing the nested structure
|
5
|
+
of the measures.
|
6
|
+
|
7
|
+
It is designed to give tools to drill in the performance of hot code and
|
8
|
+
identify bottlenecks.
|
9
|
+
|
10
|
+
Currently available output formats for the report: text, html.
|
11
|
+
|
12
|
+
== Contributing to rubyperf
|
13
|
+
|
14
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
15
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
16
|
+
* Fork the project
|
17
|
+
* Start a feature/bugfix branch
|
18
|
+
* Commit and push until you are happy with your contribution
|
19
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
20
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
21
|
+
|
22
|
+
== Copyright
|
23
|
+
|
24
|
+
Copyright (c) 2012 Lorenzo Pasqualis - DreamBox Learning, Inc
|
25
|
+
|
26
|
+
Project home-page git repository:
|
27
|
+
https://github.com/lpasqualis/rubyperf
|
28
|
+
|
29
|
+
Author can be contacted at:
|
30
|
+
lpasqualis@gmail.com
|
31
|
+
|
32
|
+
Author's Blog:
|
33
|
+
http://www.lorenzopasqualis.com
|
34
|
+
See LICENSE.txt for further details.
|
35
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "rubyperf"
|
18
|
+
gem.homepage = "http://github.com/lpasqualis/rubyperf"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{A gem to measure ruby code performance}
|
21
|
+
gem.description = %Q{Measures the performance of blocks of code, and provide reporting in various formats}
|
22
|
+
gem.email = "lpasqualis@gmail.com"
|
23
|
+
gem.authors = ["lpasqualis"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "rubyperf #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/lib/perf/meter.rb
ADDED
@@ -0,0 +1,374 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Lorenzo Pasqualis - DreamBox Learning, Inc
|
3
|
+
# https://github.com/lpasqualis/rubyperf
|
4
|
+
#
|
5
|
+
|
6
|
+
require "benchmark"
|
7
|
+
|
8
|
+
module Perf
|
9
|
+
|
10
|
+
#
|
11
|
+
# Measures the runtime execution speed of a block of code, expression or entire methods.
|
12
|
+
#
|
13
|
+
|
14
|
+
class Meter
|
15
|
+
|
16
|
+
PATH_MEASURES = '\blocks'
|
17
|
+
PATH_METHODS = '\methods'
|
18
|
+
|
19
|
+
METHOD_TYPE_INSTANCE = :instance
|
20
|
+
METHOD_TYPE_CLASS = :class
|
21
|
+
|
22
|
+
attr_accessor :measurements
|
23
|
+
attr_accessor :current_stack
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@measurements = {}
|
27
|
+
@current_stack = []
|
28
|
+
@instrumented_methods = {METHOD_TYPE_INSTANCE=>[],METHOD_TYPE_CLASS=>[]}
|
29
|
+
@class_methods = []
|
30
|
+
end
|
31
|
+
|
32
|
+
# Takes a description and a code block and measures the performance of the block.
|
33
|
+
# It returns the value retuend by the block
|
34
|
+
#
|
35
|
+
# ==== Attributes
|
36
|
+
#
|
37
|
+
# * +what+ - The title that will identify of the block
|
38
|
+
# * +code+ - Block of code to measure
|
39
|
+
#
|
40
|
+
# ==== Examples
|
41
|
+
#
|
42
|
+
# Measures the time taken by the code in the block
|
43
|
+
#
|
44
|
+
# perf = Perf::Meter.new
|
45
|
+
# perf.measure(:func) do
|
46
|
+
# some code here
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Measure the time taken to compute "some_expression"
|
50
|
+
#
|
51
|
+
# if perf.measure(:some_expression) { some_expression }
|
52
|
+
# ...
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# Measure a bunch of things, and divides the measures in sub blocks that get measures separately
|
56
|
+
#
|
57
|
+
# perf.measure(:bunch_of_stuff) do
|
58
|
+
# perf.measure(:thing1) do
|
59
|
+
# ...
|
60
|
+
# end
|
61
|
+
# perf.measure(:thing2) do
|
62
|
+
# perf.measure(:thing2_part1) do
|
63
|
+
# ...
|
64
|
+
# end
|
65
|
+
# perf.measure(:thing2_part2) do
|
66
|
+
# ...
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
|
72
|
+
def measure(what,&code)
|
73
|
+
path="#{PATH_MEASURES}\\#{get_current_path}"
|
74
|
+
@current_stack.push what
|
75
|
+
begin
|
76
|
+
res=measure_full_path(PATH_MEASURES) do
|
77
|
+
measure_full_path("#{path}#{what}",&code)
|
78
|
+
end
|
79
|
+
ensure
|
80
|
+
@current_stack.pop
|
81
|
+
end
|
82
|
+
res
|
83
|
+
end
|
84
|
+
|
85
|
+
# Takes a description and an expression returning a value and measures the performance of the expression storing the
|
86
|
+
# result by returned value. Should be used only for expressions that can return only a small discrete number of unique
|
87
|
+
# values, such a flag for example.
|
88
|
+
#
|
89
|
+
# It returns the value returned by the block
|
90
|
+
#
|
91
|
+
# ==== Attributes
|
92
|
+
#
|
93
|
+
# * +what+ - The title that will identify of the block
|
94
|
+
# * +code+ - Block of code to measure
|
95
|
+
#
|
96
|
+
# ==== Examples
|
97
|
+
#
|
98
|
+
# Measures the time take to compute the existence of user xyz and will give you stats for the case in which the
|
99
|
+
# result is true and false.
|
100
|
+
#
|
101
|
+
# perf = Perf::Meter.new
|
102
|
+
# if perf.measure_result(:long_epression) { User.find(xyz).nil? }
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
|
106
|
+
def measure_result(what,&code)
|
107
|
+
res=measure(what,&code)
|
108
|
+
merge_measures(what,"#{what} = \"#{res.to_s}\"")
|
109
|
+
res
|
110
|
+
end
|
111
|
+
|
112
|
+
# Puts a wrapper around a set of methods of a specific class to measure their performance.
|
113
|
+
# The set is provided with an array of iinstance methods, and one of class methods.
|
114
|
+
#
|
115
|
+
# The method defines the wrapper, yelds to the block, and then restores the instrumented class.
|
116
|
+
# This ensures that the instrumented class is restored, and that the instrumentation occurs only in the context
|
117
|
+
# of the block
|
118
|
+
#
|
119
|
+
# ==== Attributes
|
120
|
+
#
|
121
|
+
# * +klass+ - The Class containing the instance method that you want to measure
|
122
|
+
# * +imethods+ - An array of instance methods that you want to measure
|
123
|
+
# * +cmethods+ - An array of class methods that you want to measure
|
124
|
+
#
|
125
|
+
# ==== Examples
|
126
|
+
#
|
127
|
+
# perf = Perf::Meter.new
|
128
|
+
# m.method_meters(PerfTestExample,[:test,:test_np],[:static_method]) do
|
129
|
+
# a=PerfTestExample.new
|
130
|
+
# a.test(1,2,3)
|
131
|
+
# a.test_np
|
132
|
+
# PerfTestExample.static_method
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# After this m contains measures for the executions of the instance methods test, test_np and the class
|
136
|
+
# methods static_method
|
137
|
+
#
|
138
|
+
|
139
|
+
def method_meters(klass,imethods=[],cmethods=[])
|
140
|
+
res=nil
|
141
|
+
begin
|
142
|
+
imethods.each {|m| measure_instance_method(klass,m) }
|
143
|
+
cmethods.each {|m| measure_class_method(klass,m) }
|
144
|
+
res=yield
|
145
|
+
ensure
|
146
|
+
imethods.each {|m| restore_instance_method(klass,m) }
|
147
|
+
cmethods.each {|m| restore_class_method(klass,m) }
|
148
|
+
end
|
149
|
+
res
|
150
|
+
end
|
151
|
+
|
152
|
+
# Puts a wrapper around instance methods of a specific class to measure their performance
|
153
|
+
# Remember to use restore_instance_method when you are done, otherwise the method will stay instrumented.
|
154
|
+
#
|
155
|
+
# Use sparingly!
|
156
|
+
#
|
157
|
+
# ==== Attributes
|
158
|
+
#
|
159
|
+
# * +klass+ - The Class containing the instance method that you want to measure
|
160
|
+
# * +method_name+ - The name of the method that you want to measure
|
161
|
+
#
|
162
|
+
# ==== Examples
|
163
|
+
#
|
164
|
+
# Instruments the class find so that the execution of the method "find" will be measures every time that is used.
|
165
|
+
#
|
166
|
+
# perf = Perf::Meter.new
|
167
|
+
# perf.measure_instance_method(User,:find)
|
168
|
+
# ..
|
169
|
+
#
|
170
|
+
# Removes the instrumentation (important!)
|
171
|
+
#
|
172
|
+
# perf.restore_instance_method(User,:find)
|
173
|
+
#
|
174
|
+
# Removes all instrumentation from class User
|
175
|
+
#
|
176
|
+
# perf.restore_all_instance_methods(User)
|
177
|
+
#
|
178
|
+
|
179
|
+
def measure_instance_method(klass,method_name)
|
180
|
+
measure_method_by_type(klass,method_name,METHOD_TYPE_INSTANCE)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Removes the instrumentation of a instance method in a given class.
|
184
|
+
# See measure_instance_method for more information.
|
185
|
+
|
186
|
+
def restore_instance_method(klass,method_name)
|
187
|
+
restore_method_by_type(klass,method_name,METHOD_TYPE_INSTANCE)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Removes all instrumentation of instance methods in a given class.
|
191
|
+
# See measure_instance_method for more information.
|
192
|
+
|
193
|
+
def restore_all_instance_methods(klass)
|
194
|
+
restore_all_methods_by_type(klass,METHOD_TYPE_INSTANCE)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Puts a wrapper around class methods of a specific class to measure their performance
|
198
|
+
# Remember to use restore_class_method when you are done, otherwise the class method will stay instrumented.
|
199
|
+
#
|
200
|
+
# Use sparingly!
|
201
|
+
#
|
202
|
+
# ==== Attributes
|
203
|
+
#
|
204
|
+
# * +klass+ - The Class containing the instance method that you want to measure
|
205
|
+
# * +method_name+ - The name of the class method that you want to measure
|
206
|
+
#
|
207
|
+
# ==== Examples
|
208
|
+
#
|
209
|
+
# Instruments the class find so that the execution of the class method "static_method" will be measures every time that is used.
|
210
|
+
#
|
211
|
+
# perf = Perf::Meter.new
|
212
|
+
# perf.measure_class_method(SomeClass,:static_method)
|
213
|
+
# ..
|
214
|
+
#
|
215
|
+
# Removes the instrumentation (important!)
|
216
|
+
#
|
217
|
+
# perf.restore_class_method(SomeClass,:static_method)
|
218
|
+
#
|
219
|
+
# Removes all instrumentation from class SomeClass
|
220
|
+
#
|
221
|
+
# perf.restore_all_class_methods(SomeClass)
|
222
|
+
#
|
223
|
+
|
224
|
+
def measure_class_method(klass,method_name)
|
225
|
+
measure_method_by_type(class << klass; self end,method_name,METHOD_TYPE_CLASS)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Removes the instrumentation of a class method in a given class.
|
229
|
+
# See measure_class_method for more information.
|
230
|
+
|
231
|
+
def restore_class_method(klass,method_name)
|
232
|
+
restore_method_by_type(class << klass; self end,method_name,METHOD_TYPE_CLASS)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Removes the instrumentation of all class methods in a given class.
|
236
|
+
# See measure_class_method for more information.
|
237
|
+
|
238
|
+
def restore_all_class_methods(klass)
|
239
|
+
restore_all_methods_by_type(class << klass; self end,METHOD_TYPE_CLASS)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Removes all instrumentation of class methods and instance methods in a given class.
|
243
|
+
# See measure_class_method for more information.
|
244
|
+
|
245
|
+
def restore_all_methods(klass)
|
246
|
+
restore_all_instance_methods(klass)
|
247
|
+
restore_all_class_methods(klass)
|
248
|
+
end
|
249
|
+
|
250
|
+
# Measures a block of code given a full path. Should not be called directly unless you know what you are doing.
|
251
|
+
|
252
|
+
def measure_full_path(path,&code)
|
253
|
+
m=get_measurement(path)
|
254
|
+
m[:count] += 1
|
255
|
+
if m[:measuring]
|
256
|
+
res=code.call
|
257
|
+
else
|
258
|
+
res=nil
|
259
|
+
m[:measuring] = true
|
260
|
+
begin
|
261
|
+
m[:time] += Benchmark.measure { res=code.call }
|
262
|
+
ensure
|
263
|
+
m[:measuring] = false
|
264
|
+
end
|
265
|
+
end
|
266
|
+
res
|
267
|
+
end
|
268
|
+
|
269
|
+
private
|
270
|
+
|
271
|
+
def set_measurement(path,m)
|
272
|
+
@measurements[path]=m
|
273
|
+
end
|
274
|
+
|
275
|
+
def get_current_path
|
276
|
+
@current_stack.join("\\") + (!@current_stack.empty? ? "\\" : "")
|
277
|
+
end
|
278
|
+
|
279
|
+
def merge_measures(what_from,what_to)
|
280
|
+
measurement_root = "#{PATH_MEASURES}\\#{get_current_path}"
|
281
|
+
path_from = "#{measurement_root}#{what_from}"
|
282
|
+
path_to = "#{measurement_root}#{what_to}"
|
283
|
+
m_from = get_measurement(path_from)
|
284
|
+
m_to = get_measurement(path_to)
|
285
|
+
m_to[:time] += m_from[:time]
|
286
|
+
m_to[:count] += m_from[:count]
|
287
|
+
m_to[:measuring] ||= m_from[:measuring]
|
288
|
+
clear_measurement(path_from)
|
289
|
+
end
|
290
|
+
|
291
|
+
def clear_measurement(path)
|
292
|
+
@measurements.delete(path)
|
293
|
+
end
|
294
|
+
|
295
|
+
def get_measurement(path)
|
296
|
+
@measurements[path] ||= {:count => 0,
|
297
|
+
:time => Benchmark::Tms.new,
|
298
|
+
:measuring => false}
|
299
|
+
end
|
300
|
+
|
301
|
+
def measure_method_by_type(klass,method_name,type)
|
302
|
+
unless @instrumented_methods[type].find{|x| x[:klass]==klass && x[:method]==method_name}
|
303
|
+
klass_path="#{PATH_METHODS}\\#{klass}"
|
304
|
+
m = get_measurement("#{klass_path}\\#{method_name}")
|
305
|
+
old_method_symbol="rubyperf_org_#{method_name}".to_sym
|
306
|
+
@instrumented_methods[type] << { :klass=>klass, :method=>method_name, :perf=>m, :org=>old_method_symbol }
|
307
|
+
perf=self
|
308
|
+
klass.send(:alias_method, old_method_symbol,method_name)
|
309
|
+
klass.send(:define_method,method_name) do |*args|
|
310
|
+
res=nil
|
311
|
+
m[:count] += 1
|
312
|
+
t = perf.measure_full_path(PATH_METHODS) do
|
313
|
+
perf.measure_full_path(klass_path) do
|
314
|
+
Benchmark.measure{ res=self.send(old_method_symbol, *args) }
|
315
|
+
end
|
316
|
+
end
|
317
|
+
m[:time] += t
|
318
|
+
res
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# Removes the instrumentation of a instance method in a given class.
|
324
|
+
# See measure_instance_method for more information.
|
325
|
+
|
326
|
+
def restore_method_by_type(klass,method_name,type)
|
327
|
+
if (im=@instrumented_methods[type].find{|x| x[:klass]==klass && x[:method]==method_name})
|
328
|
+
klass.send(:remove_method,im[:method])
|
329
|
+
klass.send(:alias_method, im[:method], im[:org])
|
330
|
+
klass.send(:remove_method,im[:org])
|
331
|
+
@instrumented_methods[type].delete(im)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Removes all instrumentation of instance methods in a given class.
|
336
|
+
# See measure_instance_method for more information.
|
337
|
+
|
338
|
+
def restore_all_methods_by_type(klass,type)
|
339
|
+
remove=[]
|
340
|
+
@instrumented_methods[type].select {|x| x[:klass]==klass}.each do |im|
|
341
|
+
klass.send(:remove_method,im[:method])
|
342
|
+
klass.send(:alias_method, im[:method], im[:org])
|
343
|
+
klass.send(:remove_method,im[:org])
|
344
|
+
remove<<im
|
345
|
+
end
|
346
|
+
remove.each do |im|
|
347
|
+
@instrumented_methods[type].delete(im)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
# You can generate a report using one of the built-in report formats with a simple syntax shortcut
|
352
|
+
#
|
353
|
+
# m=Perf::Meter.new
|
354
|
+
# m.report_FORMAT
|
355
|
+
#
|
356
|
+
# Where FORMAT is the ending part of one of the ReportFormatFORMAT classes built in.
|
357
|
+
#
|
358
|
+
# ==== Examples
|
359
|
+
#
|
360
|
+
# m=Perf::Meter.new
|
361
|
+
# m.measure(:something) {something}
|
362
|
+
# puts m.report_html
|
363
|
+
# puts m.report_simple
|
364
|
+
#
|
365
|
+
|
366
|
+
def method_missing(method_sym, *arguments, &block)
|
367
|
+
if method_sym.to_s =~ /^report_(.*)$/
|
368
|
+
klass=Object.const_get("Perf").const_get("ReportFormat#{$1.capitalize}")
|
369
|
+
return klass.new.format(self) if klass
|
370
|
+
end
|
371
|
+
super
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Lorenzo Pasqualis - DreamBox Learning, Inc
|
3
|
+
# https://github.com/lpasqualis/rubyperf
|
4
|
+
#
|
5
|
+
|
6
|
+
module Perf
|
7
|
+
|
8
|
+
# Simple Perf::Meter factory and singleton management.
|
9
|
+
# Useful to not have to pass around Perf::Meter objects and still be able to generate stats in various parts of
|
10
|
+
# the code.
|
11
|
+
#
|
12
|
+
class MeterFactory
|
13
|
+
|
14
|
+
DEFAULT_METER = :default
|
15
|
+
|
16
|
+
# Returns a Perf::Meter with a given key, and creates it lazly if it doesn't exist'.
|
17
|
+
def self.get(key=DEFAULT_METER)
|
18
|
+
@@perf_meters ||= {}
|
19
|
+
@@perf_meters[key] ||= Perf::Meter.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# Pushes a Perf::Meter into a key
|
23
|
+
def self.set_meter(key,meter)
|
24
|
+
@@perf_meters ||= {}
|
25
|
+
@@perf_meters[key]=meter
|
26
|
+
end
|
27
|
+
|
28
|
+
# Sets the default meter.
|
29
|
+
def self.set_default(meter)
|
30
|
+
set_meter(DEFAULT_METER,meter)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.all
|
34
|
+
@@perf_meters ||= {}
|
35
|
+
return @@perf_meters.clone
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.clear_meter(key=DEFAULT_METER)
|
39
|
+
@@perf_meters.delete(key) if @@perf_meters
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.clear_all!
|
43
|
+
@@perf_meters=nil
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Lorenzo Pasqualis - DreamBox Learning, Inc
|
3
|
+
# https://github.com/lpasqualis/rubyperf
|
4
|
+
#
|
5
|
+
|
6
|
+
module Perf
|
7
|
+
#
|
8
|
+
# This class can be used in substitution to a Perf::Measure class to avoid overhead when performance measurments is not
|
9
|
+
# required. It needs to maintain the same API as Perf::Measure.
|
10
|
+
#
|
11
|
+
class NoOpMeter
|
12
|
+
|
13
|
+
def initialize(logger = nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear
|
17
|
+
end
|
18
|
+
|
19
|
+
#############################################################################################################
|
20
|
+
|
21
|
+
def measure(what,type=nil)
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
|
25
|
+
def count_value(what_to_count)
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def report_arr(options={})
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
def report(options={})
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|