d_heap 0.6.1 → 0.7.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.
@@ -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