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 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
+ [![Gem Version](https://badge.fury.io/rb/micro_bench.svg)](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
@@ -0,0 +1,3 @@
1
+ module MicroBench
2
+ VERSION = "0.1.1".freeze
3
+ end
@@ -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
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift File.join(__dir__, "..", "lib")
2
+
3
+ require "bundler/setup"
4
+ require "byebug"
5
+ require "micro_bench"
6
+
7
+ RSpec.configure do |config|
8
+ # Config goes here
9
+ end
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