rubyperf 1.3.5 → 1.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/perf/meter.rb +59 -19
- data/lib/perf/report_format.rb +25 -21
- data/rubyperf.gemspec +2 -2
- data/test/test_perf_meter.rb +20 -11
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.3.
|
1
|
+
1.3.6
|
data/lib/perf/meter.rb
CHANGED
@@ -14,9 +14,22 @@ module Perf
|
|
14
14
|
|
15
15
|
class Meter
|
16
16
|
|
17
|
+
# Constant for accuracy. The constant represents the upper bound of its description.
|
18
|
+
|
19
|
+
ACCURACY_UNKNOWN = 0.0
|
20
|
+
ACCURACY_VERY_POOR = 1.0
|
21
|
+
ACCURACY_POOR = 50.0
|
22
|
+
ACCURACY_FAIR = 100.0
|
23
|
+
ACCURACY_GOOD = 1000.0
|
24
|
+
ACCURACY_EXCELLENT = 1.0/0
|
25
|
+
|
26
|
+
# Name of the path roots
|
27
|
+
|
17
28
|
PATH_MEASURES = '\blocks'
|
18
29
|
PATH_METHODS = '\methods'
|
19
30
|
|
31
|
+
# Hash keys for instrumented methods
|
32
|
+
|
20
33
|
METHOD_TYPE_INSTANCE = :instance
|
21
34
|
METHOD_TYPE_CLASS = :class
|
22
35
|
|
@@ -27,7 +40,7 @@ module Perf
|
|
27
40
|
|
28
41
|
# Overhead calculation tuning constants
|
29
42
|
OVERHEAD_CALC_MAX_REPETITIONS = 1000
|
30
|
-
OVERHEAD_CALC_RUNS =
|
43
|
+
OVERHEAD_CALC_RUNS = 10
|
31
44
|
OVERHEAD_CALC_MIN_TIME = 0.1
|
32
45
|
|
33
46
|
# Creation of a Perf::Meter allows you to specify if you want to consider the overhead in the calculation or not.
|
@@ -41,19 +54,42 @@ module Perf
|
|
41
54
|
@measurements = {} # A hash of Measure
|
42
55
|
@current_path = nil
|
43
56
|
@instrumented_methods = {METHOD_TYPE_INSTANCE=>[],METHOD_TYPE_CLASS=>[]}
|
44
|
-
@class_methods = []
|
45
57
|
@subtract_overhead = @options[:subtract_overhead]
|
46
58
|
if @@overhead.nil?
|
47
|
-
@@overhead
|
48
|
-
@measurements
|
59
|
+
@@overhead = measure_overhead
|
60
|
+
@measurements = {} # A hash of Measure; must repeat here to cleanup what measure_overhead did
|
49
61
|
end
|
50
62
|
end
|
51
63
|
|
52
64
|
def overhead
|
53
65
|
if @subtract_overhead
|
54
|
-
@@overhead.
|
66
|
+
@@overhead.dup
|
55
67
|
else
|
56
|
-
Benchmark::Tms.new
|
68
|
+
{:time=>Benchmark::Tms.new,:count=>0}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def adjusted_time(m)
|
73
|
+
return m.time if !@subtract_overhead || !@overhead
|
74
|
+
|
75
|
+
utime,stime,cutime,cstime,real = nil,nil,nil,nil,nil
|
76
|
+
|
77
|
+
adj=m.time-((@overhead[:time]*m.count)/@overhead[:count])
|
78
|
+
|
79
|
+
utime = 0.0 if adj.utime < 0.0
|
80
|
+
stime = 0.0 if adj.stime < 0.0
|
81
|
+
cutime = 0.0 if adj.cutime < 0.0
|
82
|
+
cstime = 0.0 if adj.cstime < 0.0
|
83
|
+
real = 0.0 if adj.real < 0.0
|
84
|
+
|
85
|
+
if utime || stime || cutime || cstime || real
|
86
|
+
Benchmark::Tms.new(utime || adj.utime,
|
87
|
+
stime || adj.stime,
|
88
|
+
cutime || adj.cutime,
|
89
|
+
cstime || adj.cstime,
|
90
|
+
real || adj.real)
|
91
|
+
else
|
92
|
+
adj
|
57
93
|
end
|
58
94
|
end
|
59
95
|
|
@@ -124,17 +160,14 @@ module Perf
|
|
124
160
|
begin
|
125
161
|
m=get_measurement(@current_path)
|
126
162
|
m.count += 1
|
163
|
+
root.count += 1 if root
|
127
164
|
m.measuring +=1
|
128
165
|
if m.measuring>1
|
129
166
|
res=code.call
|
130
167
|
else
|
131
168
|
t = Benchmark.measure { res=code.call }
|
132
|
-
|
133
|
-
|
134
|
-
if t.total>=0 || t.real>=0
|
135
|
-
m.time += t
|
136
|
-
root.time += t if root
|
137
|
-
end
|
169
|
+
root.time += t if root
|
170
|
+
m.time += t
|
138
171
|
end
|
139
172
|
ensure
|
140
173
|
@current_path=current_path
|
@@ -317,15 +350,22 @@ module Perf
|
|
317
350
|
|
318
351
|
def accuracy(path)
|
319
352
|
if @@overhead
|
320
|
-
over=@@overhead.total+@@overhead.real
|
321
|
-
if over>0
|
353
|
+
over=@@overhead[:time].total+@@overhead[:time].real
|
354
|
+
if over>0
|
322
355
|
m=get_measurement(path)
|
323
|
-
|
324
|
-
return (m.time.total+m.time.real) / (over*m.count)
|
325
|
-
end
|
356
|
+
return ((m.time.total+m.time.real)*@@overhead[:count] / (over*m.count)) if m.count>0
|
326
357
|
end
|
327
358
|
end
|
328
|
-
-1
|
359
|
+
-1.0
|
360
|
+
end
|
361
|
+
|
362
|
+
# The overhead cannot be larger that any of the measures taken. If a measure taken is larger than the overhead,
|
363
|
+
# than this function takes care of adjusting the overhead. This is called by the ReportFormat class just before
|
364
|
+
# rendering the report, so you should not have to call this by hand unless you are interested in getting the
|
365
|
+
# overhead.
|
366
|
+
|
367
|
+
def adjust_overhead
|
368
|
+
false
|
329
369
|
end
|
330
370
|
|
331
371
|
protected
|
@@ -347,7 +387,7 @@ protected
|
|
347
387
|
cnt += runs # Count the total runs
|
348
388
|
runs *= 2 # Increases the number of runs to quickly adapt to the speed of the machine
|
349
389
|
end
|
350
|
-
t
|
390
|
+
{:time=>t,:count=>cnt}
|
351
391
|
end
|
352
392
|
|
353
393
|
def set_measurement(path,m)
|
data/lib/perf/report_format.rb
CHANGED
@@ -13,8 +13,20 @@ module Perf
|
|
13
13
|
#
|
14
14
|
class ReportFormat
|
15
15
|
|
16
|
+
# Descrition of the accuracy, as reported by the reports
|
17
|
+
|
18
|
+
ACCURACY_DESCRIPTION = {Perf::Meter::ACCURACY_UNKNOWN => "?",
|
19
|
+
Perf::Meter::ACCURACY_VERY_POOR => "very poor",
|
20
|
+
Perf::Meter::ACCURACY_POOR => "poor",
|
21
|
+
Perf::Meter::ACCURACY_FAIR => "fair",
|
22
|
+
Perf::Meter::ACCURACY_GOOD => "good",
|
23
|
+
Perf::Meter::ACCURACY_EXCELLENT => "excellent"}
|
24
|
+
|
25
|
+
# Largest accuracy description length
|
26
|
+
MAX_ACCURACY_SIZE = ACCURACY_DESCRIPTION.values.map{|x| x.length}.max+1 # Maximium size of the accuracy value returned by format_accuracy
|
27
|
+
|
28
|
+
# Minimum possible time
|
16
29
|
MIN_TOTAL_TIME = 1.0e-10
|
17
|
-
MAX_ACCURACY_SIZE = 10
|
18
30
|
|
19
31
|
# Format takes a Perf::Meter plus a hash of options and converts it into a header, followed by a series
|
20
32
|
# of entries in a hash format that can be easily converted in any other format such as Text, HTML, XML, etc.
|
@@ -29,6 +41,9 @@ module Perf
|
|
29
41
|
#
|
30
42
|
|
31
43
|
def format(perf,options={})
|
44
|
+
|
45
|
+
perf.adjust_overhead
|
46
|
+
|
32
47
|
options||={}
|
33
48
|
options[:max_count_len] ||= 6
|
34
49
|
options[:filter_below_accuracy] ||= nil
|
@@ -48,10 +63,10 @@ module Perf
|
|
48
63
|
max_title = title_len if title_len>max_title
|
49
64
|
max_count = m.count.to_s.length if m.count.to_s.length>max_count
|
50
65
|
|
51
|
-
total += m
|
66
|
+
total += perf.adjusted_time(m) if path.size==2 # This calculates the max of the level-1 entries needed for the root entry.
|
52
67
|
end
|
53
68
|
|
54
|
-
totals=[total.real]
|
69
|
+
totals=[total.real+total.total]
|
55
70
|
depth=1
|
56
71
|
keys_in_order.each do |what|
|
57
72
|
m = perf.measurements[what]
|
@@ -64,9 +79,10 @@ module Perf
|
|
64
79
|
end
|
65
80
|
depth=path.size-1
|
66
81
|
end
|
67
|
-
|
68
|
-
totals[totals.size-1] =
|
69
|
-
|
82
|
+
adj=perf.adjusted_time(m)
|
83
|
+
totals[totals.size-1] = adj.real+adj.total
|
84
|
+
#totals[totals.size-1] = MIN_TOTAL_TIME if totals[totals.size-1]<MIN_TOTAL_TIME
|
85
|
+
percents[what]=((adj.real+adj.total)*100.0)/totals[totals.size-2]
|
70
86
|
end
|
71
87
|
|
72
88
|
# Header
|
@@ -74,7 +90,7 @@ module Perf
|
|
74
90
|
:percent => "percent",
|
75
91
|
:count => "count", :max_count => max_count,
|
76
92
|
:time => Benchmark::Tms::CAPTION,
|
77
|
-
:accuracy
|
93
|
+
:accuracy => "accuracy", :max_accuracy => MAX_ACCURACY_SIZE,
|
78
94
|
:options => options)
|
79
95
|
|
80
96
|
# Root
|
@@ -89,7 +105,7 @@ module Perf
|
|
89
105
|
rep << format_measure(:title => title, :max_title => max_title,
|
90
106
|
:percent => percents[what]||0.0,
|
91
107
|
:count => m.count, :max_count => max_count,
|
92
|
-
:time => m
|
108
|
+
:time => perf.adjusted_time(m),
|
93
109
|
:accuracy => format_accuracy(accuracy), :max_accuracy => MAX_ACCURACY_SIZE,
|
94
110
|
:options => options)
|
95
111
|
end
|
@@ -143,19 +159,7 @@ module Perf
|
|
143
159
|
# See Perf::Meter#accuracy for more information
|
144
160
|
|
145
161
|
def format_accuracy(accuracy)
|
146
|
-
|
147
|
-
"unknown"
|
148
|
-
elsif accuracy<=1
|
149
|
-
"very poor"
|
150
|
-
elsif accuracy<=50
|
151
|
-
"poor"
|
152
|
-
elsif accuracy<=100
|
153
|
-
"fair"
|
154
|
-
elsif accuracy<=1000
|
155
|
-
"good"
|
156
|
-
else
|
157
|
-
"excellent"
|
158
|
-
end
|
162
|
+
ACCURACY_DESCRIPTION[ACCURACY_DESCRIPTION.keys.sort.find{|a| a>=accuracy}]
|
159
163
|
end
|
160
164
|
|
161
165
|
end
|
data/rubyperf.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rubyperf}
|
8
|
-
s.version = "1.3.
|
8
|
+
s.version = "1.3.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["lpasqualis"]
|
12
|
-
s.date = %q{2012-01-
|
12
|
+
s.date = %q{2012-01-17}
|
13
13
|
s.description = %q{Used to easily measure the performance of blocks of Ruby code, expressions and methods; provides reporting in various formats}
|
14
14
|
s.email = %q{lpasqualis@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/test_perf_meter.rb
CHANGED
@@ -66,7 +66,7 @@ class TestPerfMeter < Test::Unit::TestCase
|
|
66
66
|
Array.new(1000000,"abc").reverse.sort
|
67
67
|
end
|
68
68
|
|
69
|
-
assert_equal ['\blocks,
|
69
|
+
assert_equal ['\blocks,9',
|
70
70
|
'\blocks\empty,1',
|
71
71
|
'\blocks\emtpy_loop,1',
|
72
72
|
'\blocks\rough_overhead_x10000,1',
|
@@ -131,12 +131,11 @@ class TestPerfMeter < Test::Unit::TestCase
|
|
131
131
|
m.measure(:a) do
|
132
132
|
("123"*1_000_000).reverse
|
133
133
|
end
|
134
|
-
assert m.accuracy(m.measurements['\blocks'].path)
|
135
|
-
assert m.accuracy(m.measurements['\blocks\a'].path)
|
136
|
-
assert m.accuracy(m.measurements['\blocks\b'].path) <
|
137
|
-
assert_equal 2,m.report_list_of_measures(:filter_below_accuracy=>
|
138
|
-
assert_equal
|
139
|
-
assert_equal 3,m.report_list_of_measures(:filter_below_accuracy=>-10).length
|
134
|
+
assert m.accuracy(m.measurements['\blocks'].path) > Perf::Meter::ACCURACY_UNKNOWN
|
135
|
+
assert m.accuracy(m.measurements['\blocks\a'].path) > Perf::Meter::ACCURACY_UNKNOWN
|
136
|
+
assert m.accuracy(m.measurements['\blocks\b'].path) < Perf::Meter::ACCURACY_VERY_POOR
|
137
|
+
assert_equal 2,m.report_list_of_measures(:filter_below_accuracy=>1).length
|
138
|
+
assert_equal 3,m.report_list_of_measures(:filter_below_accuracy=>Perf::Meter::ACCURACY_UNKNOWN).length
|
140
139
|
assert_equal 3,m.report_list_of_measures(:filter_below_percent=>-10).length
|
141
140
|
end
|
142
141
|
|
@@ -151,8 +150,8 @@ class TestPerfMeter < Test::Unit::TestCase
|
|
151
150
|
m.measure(:c) do
|
152
151
|
sleep(0.0001)
|
153
152
|
end
|
153
|
+
#puts m.report_simple
|
154
154
|
assert_equal 4,m.report_list_of_measures.length
|
155
|
-
assert_equal 3,m.report_list_of_measures(:filter_below_accuracy=>1).length
|
156
155
|
assert_equal 3,m.report_list_of_measures(:filter_below_accuracy=>500).length
|
157
156
|
assert_equal 3,m.report_list_of_measures(:filter_below_percent=>10).length
|
158
157
|
assert_equal 2,m.report_list_of_measures(:filter_below_percent=>45).length
|
@@ -299,13 +298,21 @@ class TestPerfMeter < Test::Unit::TestCase
|
|
299
298
|
'\blocks\some_expressions\expression1 = "1111",1',
|
300
299
|
'\blocks\some_expressions\expression1 = "13579",1',
|
301
300
|
'\blocks\some_expressions\expression2 = "string",1',
|
302
|
-
'\methods,
|
301
|
+
'\methods,4',
|
303
302
|
'\methods\#<Class:PerfTestExample>.static_method,1',
|
304
303
|
'\methods\PerfTestExample.test,1',
|
305
304
|
'\methods\PerfTestExample.test_np,2'],
|
306
305
|
m.report_list_of_measures
|
307
306
|
end
|
308
307
|
|
308
|
+
def test_precision
|
309
|
+
runs=1_000
|
310
|
+
a=(1..100_000).to_a
|
311
|
+
m=Perf::Meter.new
|
312
|
+
runs.times { m.measure(:a) { a.reverse! } }
|
313
|
+
m.measure(:b) { runs.times { a.reverse! } }
|
314
|
+
# TODO find proper assert
|
315
|
+
end
|
309
316
|
|
310
317
|
def test_overhead
|
311
318
|
runs=1_000
|
@@ -319,7 +326,7 @@ class TestPerfMeter < Test::Unit::TestCase
|
|
319
326
|
b2_yes_overhead=Benchmark.measure { runs.times { a.reverse! } }
|
320
327
|
|
321
328
|
|
322
|
-
assert_equal ['\blocks,
|
329
|
+
assert_equal ['\blocks,1000',
|
323
330
|
'\blocks\a,1000'],
|
324
331
|
m_no_overhead.report_list_of_measures
|
325
332
|
|
@@ -338,6 +345,8 @@ class TestPerfMeter < Test::Unit::TestCase
|
|
338
345
|
#puts m_no_overhead.report_simple
|
339
346
|
#puts m_yes_overhead.report_simple
|
340
347
|
#
|
341
|
-
#
|
348
|
+
# puts m_no_overhead.blocks_time
|
349
|
+
# puts m_yes_overhead.blocks_time
|
350
|
+
# assert m_no_overhead.blocks_time.total+m_no_overhead.blocks_time.real <= m_yes_overhead.blocks_time.total+m_no_overhead.blocks_time.real
|
342
351
|
end
|
343
352
|
end
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 3
|
8
|
-
-
|
8
|
+
- 6
|
9
9
|
segments_generated: true
|
10
|
-
version: 1.3.
|
10
|
+
version: 1.3.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- lpasqualis
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-01-
|
18
|
+
date: 2012-01-17 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|