benchmark-trend 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|