micro_bench 0.1.1
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 +7 -0
- data/README.md +102 -0
- data/lib/micro_bench/benchmark.rb +31 -0
- data/lib/micro_bench/version.rb +3 -0
- data/lib/micro_bench.rb +70 -0
- data/spec/micro_bench/micro_bench_spec.rb +67 -0
- data/spec/spec_helper.rb +9 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4b772118be3419e0878ddf0f0cec08a83c67eefb
|
4
|
+
data.tar.gz: 1e08246f863d68db6434eeeb60ffd6bd8e04bc61
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cc8cc8b61b6324d3fbb5a0e6d430b1dfbe057f7e23d802b4bf1094cb74795e49cf59461a9ed9431c96a17001d22383b8789079e2238c687e46437058f0914615
|
7
|
+
data.tar.gz: 1f6c2876766fec38271ef0245a9e9af48ee5fe5585e73435b2259dd70a0a8b752dfe439e7b28fcc6d560326bbe9337281f57825b89b547288f85b07dd5a6f9ca
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
|
2
|
+
# MicroBench
|
3
|
+
|
4
|
+
[](https://badge.fury.io/rb/micro_bench)
|
5
|
+
|
6
|
+
Ruby `Benchmark` module is nice but it uses blocks. We see 2 problems to it :
|
7
|
+
- if we want to instrument a snippet of code, it breaks git history,
|
8
|
+
- variables are tied to the benchmark block, so we have to initialize them outside of the benchmark block to use them subsequently.
|
9
|
+
|
10
|
+
Let's say you want to output the duration of `method_1` from :
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
foo = method_1
|
14
|
+
method_2(foo)
|
15
|
+
```
|
16
|
+
|
17
|
+
With `Benchmark`, we would write something like :
|
18
|
+
```ruby
|
19
|
+
foo = nil
|
20
|
+
duration = Benchmark.realtime do
|
21
|
+
foo = method_1
|
22
|
+
end
|
23
|
+
puts "Method 1 duration : #{duration} seconds"
|
24
|
+
method_2(foo)
|
25
|
+
```
|
26
|
+
|
27
|
+
With `MicroBench`, it will look like this :
|
28
|
+
```ruby
|
29
|
+
MicroBench.start
|
30
|
+
foo = method_1
|
31
|
+
puts "Method 1 duration : #{MicroBench.duration} seconds"
|
32
|
+
method_2(foo)
|
33
|
+
```
|
34
|
+
|
35
|
+
## Install
|
36
|
+
|
37
|
+
```
|
38
|
+
gem install micro_bench
|
39
|
+
```
|
40
|
+
|
41
|
+
or in Bundler:
|
42
|
+
```ruby
|
43
|
+
gem "micro_bench"
|
44
|
+
```
|
45
|
+
|
46
|
+
## Usage
|
47
|
+
|
48
|
+
### Basic usage
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
require "micro_bench"
|
52
|
+
|
53
|
+
MicroBench.start
|
54
|
+
|
55
|
+
MicroBench.duration
|
56
|
+
# 1.628093000501394
|
57
|
+
|
58
|
+
MicroBench.duration
|
59
|
+
# 2.999483000487089
|
60
|
+
|
61
|
+
MicroBench.stop
|
62
|
+
# true
|
63
|
+
|
64
|
+
MicroBench.duration
|
65
|
+
# 5.4341670004651
|
66
|
+
|
67
|
+
MicroBench.duration
|
68
|
+
# 5.4341670004651
|
69
|
+
```
|
70
|
+
|
71
|
+
### Named benchmarks
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
require "micro_bench"
|
75
|
+
|
76
|
+
MicroBench.start("timer1")
|
77
|
+
|
78
|
+
MicroBench.stop("timer1")
|
79
|
+
|
80
|
+
MicroBench.duration("timer1")
|
81
|
+
# 1.628093000501394
|
82
|
+
```
|
83
|
+
|
84
|
+
### Thread safety
|
85
|
+
|
86
|
+
A benchmark is tied to a thread, ensuring that `MicroBench` is thread-safe. At the same time, it doesn't allow to share a benchmark between multiple threads.
|
87
|
+
|
88
|
+
### Multiple starts
|
89
|
+
|
90
|
+
Calling `.start` multiple times with the same `bench_id` will cause a "restart" of the given benchmark.
|
91
|
+
|
92
|
+
## Versioning
|
93
|
+
|
94
|
+
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/klaxit/micro_bench/tags).
|
95
|
+
|
96
|
+
## Authors
|
97
|
+
|
98
|
+
See the list of [contributors](https://github.com/klaxit/micro_bench/contributors) who participated in this project.
|
99
|
+
|
100
|
+
## License
|
101
|
+
|
102
|
+
Please see LICENSE
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class MicroBench::Benchmark
|
2
|
+
def initialize
|
3
|
+
@start_time = monotonic_clock_time
|
4
|
+
end
|
5
|
+
|
6
|
+
def stop
|
7
|
+
return false unless running?
|
8
|
+
|
9
|
+
@duration = monotonic_clock_time - @start_time
|
10
|
+
|
11
|
+
return true
|
12
|
+
end
|
13
|
+
|
14
|
+
def duration
|
15
|
+
@duration || (monotonic_clock_time - @start_time)
|
16
|
+
end
|
17
|
+
|
18
|
+
def running?
|
19
|
+
@duration.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
duration.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def monotonic_clock_time
|
29
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
30
|
+
end
|
31
|
+
end
|
data/lib/micro_bench.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
module MicroBench
|
2
|
+
class << self
|
3
|
+
# Start a benchmark
|
4
|
+
#
|
5
|
+
# == Parameters:
|
6
|
+
# bench_id::
|
7
|
+
# Identifier of the benchmark
|
8
|
+
#
|
9
|
+
# == Returns:
|
10
|
+
# A boolean representing success
|
11
|
+
#
|
12
|
+
# == Example usage:
|
13
|
+
# MicroBench.start(:my_benchmark)
|
14
|
+
#
|
15
|
+
# Calling the method multiple times with the same bench_id will restart
|
16
|
+
# the benchmark for the given bench_id.
|
17
|
+
#
|
18
|
+
def start(bench_id = nil)
|
19
|
+
benchmarks[benchmark_key(bench_id)] = MicroBench::Benchmark.new
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
|
23
|
+
# Stop a benchmark
|
24
|
+
#
|
25
|
+
# == Parameters:
|
26
|
+
# bench_id::
|
27
|
+
# Identifier of the benchmark
|
28
|
+
#
|
29
|
+
# == Returns:
|
30
|
+
# A boolean representing success
|
31
|
+
#
|
32
|
+
# == Example usage:
|
33
|
+
# MicroBench.stop(:my_benchmark)
|
34
|
+
#
|
35
|
+
def stop(bench_id = nil)
|
36
|
+
key = benchmark_key(bench_id)
|
37
|
+
return false unless benchmarks.key?(key)
|
38
|
+
|
39
|
+
benchmarks[key].stop
|
40
|
+
end
|
41
|
+
|
42
|
+
# Give duration of the benchmark
|
43
|
+
#
|
44
|
+
# == Parameters:
|
45
|
+
# bench_id::
|
46
|
+
# Identifier of the benchmark
|
47
|
+
#
|
48
|
+
# == Returns:
|
49
|
+
# Duration of the given benchmark, or nil if benchmark is unknown
|
50
|
+
#
|
51
|
+
# == Example usage:
|
52
|
+
# MicroBench.stop(:my_benchmark)
|
53
|
+
#
|
54
|
+
def duration(bench_id = nil)
|
55
|
+
benchmarks[benchmark_key(bench_id)]&.duration
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def benchmarks
|
61
|
+
@benchmarks ||= {}
|
62
|
+
end
|
63
|
+
|
64
|
+
def benchmark_key(bench_id = nil)
|
65
|
+
"#{Thread.current.object_id}||#{bench_id}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
require "micro_bench/benchmark"
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe MicroBench do
|
4
|
+
it "gives seconds duration doing something" do
|
5
|
+
described_class.start
|
6
|
+
sleep(0.01)
|
7
|
+
expect(
|
8
|
+
described_class.duration.round(2)
|
9
|
+
).to eq(0.01)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "allows to stop benchmark" do
|
13
|
+
described_class.start
|
14
|
+
sleep(0.01)
|
15
|
+
described_class.stop
|
16
|
+
sleep(0.02)
|
17
|
+
expect(
|
18
|
+
described_class.duration.round(2)
|
19
|
+
).to eq(0.01)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "restart each time 'start' is called" do
|
23
|
+
described_class.start
|
24
|
+
sleep(0.02)
|
25
|
+
described_class.start
|
26
|
+
sleep(0.01)
|
27
|
+
expect(
|
28
|
+
described_class.duration.round(2)
|
29
|
+
).to eq(0.01)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "allows multiple parallel named benchmarks" do
|
33
|
+
described_class.start(:bench1)
|
34
|
+
described_class.start(:bench2)
|
35
|
+
sleep(0.01)
|
36
|
+
described_class.stop(:bench1)
|
37
|
+
sleep(0.01)
|
38
|
+
described_class.stop(:bench2)
|
39
|
+
expect(
|
40
|
+
described_class.duration(:bench1).round(2)
|
41
|
+
).to eq(0.01)
|
42
|
+
expect(
|
43
|
+
described_class.duration(:bench2).round(2)
|
44
|
+
).to eq(0.01 * 2)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "is thread safe" do
|
48
|
+
t1 = Thread.new do
|
49
|
+
described_class.start
|
50
|
+
sleep(0.01)
|
51
|
+
described_class.stop
|
52
|
+
Thread.current[:expected] = 0.01
|
53
|
+
Thread.current[:duration] = described_class.duration
|
54
|
+
end
|
55
|
+
t2 = Thread.new do
|
56
|
+
described_class.start
|
57
|
+
sleep(0.01 * 2)
|
58
|
+
described_class.stop
|
59
|
+
Thread.current[:expected] = 0.01 * 2
|
60
|
+
Thread.current[:duration] = described_class.duration
|
61
|
+
end
|
62
|
+
[t1, t2].each do |t|
|
63
|
+
t.join
|
64
|
+
expect(t[:duration].round(2)).to eq(t[:expected])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: micro_bench
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cyrille Courtière
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-11-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: byebug
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '9.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '9.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.8'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.8'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- cyrille@klaxit.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- README.md
|
49
|
+
- lib/micro_bench.rb
|
50
|
+
- lib/micro_bench/benchmark.rb
|
51
|
+
- lib/micro_bench/version.rb
|
52
|
+
- spec/micro_bench/micro_bench_spec.rb
|
53
|
+
- spec/spec_helper.rb
|
54
|
+
homepage: http://github.com/klaxit/micro_bench
|
55
|
+
licenses:
|
56
|
+
- MIT
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.5.2.3
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Dead simple benchmarks
|
78
|
+
test_files:
|
79
|
+
- spec/micro_bench/micro_bench_spec.rb
|
80
|
+
- spec/spec_helper.rb
|