benchmark-trend 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +71 -6
- data/examples/fib_constant.rb +16 -0
- data/examples/fib_linear.rb +17 -0
- data/lib/benchmark/trend.rb +53 -12
- data/lib/benchmark/trend/version.rb +1 -1
- data/spec/unit/fit_power_spec.rb +5 -5
- data/spec/unit/infer_trend_spec.rb +33 -16
- data/spec/unit/measure_execution_time_spec.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2684a8a9c5ed41c53e7510602d352dccb111150e7ce757567f3e1340a679eb5f
|
4
|
+
data.tar.gz: 8b7363a4ca90e53557d1a4397e30a5a37a93515976a42773c5225d1715e00ae3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d27391b226536bb79d6dbe5e75ba3d66cf2362993b9d6afcb5409ea2a8a999deef276d7708a6c0bfa9b28eeeaffd9f31d8b2238e9f3daff21e3357baa80397d
|
7
|
+
data.tar.gz: bdae380f8bdaf37432cda9f03820421fb9f7fb00f9633d0c8a9a0b5b575f566ef905f9ec70ab83c4d0eaeb64162c2a43d7fe659722c90576db40ad621a553ed6
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,23 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.2.0] - 2018-09-30
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add ability to measure monotonic time
|
7
|
+
* Add ability to repeat measurements to increase stability of execution times
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
* Change to prefer simpler complexity for similar measurements
|
11
|
+
* Change to use monotonic clock
|
12
|
+
* Change to differentiate linear vs logarithmic complexity for small values
|
13
|
+
* Change to differentiate linear vs constant complexity for small values
|
14
|
+
|
15
|
+
## Fixed
|
16
|
+
* Fix fit_power to correctly calculate slope and intercept
|
17
|
+
|
3
18
|
## [v0.1.0] - 2018-09-08
|
4
19
|
|
5
20
|
* Inital implementation and release
|
6
21
|
|
22
|
+
[v0.2.0]: https://github.com/piotrmurach/benchmark-trend/compare/v0.1.0...v0.2.0
|
7
23
|
[v0.1.0]: https://github.com/piotrmurach/benchmark-trend/compare/v0.1.0
|
data/README.md
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
[coverage]: https://coveralls.io/github/piotrmurach/benchmark-trend?branch=master
|
15
15
|
[inchpages]: http://inch-ci.org/github/piotrmurach/benchmark-trend
|
16
16
|
|
17
|
-
> Measure
|
17
|
+
> Measure performance trends of Ruby code based on the input size distribution.
|
18
18
|
|
19
19
|
**Benchmark::Trend** will help you estimate the computational complexity of Ruby code by running it on inputs increasing in size, measuring their execution times, and then fitting these observations into a model that best predicts how a given Ruby code will scale as a function of growing workload.
|
20
20
|
|
@@ -43,11 +43,14 @@ Or install it yourself as:
|
|
43
43
|
## Contents
|
44
44
|
|
45
45
|
* [1. Usage](#1-usage)
|
46
|
-
* [2. API](#2
|
46
|
+
* [2. API](#2-api)
|
47
47
|
* [2.1 range](#21-range)
|
48
48
|
* [2.2 infer_trend](#22-infer_trend)
|
49
|
+
* [2.2.1 repeat](#221-repeat)
|
49
50
|
* [2.3 fit](#23-fit)
|
50
51
|
* [2.4 fit_at](#24-fit_at)
|
52
|
+
* [3. Examples](#3-examples)
|
53
|
+
* [3.1 Ruby array max](#31-ruby-array-max)
|
51
54
|
|
52
55
|
## 1. Usage
|
53
56
|
|
@@ -59,12 +62,12 @@ def fibonacci(n)
|
|
59
62
|
end
|
60
63
|
```
|
61
64
|
|
62
|
-
To measure the actual complexity of above function, we will use `
|
65
|
+
To measure the actual complexity of above function, we will use `infer_trend` method and pass it as a first argument an array of integer sizes and a block to execute the method:
|
63
66
|
|
64
67
|
```ruby
|
65
68
|
numbers = Benchmark::Trend.range(1, 28, ratio: 2)
|
66
69
|
|
67
|
-
trend, trends = Benchmark::Trend.infer_trend(numbers) do |n|
|
70
|
+
trend, trends = Benchmark::Trend.infer_trend(numbers) do |n, i|
|
68
71
|
fibonacci(n)
|
69
72
|
end
|
70
73
|
```
|
@@ -134,7 +137,7 @@ Benchmark::Trend.range(8, 8 << 10, ratio: 2)
|
|
134
137
|
|
135
138
|
### 2.2 infer_trend
|
136
139
|
|
137
|
-
To calculate an asymptotic behaviour of
|
140
|
+
To calculate an asymptotic behaviour of Ruby code by inferring its computational complexity use `infer_trend`. This method takes as an argument an array of inputs which can be generated using [range](#21-range). The code to measure needs to be provided inside a block. Two parameters are always yielded to a block, first, the actual data input and second the current index matching the input.
|
138
141
|
|
139
142
|
For example, let's assume you would like to find out asymptotic behaviour of a Fibonacci algorithm:
|
140
143
|
|
@@ -154,7 +157,7 @@ numbers = Benchmark::Trend.range(1, 32, ratio: 2)
|
|
154
157
|
Then measure the performance of the Fibonacci algorithm for each of the data points and fit the observations into a model to predict behaviour as a function of input size:
|
155
158
|
|
156
159
|
```ruby
|
157
|
-
trend, trends = Benchmark::Trend.infer_trend(numbers) do |n|
|
160
|
+
trend, trends = Benchmark::Trend.infer_trend(numbers) do |n, i|
|
158
161
|
fibonacci(n)
|
159
162
|
end
|
160
163
|
```
|
@@ -204,6 +207,23 @@ print trends[trend]
|
|
204
207
|
# :residual=>0.9052392775178072}
|
205
208
|
```
|
206
209
|
|
210
|
+
### 2.2.1 repeat
|
211
|
+
|
212
|
+
To increase stability of you tests consider repeating all time execution measurements using `:repeat` keyword.
|
213
|
+
|
214
|
+
Start by generating a range of inputs for your algorithm:
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
numbers = Benchmark::Trend.range(1, 32, ratio: 2)
|
218
|
+
# => [1, 2, 4, 8, 16, 32]
|
219
|
+
```
|
220
|
+
|
221
|
+
and then run your algorithm for each input repeating measurements `100` times:
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
Benchmark::Trend.infer_trend(numbers, repeat: 100) { |n, i| ... }
|
225
|
+
```
|
226
|
+
|
207
227
|
### 2.3 fit
|
208
228
|
|
209
229
|
Use `fit` method if you wish to fit arbitrary data into a model with a slope and intercept parameters that minimize the error.
|
@@ -264,6 +284,51 @@ Benchamrk::Trend.fit_at(:exponential, slope: 1.382889711685203, intercept: 3.822
|
|
264
284
|
|
265
285
|
This means Fibonacci recursive algorithm will take about 1.45 year to complete!
|
266
286
|
|
287
|
+
## 3. Examples
|
288
|
+
|
289
|
+
### 3.1 Ruby array max
|
290
|
+
|
291
|
+
Suppose you wish to find an asymptotic behaviour of Ruby built Array `max` method.
|
292
|
+
|
293
|
+
You could start with generating a [range](#21-range) of inputs:
|
294
|
+
|
295
|
+
```ruby
|
296
|
+
array_sizes = Benchmark::Trend.range(1, 100_000)
|
297
|
+
# => [1, 8, 64, 512, 4096, 32768, 100000]
|
298
|
+
```
|
299
|
+
|
300
|
+
Next, based on the generated ranges create arrays containing randomly generated integers:
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
number_arrays = array_sizes.map { |n| Array.new(n) { rand(n) } }
|
304
|
+
```
|
305
|
+
|
306
|
+
Then feed this information to infer a trend:
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
trend, trends = Benchmark::Trend.infer_trend(array_sizes) do |n, i|
|
310
|
+
number_arrays[i].max
|
311
|
+
end
|
312
|
+
```
|
313
|
+
|
314
|
+
Unsuprisingly, we discover that Ruby's `max` call scales linearily with the input size:
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
print trend
|
318
|
+
# => linear
|
319
|
+
```
|
320
|
+
|
321
|
+
We can also see from the residual value that this is a near perfect fit:
|
322
|
+
|
323
|
+
```ruby
|
324
|
+
print trends[trend]
|
325
|
+
# =>
|
326
|
+
# {:trend=>"0.00 + 0.00*x",
|
327
|
+
# :slope=>5.873536409841244e-09,
|
328
|
+
# :intercept=>3.028647045635842e-05,
|
329
|
+
# :residual=>0.9986764704492359}
|
330
|
+
```
|
331
|
+
|
267
332
|
## Development
|
268
333
|
|
269
334
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative '../lib/benchmark-trend'
|
2
|
+
|
3
|
+
# constant
|
4
|
+
def fib_const(n)
|
5
|
+
phi = (1 + Math.sqrt(5))/2
|
6
|
+
(phi ** n / Math.sqrt(5)).round
|
7
|
+
end
|
8
|
+
|
9
|
+
numbers = Benchmark::Trend.range(1, 1400, ratio: 2)
|
10
|
+
trend, trends = Benchmark::Trend.infer_trend(numbers, repeat: 100) do |n|
|
11
|
+
fib_const(n)
|
12
|
+
end
|
13
|
+
|
14
|
+
puts "Trend: #{trend}"
|
15
|
+
puts "Trend data:"
|
16
|
+
pp trends
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative '../lib/benchmark-trend'
|
2
|
+
|
3
|
+
# linear
|
4
|
+
def fib_iter(n)
|
5
|
+
a, b = 0, 1
|
6
|
+
n.times { a, b = b, a + b}
|
7
|
+
a
|
8
|
+
end
|
9
|
+
|
10
|
+
numbers = Benchmark::Trend.range(1, 20_000)
|
11
|
+
trend, trends = Benchmark::Trend.infer_trend(numbers) do |n|
|
12
|
+
fib_iter(n)
|
13
|
+
end
|
14
|
+
|
15
|
+
puts "Trend: #{trend}"
|
16
|
+
puts "Trend data:"
|
17
|
+
pp trends
|
data/lib/benchmark/trend.rb
CHANGED
@@ -14,6 +14,31 @@ module Benchmark
|
|
14
14
|
private_class_method(method)
|
15
15
|
end
|
16
16
|
|
17
|
+
if defined?(Process::CLOCK_MONOTONIC)
|
18
|
+
# Object representing current time
|
19
|
+
def time_now
|
20
|
+
Process.clock_gettime Process::CLOCK_MONOTONIC
|
21
|
+
end
|
22
|
+
module_function :time_now
|
23
|
+
else
|
24
|
+
# Object represeting current time
|
25
|
+
def time_now
|
26
|
+
Time.now
|
27
|
+
end
|
28
|
+
module_function :time_now
|
29
|
+
end
|
30
|
+
|
31
|
+
# Measure time elapsed with a monotonic clock
|
32
|
+
#
|
33
|
+
# @public
|
34
|
+
def clock_time
|
35
|
+
before = time_now
|
36
|
+
yield
|
37
|
+
after = time_now
|
38
|
+
after - before
|
39
|
+
end
|
40
|
+
module_function :clock_time
|
41
|
+
|
17
42
|
# Generate a range of inputs spaced by powers.
|
18
43
|
#
|
19
44
|
# The default range is generated in the multiples of 8.
|
@@ -66,18 +91,25 @@ module Benchmark
|
|
66
91
|
# @param [Array[Numeric]] data
|
67
92
|
# the data to run measurements for
|
68
93
|
#
|
94
|
+
# @param [Integer] repeat
|
95
|
+
# nubmer of times work is called to compute execution time
|
96
|
+
#
|
69
97
|
# @return [Array[Array, Array]]
|
70
98
|
#
|
71
99
|
# @api public
|
72
|
-
def measure_execution_time(data = nil, &work)
|
100
|
+
def measure_execution_time(data = nil, repeat: 1, &work)
|
73
101
|
inputs = data || range(1, 10_000)
|
74
102
|
times = []
|
75
103
|
|
76
|
-
inputs.
|
104
|
+
inputs.each_with_index do |input, i|
|
77
105
|
GC.start
|
78
|
-
|
79
|
-
|
106
|
+
measurements = []
|
107
|
+
|
108
|
+
repeat.times do
|
109
|
+
measurements << clock_time { work.(input, i) }
|
80
110
|
end
|
111
|
+
|
112
|
+
times << measurements.reduce(&:+).to_f / measurements.size
|
81
113
|
end
|
82
114
|
[inputs, times]
|
83
115
|
end
|
@@ -126,7 +158,7 @@ module Benchmark
|
|
126
158
|
|
127
159
|
# Finds a line of best fit that approxmimates power function
|
128
160
|
#
|
129
|
-
# Function form: y =
|
161
|
+
# Function form: y = bx^a
|
130
162
|
#
|
131
163
|
# @return [Numeric, Numeric, Numeric]
|
132
164
|
# returns a, b, and rr values
|
@@ -136,7 +168,7 @@ module Benchmark
|
|
136
168
|
a, b, rr = fit(xs, ys, tran_x: ->(x) { Math.log(x) },
|
137
169
|
tran_y: ->(y) { Math.log(y) })
|
138
170
|
|
139
|
-
[Math.exp(b),
|
171
|
+
[a, Math.exp(b), rr]
|
140
172
|
end
|
141
173
|
module_function :fit_power
|
142
174
|
|
@@ -172,7 +204,7 @@ module Benchmark
|
|
172
204
|
#
|
173
205
|
# @api public
|
174
206
|
def fit(xs, ys, tran_x: ->(x) { x }, tran_y: ->(y) { y })
|
175
|
-
eps =
|
207
|
+
eps = (10 ** -10)
|
176
208
|
n = 0
|
177
209
|
sum_x = 0.0
|
178
210
|
sum_x2 = 0.0
|
@@ -193,9 +225,11 @@ module Benchmark
|
|
193
225
|
tx = n * sum_x2 - sum_x ** 2
|
194
226
|
ty = n * sum_y2 - sum_y ** 2
|
195
227
|
|
228
|
+
is_linear = tran_x.(Math::E) * tran_y.(Math::E) == Math::E ** 2
|
229
|
+
|
196
230
|
if tx.abs < eps # no variation in xs
|
197
231
|
raise ArgumentError, "No variation in data #{xs}"
|
198
|
-
elsif ty.abs < eps # no variation in ys - constant fit
|
232
|
+
elsif ty.abs < eps && is_linear # no variation in ys - constant fit
|
199
233
|
slope = 0
|
200
234
|
intercept = sum_y / n
|
201
235
|
residual_sq = 1 # doesn't exist
|
@@ -249,7 +283,7 @@ module Benchmark
|
|
249
283
|
case type
|
250
284
|
when :logarithmic, :log
|
251
285
|
"%.2f + %.2f*ln(x)"
|
252
|
-
when :linear
|
286
|
+
when :linear, :constant
|
253
287
|
"%.2f + %.2f*x"
|
254
288
|
when :power
|
255
289
|
"%.2f * x^%.2f"
|
@@ -268,14 +302,18 @@ module Benchmark
|
|
268
302
|
#
|
269
303
|
# Fits the executiom times for each range to several fit models.
|
270
304
|
#
|
305
|
+
# @param [Integer] repeat
|
306
|
+
# nubmer of times work is called to compute execution time
|
307
|
+
#
|
271
308
|
# @yieldparam work
|
309
|
+
# the block of which the complexity is measured
|
272
310
|
#
|
273
311
|
# @return [Array[Symbol, Hash]]
|
274
312
|
# the best fitting and all the trends
|
275
313
|
#
|
276
314
|
# @api public
|
277
|
-
def infer_trend(data, &work)
|
278
|
-
ns, times = *measure_execution_time(data, &work)
|
315
|
+
def infer_trend(data, repeat: 1, &work)
|
316
|
+
ns, times = *measure_execution_time(data, repeat: repeat, &work)
|
279
317
|
best_fit = :none
|
280
318
|
best_residual = 0
|
281
319
|
fitted = {}
|
@@ -287,9 +325,12 @@ module Benchmark
|
|
287
325
|
a, b, rr = *send(:"fit_#{fit}", ns, times)
|
288
326
|
# goodness of model
|
289
327
|
aic = n * (Math.log(Math::PI) + 1) + n * Math.log(rr / n)
|
328
|
+
if a == 0 && fit == :linear
|
329
|
+
fit = :constant
|
330
|
+
end
|
290
331
|
fitted[fit] = { trend: format_fit(fit) % [a, b],
|
291
332
|
slope: a, intercept: b, residual: rr }
|
292
|
-
if rr
|
333
|
+
if rr >= best_residual && aic >= best_aic
|
293
334
|
best_residual = rr
|
294
335
|
best_fit = fit
|
295
336
|
best_aic = aic
|
data/spec/unit/fit_power_spec.rb
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
RSpec.describe Benchmark::Trend, '#fit_power' do
|
4
4
|
it 'calculates perfect power fit' do
|
5
5
|
xs = [1, 2, 3, 4, 5]
|
6
|
-
ys = xs.map { |x| 1.5*(x ** 2) }
|
6
|
+
ys = xs.map { |x| 1.5 * (x ** 2) }
|
7
7
|
|
8
8
|
a, b, rr = Benchmark::Trend.fit_power(xs, ys)
|
9
9
|
|
10
|
-
expect(a).to be_within(0.001).of(
|
11
|
-
expect(b).to be_within(0.001).of(
|
10
|
+
expect(a).to be_within(0.001).of(2.0)
|
11
|
+
expect(b).to be_within(0.001).of(1.5)
|
12
12
|
expect(rr).to be_within(0.001).of(1.0)
|
13
13
|
end
|
14
14
|
|
@@ -19,8 +19,8 @@ RSpec.describe Benchmark::Trend, '#fit_power' do
|
|
19
19
|
|
20
20
|
a, b, rr = Benchmark::Trend.fit_power(xs, ys)
|
21
21
|
|
22
|
-
expect(a).to be_within(0.001).of(1.
|
23
|
-
expect(b).to be_within(0.001).of(1.
|
22
|
+
expect(a).to be_within(0.001).of(1.5)
|
23
|
+
expect(b).to be_within(0.001).of(1.0)
|
24
24
|
expect(rr).to be_within(0.001).of(0.999)
|
25
25
|
end
|
26
26
|
end
|
@@ -23,15 +23,23 @@ RSpec.describe Benchmark::Trend, '#infer_trend' do
|
|
23
23
|
a
|
24
24
|
end
|
25
25
|
|
26
|
-
#
|
26
|
+
# logarithmic
|
27
27
|
def fib_const(n)
|
28
28
|
phi = (1 + Math.sqrt(5))/2
|
29
29
|
(phi ** n / Math.sqrt(5)).round
|
30
30
|
end
|
31
31
|
|
32
|
+
it "infers constant trend" do
|
33
|
+
numbers = Benchmark::Trend.range(1, 100_000)
|
34
|
+
trend, = Benchmark::Trend.infer_trend(numbers, repeat: 100) do |n|
|
35
|
+
n
|
36
|
+
end
|
37
|
+
|
38
|
+
expect(trend).to eq(:constant)
|
39
|
+
end
|
40
|
+
|
32
41
|
it "infers fibonacci classic algorithm trend to be exponential" do
|
33
|
-
|
34
|
-
trend, trends = Benchmark::Trend.infer_trend(numbers) do |n|
|
42
|
+
trend, trends = Benchmark::Trend.infer_trend((1..20), repeat: 10) do |n|
|
35
43
|
fibonacci(n)
|
36
44
|
end
|
37
45
|
|
@@ -52,29 +60,38 @@ RSpec.describe Benchmark::Trend, '#infer_trend' do
|
|
52
60
|
expect(trend).to eq(:linear)
|
53
61
|
end
|
54
62
|
|
55
|
-
it "infers fibonacci constant algorithm trend to be
|
56
|
-
|
57
|
-
|
63
|
+
it "infers fibonacci constant algorithm trend to be constant" do
|
64
|
+
# exponetiation by squaring has logarithmic complexity
|
65
|
+
numbers = Benchmark::Trend.range(1, 1400, ratio: 2)
|
66
|
+
trend, trends = Benchmark::Trend.infer_trend(numbers, repeat: 100) do |n|
|
58
67
|
fib_const(n)
|
59
68
|
end
|
60
69
|
|
61
|
-
expect(trend).to eq(:
|
62
|
-
expect(trends[trend][:slope]).to
|
70
|
+
expect(trend).to eq(:constant)
|
71
|
+
expect(trends[trend][:slope]).to be_within(0.0001).of(0)
|
63
72
|
end
|
64
73
|
|
65
74
|
it "infers finding maximum value trend to be linear" do
|
66
75
|
array_sizes = Benchmark::Trend.range(1, 100_000)
|
67
|
-
|
76
|
+
numbers = array_sizes.map { |n| Array.new(n) { rand(n) } }
|
68
77
|
|
69
|
-
trend, trends = Benchmark::Trend.infer_trend(array_sizes) do
|
70
|
-
|
78
|
+
trend, trends = Benchmark::Trend.infer_trend(array_sizes, repeat: 10) do |n, i|
|
79
|
+
numbers[i].max
|
71
80
|
end
|
72
81
|
|
73
82
|
expect(trend).to eq(:linear)
|
74
|
-
expect(trends).to
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
)
|
83
|
+
expect(trends[trend][:slope]).to be_within(0.0001).of(0)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "infers binary search trend to be constant" do
|
87
|
+
range = Benchmark::Trend.range(10, 8 << 10, ratio: 2)
|
88
|
+
numbers = range.reduce([]) { |acc, n| acc << (1..n).to_a; acc }
|
89
|
+
|
90
|
+
trend, trends = Benchmark::Trend.infer_trend(range, repeat: 100) do |n, i|
|
91
|
+
numbers[i].bsearch { |x| x == n/2 }
|
92
|
+
end
|
93
|
+
|
94
|
+
expect(trend).to eq(:constant)
|
95
|
+
expect(trends[trend][:slope]).to be_within(0.0001).of(0)
|
79
96
|
end
|
80
97
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: benchmark-trend
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -70,6 +70,8 @@ files:
|
|
70
70
|
- benchmark-trend.gemspec
|
71
71
|
- bin/console
|
72
72
|
- bin/setup
|
73
|
+
- examples/fib_constant.rb
|
74
|
+
- examples/fib_linear.rb
|
73
75
|
- exe/bench-trend
|
74
76
|
- lib/benchmark-trend.rb
|
75
77
|
- lib/benchmark/trend.rb
|