micro_bench 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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