d_heap 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,32 +0,0 @@
1
- ---
2
- prelude: |
3
- system("#{RbConfig.ruby} bin/rake compile", err: :out, exception: true)
4
- require "d_heap/benchmarks"
5
- include DHeap::Benchmarks
6
- fill_random_vals
7
-
8
- n = ENV.fetch("BENCH_N", 1000).to_i
9
-
10
- benchmark:
11
- - script: &script |
12
- q << random_val
13
- q.pop
14
- name: "push + pop (findmin)"
15
- prelude: "q = FindMin.new(n) { random_val }"
16
- loop_count: 250000
17
- - script: *script
18
- name: "push + pop (bsearch)"
19
- prelude: "q = BSearch.new(n) { random_val }"
20
- loop_count: 5000000
21
- - script: *script
22
- name: "push + pop (rb_heap)"
23
- prelude: "q = RbHeap.new(n) { random_val }"
24
- loop_count: 2000000
25
- - script: *script
26
- name: "push + pop (c++ stl)"
27
- prelude: "q = initq CppSTL, n"
28
- loop_count: 13000000
29
- - script: *script
30
- name: "push + pop (c_dheap)"
31
- prelude: "q = initq DHeap, n"
32
- loop_count: 20000000
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "stackprof"
5
-
6
- system("#{RbConfig.ruby} bin/rake compile", err: :out, exception: true)
7
- require "d_heap/benchmarks"
8
- include DHeap::Benchmarks # rubocop:disable Style/MixinUsage
9
- fill_random_vals
10
-
11
- n = ENV.fetch("BENCH_N", 5_000_000).to_i
12
- interval = ENV.fetch("PROF_INTERVAL", 100).to_i # measured in μs
13
-
14
- i = 0
15
-
16
- q = initq RbHeap
17
- n.times { q << n }
18
- q.clear
19
-
20
- StackProf.run(mode: :cpu, out: "stackprof-cpu-push.dump", interval: interval) do
21
- while i < n
22
- q << random_val
23
- i += 1
24
- end
25
- end
26
- StackProf.run(mode: :cpu, out: "stackprof-cpu-pop.dump", interval: interval) do
27
- while 0 < i # rubocop:disable Style/NumericPredicate
28
- q.pop
29
- i -= 1
30
- end
31
- end
data/bin/bench_charts DELETED
@@ -1,13 +0,0 @@
1
- #!/bin/bash
2
- set -eu
3
- SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null; pwd -P)
4
- PROJECT_DIR=$(cd "$SCRIPT_DIR" > /dev/null; cd .. > /dev/null; pwd -P)
5
- cd "$PROJECT_DIR"
6
-
7
- opts=( --bundle -e 'N 100000;N 10000;N 1000;N 100;N 10' -o gruff )
8
-
9
- for bm in push_n push_n_pop_n push_pop; do
10
- bin/benchmark-driver "${opts[@]}" "benchmarks/${bm}.yml"
11
- mv graph.png "images/${bm}.png"
12
- done
13
-
data/bin/bench_n DELETED
@@ -1,7 +0,0 @@
1
- #!/bin/sh
2
- set -eu
3
-
4
- export BENCH_N="$1"
5
- shift
6
-
7
- exec ruby "$@"
data/bin/benchmark-driver DELETED
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'benchmark-driver' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- require "pathname"
12
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
- Pathname.new(__FILE__).realpath)
14
-
15
- bundle_binstub = File.expand_path("../bundle", __FILE__)
16
-
17
- if File.file?(bundle_binstub)
18
- if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
- load(bundle_binstub)
20
- else
21
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
- end
24
- end
25
-
26
- require "rubygems"
27
- require "bundler/setup"
28
-
29
- load Gem.bin_path("benchmark_driver", "benchmark-driver")
data/bin/benchmarks DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "pathname"
5
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
6
- require "rubygems"
7
- require "bundler/setup"
8
-
9
- require "d_heap/benchmarks/benchmarker"
10
- DHeap::Benchmarks::Benchmarker.new.call
data/bin/console DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "d_heap"
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
- require "irb"
15
- IRB.start(__FILE__)
data/bin/profile DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "pathname"
5
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
6
- require "rubygems"
7
- require "bundler/setup"
8
-
9
- require "d_heap/benchmarks/profiler"
10
- DHeap::Benchmarks::Profiler.new.call
data/bin/rake DELETED
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rake' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- require "pathname"
12
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
- Pathname.new(__FILE__).realpath)
14
-
15
- bundle_binstub = File.expand_path("../bundle", __FILE__)
16
-
17
- if File.file?(bundle_binstub)
18
- if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
- load(bundle_binstub)
20
- else
21
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
- end
24
- end
25
-
26
- require "rubygems"
27
- require "bundler/setup"
28
-
29
- load Gem.bin_path("rake", "rake")
data/bin/rspec DELETED
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rspec' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- require "pathname"
12
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
- Pathname.new(__FILE__).realpath)
14
-
15
- bundle_binstub = File.expand_path("../bundle", __FILE__)
16
-
17
- if File.file?(bundle_binstub)
18
- if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
- load(bundle_binstub)
20
- else
21
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
- end
24
- end
25
-
26
- require "rubygems"
27
- require "bundler/setup"
28
-
29
- load Gem.bin_path("rspec-core", "rspec")
data/bin/rubocop DELETED
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rubocop' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- require "pathname"
12
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
- Pathname.new(__FILE__).realpath)
14
-
15
- bundle_binstub = File.expand_path("../bundle", __FILE__)
16
-
17
- if File.file?(bundle_binstub)
18
- if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
- load(bundle_binstub)
20
- else
21
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
- end
24
- end
25
-
26
- require "rubygems"
27
- require "bundler/setup"
28
-
29
- load Gem.bin_path("rubocop", "rubocop")
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
@@ -1,158 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "English" # $CHILD_STATUS
4
- require "timeout" # Timeout::Error
5
-
6
- require "benchmark_driver"
7
-
8
- # monkey-patch to convert miniscule values to 0.0
9
- class BenchmarkDriver::Output::Compare
10
-
11
- # monkey-patch to convert miniscule values to 0.0
12
- module MinisculeToZero
13
-
14
- def humanize(value, width = 10)
15
- value <= 0.0.next_float.next_float ? 0.0 : super(value, width)
16
- end
17
-
18
- end
19
-
20
- prepend MinisculeToZero
21
-
22
- end
23
-
24
- # A simple patch to let slow specs error out without
25
- class BenchmarkDriver::Runner::IpsZeroFail < BenchmarkDriver::Runner::Ips
26
- METRIC = BenchmarkDriver::Runner::Ips::METRIC
27
-
28
- # always run at least once
29
- class Job < BenchmarkDriver::DefaultJob
30
- attr_accessor :warmup_value, :warmup_duration, :warmup_loop_count
31
-
32
- def add_warmup_attrs(value, duration, loop_count)
33
- self.warmup_value = value
34
- self.warmup_duration = duration
35
- self.warmup_loop_count = loop_count
36
- end
37
-
38
- end
39
-
40
- # BenchmarkDriver::Runner looks for this class
41
- JobParser = BenchmarkDriver::DefaultJobParser.for(klass: Job, metrics: [METRIC])
42
-
43
- # This method is dynamically called by `BenchmarkDriver::JobRunner.run`
44
- # @param [Array<BenchmarkDriver::Default::Job>] jobs
45
- def run(jobs)
46
- jobs = run_all_jobs_warmup(jobs)
47
- run_all_jobs_benchmarks(jobs)
48
- end
49
-
50
- def run_all_jobs_warmup(jobs)
51
- return jobs if jobs.all?(&:loop_count)
52
- @output.with_warmup do
53
- jobs.map! {|job|
54
- # skip warmup if loop_count is set
55
- job.loop_count ? job : output_warmup_and_config_job(job)
56
- }
57
- end
58
- end
59
-
60
- def run_all_jobs_benchmarks(jobs)
61
- @output.with_benchmark do
62
- jobs.each do |job|
63
- @output.with_job(name: job.name) do
64
- job.runnable_contexts(@contexts).each do |context|
65
- run_and_report_job(job, context)
66
- end
67
- end
68
- end
69
- end
70
- end
71
-
72
- def output_warmup_and_config_job(job)
73
- @output.with_job(name: job.name) do
74
- context = job.runnable_contexts(@contexts).first
75
- value, duration, warmup_loop_count = run_and_report_warmup_job(job, context)
76
- loop_count = (warmup_loop_count.to_f * @config.run_duration / duration).floor
77
- Job.new(**job.to_h.merge(loop_count: loop_count))
78
- .tap {|j| j.add_warmup_attrs(value, duration, warmup_loop_count) }
79
- end
80
- end
81
-
82
- def run_and_report_warmup_job(job, context)
83
- duration, loop_count = run_warmup(job, context: context)
84
- value, duration = value_duration(duration: duration, loop_count: loop_count)
85
- output_with_context(context) do
86
- @output.report(
87
- values: {metric => value}, duration: duration, loop_count: loop_count
88
- )
89
- end
90
- [value, duration, loop_count]
91
- end
92
-
93
- def run_and_report_job(job, context)
94
- result, loop_count = run_job_with_repeater(job, context)
95
- value, duration = result.value
96
- output_with_context(context) do
97
- @output.report(
98
- values: { metric => value },
99
- all_values: { metric => result.all_values },
100
- duration: duration,
101
- loop_count: loop_count,
102
- )
103
- end
104
- end
105
-
106
- def output_with_context(context, &block)
107
- @output.with_context(
108
- name: context.name,
109
- executable: context.executable,
110
- gems: context.gems,
111
- prelude: context.prelude,
112
- &block
113
- )
114
- end
115
-
116
- def run_job_with_repeater(job, context)
117
- repeat_params = { config: @config, larger_better: true, rest_on_average: :average }
118
- if job.loop_count&.positive?
119
- run_job_with_own_loop_count(job, context, repeat_params)
120
- else
121
- run_job_with_warmup_loop_count(job, context, repeat_params)
122
- end
123
- end
124
-
125
- def run_job_with_own_loop_count(job, context, repeat_params)
126
- loop_count = job.loop_count
127
- result = BenchmarkDriver::Repeater.with_repeat(**repeat_params) {
128
- run_benchmark(job, context: context)
129
- }
130
- [result, loop_count]
131
- end
132
-
133
- def run_job_with_warmup_loop_count(job, context, repeat_params)
134
- loop_count = job.warmup_loop_count
135
- repeater_value = [job.warmup_value, job.warmup_duration]
136
- result = BenchmarkDriver::Repeater::RepeatResult.new(
137
- value: repeater_value, all_values: [repeater_value]
138
- )
139
- [result, loop_count]
140
- end
141
-
142
- def run_warmup(job, context:)
143
- start = Time.now
144
- super(job, context: context)
145
- rescue Timeout::Error
146
- [Time.now - start, 0.0.next_float]
147
- end
148
-
149
- def execute(*args, exception: true)
150
- super
151
- rescue RuntimeError => ex
152
- if args.include?("timeout") && $CHILD_STATUS&.exitstatus == 124
153
- raise Timeout::Error, ex.message
154
- end
155
- raise ex
156
- end
157
-
158
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "d_heap"
4
- require "ostruct"
5
-
6
- # Different benchmark scenarios and implementations to benchmark
7
- module DHeap::Benchmarks
8
-
9
- def self.puts_version_info(type = "Benchmark", io = $stdout)
10
- io.puts "#{type} run at %s" % [Time.now]
11
- io.puts "ruby v%s, DHeap v%s" % [RUBY_VERSION, DHeap::VERSION]
12
- io.puts
13
- end
14
-
15
- # rubocop:disable Style/NumericPredicate
16
-
17
- # moves "rand" outside the benchmarked code, to avoid measuring that too.
18
- module Randomness
19
-
20
- def default_randomness_size; 1_000_000 end
21
-
22
- def fill_random_vals(target_size = default_randomness_size, io: $stdout)
23
- @dheap_bm_random_vals ||= []
24
- count = target_size - @dheap_bm_random_vals.length
25
- return 0 if count <= 0
26
- millions = (count / 1_000_000.0).round(3)
27
- io&.puts "~~~~~~ filling @dheap_bm_random_vals with #{millions}M ~~~~~~"
28
- io&.flush
29
- count.times do @dheap_bm_random_vals << rand(0..10_000) end
30
- @dheap_bm_random_len = @dheap_bm_random_vals.length
31
- @dheap_bm_random_idx = (((@dheap_bm_random_idx || -1) + 1) % @dheap_bm_random_len)
32
- nil
33
- end
34
-
35
- def random_val
36
- @dheap_bm_random_vals.fetch(
37
- @dheap_bm_random_idx = ((@dheap_bm_random_idx + 1) % @dheap_bm_random_len)
38
- )
39
- end
40
-
41
- end
42
-
43
- # different scenarios to be benchmarked or profiled
44
- module Scenarios
45
-
46
- def push_n_multiple_queues(count, *queues)
47
- while 0 < count
48
- value = @dheap_bm_random_vals.fetch(
49
- @dheap_bm_random_idx = ((@dheap_bm_random_idx + 1) % @dheap_bm_random_len)
50
- )
51
- queues.each do |queue|
52
- queue << value
53
- end
54
- count -= 1
55
- end
56
- end
57
-
58
- def push_n(queue, count)
59
- while 0 < count
60
- queue << @dheap_bm_random_vals.fetch(
61
- @dheap_bm_random_idx = ((@dheap_bm_random_idx + 1) % @dheap_bm_random_len)
62
- )
63
- count -= 1
64
- end
65
- end
66
-
67
- def push_n_then_pop_n(queue, count) # rubocop:disable Metrics/MethodLength
68
- i = 0
69
- while i < count
70
- queue << @dheap_bm_random_vals.fetch(
71
- @dheap_bm_random_idx = ((@dheap_bm_random_idx + 1) % @dheap_bm_random_len)
72
- )
73
- i += 1
74
- end
75
- while 0 < i
76
- queue.pop
77
- i -= 1
78
- end
79
- end
80
-
81
- def repeated_push_pop(queue, count)
82
- while 0 < count
83
- queue << @dheap_bm_random_vals.fetch(
84
- @dheap_bm_random_idx = ((@dheap_bm_random_idx + 1) % @dheap_bm_random_len)
85
- )
86
- queue.pop
87
- count -= 1
88
- end
89
- end
90
-
91
- end
92
-
93
- include Randomness
94
- include Scenarios
95
-
96
- def initq(klass, count = 0, clear: false)
97
- queue = klass.new
98
- while 0 < count
99
- queue << @dheap_bm_random_vals.fetch(
100
- @dheap_bm_random_idx = ((@dheap_bm_random_idx + 1) % @dheap_bm_random_len)
101
- )
102
- count -= 1
103
- end
104
- queue.clear if clear
105
- queue
106
- end
107
-
108
- # rubocop:enable Style/NumericPredicate
109
-
110
- require "d_heap/benchmarks/implementations"
111
-
112
- end