d_heap 0.2.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +26 -0
- data/.rubocop.yml +199 -0
- data/CHANGELOG.md +59 -0
- data/Gemfile +10 -2
- data/Gemfile.lock +42 -5
- data/README.md +392 -109
- data/Rakefile +8 -2
- data/benchmarks/perf.rb +29 -0
- data/benchmarks/push_n.yml +31 -0
- data/benchmarks/push_n_pop_n.yml +35 -0
- data/benchmarks/push_pop.yml +27 -0
- data/benchmarks/stackprof.rb +31 -0
- data/bin/bench_n +7 -0
- data/bin/benchmark-driver +29 -0
- data/bin/benchmarks +10 -0
- data/bin/console +1 -0
- data/bin/profile +10 -0
- data/bin/rubocop +29 -0
- data/d_heap.gemspec +11 -6
- data/docs/benchmarks-2.txt +75 -0
- data/docs/benchmarks-mem.txt +39 -0
- data/docs/benchmarks.txt +515 -0
- data/docs/profile.txt +392 -0
- data/ext/d_heap/d_heap.c +555 -225
- data/ext/d_heap/d_heap.h +24 -48
- data/ext/d_heap/extconf.rb +20 -0
- data/lib/benchmark_driver/runner/ips_zero_fail.rb +120 -0
- data/lib/d_heap.rb +40 -2
- data/lib/d_heap/benchmarks.rb +112 -0
- data/lib/d_heap/benchmarks/benchmarker.rb +116 -0
- data/lib/d_heap/benchmarks/implementations.rb +222 -0
- data/lib/d_heap/benchmarks/profiler.rb +71 -0
- data/lib/d_heap/benchmarks/rspec_matchers.rb +374 -0
- data/lib/d_heap/version.rb +4 -1
- metadata +54 -3
data/ext/d_heap/d_heap.h
CHANGED
@@ -11,64 +11,40 @@
|
|
11
11
|
// comparisons as d gets further from 4.
|
12
12
|
#define DHEAP_MAX_D 32
|
13
13
|
|
14
|
+
typedef long double SCORE;
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
#define CMP_GT(a, b, cmp_opt) \
|
20
|
-
(OPTIMIZED_CMP(a, b, cmp_opt) > 0)
|
21
|
-
#define CMP_GTE(a, b, cmp_opt) \
|
22
|
-
(OPTIMIZED_CMP(a, b, cmp_opt) >= 0)
|
16
|
+
typedef struct dheap_entry {
|
17
|
+
SCORE score;
|
18
|
+
VALUE value;
|
19
|
+
} ENTRY;
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
// from internal/numeric.h
|
28
|
-
#ifndef INTERNAL_NUMERIC_H
|
29
|
-
int rb_float_cmp(VALUE x, VALUE y);
|
30
|
-
#endif /* INTERNAL_NUMERIC_H */
|
21
|
+
#define DHEAP_DEFAULT_SIZE 256
|
22
|
+
#define DHEAP_MAX_SIZE (LONG_MAX / (int)sizeof(ENTRY))
|
31
23
|
|
32
|
-
|
33
|
-
#ifndef INTERNAL_COMPAR_H
|
34
|
-
#define STRING_P(s) (RB_TYPE_P((s), T_STRING) && CLASS_OF(s) == rb_cString)
|
24
|
+
#define DHEAP_CAPA_INCR_MAX (10 * 1024 * 1024 / (int)sizeof(ENTRY))
|
35
25
|
|
36
|
-
|
37
|
-
cmp_opt_Integer,
|
38
|
-
cmp_opt_String,
|
39
|
-
cmp_opt_Float,
|
40
|
-
cmp_optimizable_count
|
41
|
-
};
|
26
|
+
VALUE rb_cDHeap;
|
42
27
|
|
43
|
-
|
44
|
-
unsigned int opt_methods;
|
45
|
-
unsigned int opt_inited;
|
46
|
-
};
|
28
|
+
// copied from pg gem
|
47
29
|
|
48
|
-
#define
|
49
|
-
NEW_PARTIAL_MEMO_FOR(type, value, cmp_opt)
|
50
|
-
#define CMP_OPTIMIZABLE_BIT(type) (1U << TOKEN_PASTE(cmp_opt_,type))
|
51
|
-
#define CMP_OPTIMIZABLE(data, type) \
|
52
|
-
(((data).opt_inited & CMP_OPTIMIZABLE_BIT(type)) ? \
|
53
|
-
((data).opt_methods & CMP_OPTIMIZABLE_BIT(type)) : \
|
54
|
-
(((data).opt_inited |= CMP_OPTIMIZABLE_BIT(type)), \
|
55
|
-
rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \
|
56
|
-
((data).opt_methods |= CMP_OPTIMIZABLE_BIT(type))))
|
30
|
+
#define UNUSED(x) ((void)(x))
|
57
31
|
|
58
|
-
#
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
32
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
33
|
+
#define dheap_compact_callback(x) ((void (*)(void*))(x))
|
34
|
+
#define dheap_gc_location(x) x = rb_gc_location(x)
|
35
|
+
#else
|
36
|
+
#define rb_gc_mark_movable(x) rb_gc_mark(x)
|
37
|
+
#define dheap_compact_callback(x) {(x)}
|
38
|
+
#define dheap_gc_location(x) UNUSED(x)
|
39
|
+
#endif
|
66
40
|
|
67
|
-
#
|
41
|
+
#ifdef __D_HEAP_DEBUG
|
42
|
+
#define debug(v) { \
|
68
43
|
ID sym_puts = rb_intern("puts"); \
|
69
44
|
rb_funcall(rb_mKernel, sym_puts, 1, v); \
|
70
45
|
}
|
71
|
-
|
72
|
-
#
|
46
|
+
#else
|
47
|
+
#define debug(v)
|
48
|
+
#endif
|
73
49
|
|
74
50
|
#endif /* D_HEAP_H */
|
data/ext/d_heap/extconf.rb
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "mkmf"
|
2
4
|
|
5
|
+
# For testing in CI (because I don't otherwise have easy access to Mac OS):
|
6
|
+
# $CFLAGS << " -D__D_HEAP_DEBUG" if /darwin/ =~ RUBY_PLATFORM
|
7
|
+
# $CFLAGS << " -debug inline-debug-info "
|
8
|
+
# $CFLAGS << " -g -ginline-points "
|
9
|
+
# $CFLAGS << " -fno-omit-frame-pointer "
|
10
|
+
|
11
|
+
# CONFIG["debugflags"] << " -ggdb3 -gstatement-frontiers -ginline-points "
|
12
|
+
CONFIG["optflags"] << " -O3 "
|
13
|
+
CONFIG["optflags"] << " -fno-omit-frame-pointer "
|
14
|
+
CONFIG["warnflags"] << " -Werror"
|
15
|
+
|
16
|
+
have_func "rb_gc_mark_movable" # since ruby-2.7
|
17
|
+
|
18
|
+
check_sizeof("long")
|
19
|
+
check_sizeof("unsigned long long")
|
20
|
+
check_sizeof("long double")
|
21
|
+
have_macro("LDBL_MANT_DIG", "float.h")
|
22
|
+
|
3
23
|
create_makefile("d_heap/d_heap")
|
@@ -0,0 +1,120 @@
|
|
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
|
+
end
|
33
|
+
|
34
|
+
# BenchmarkDriver::Runner looks for this class
|
35
|
+
JobParser = BenchmarkDriver::DefaultJobParser.for(klass: Job, metrics: [METRIC])
|
36
|
+
|
37
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/BlockLength, Layout/LineLength, Layout/SpaceInsideBlockBraces, Style/BlockDelimiters
|
38
|
+
|
39
|
+
# This method is dynamically called by `BenchmarkDriver::JobRunner.run`
|
40
|
+
# @param [Array<BenchmarkDriver::Default::Job>] jobs
|
41
|
+
def run(jobs)
|
42
|
+
if jobs.any? { |job| job.loop_count.nil? }
|
43
|
+
@output.with_warmup do
|
44
|
+
jobs = jobs.map do |job|
|
45
|
+
next job if job.loop_count # skip warmup if loop_count is set
|
46
|
+
|
47
|
+
@output.with_job(name: job.name) do
|
48
|
+
context = job.runnable_contexts(@contexts).first
|
49
|
+
duration, loop_count = run_warmup(job, context: context)
|
50
|
+
value, duration = value_duration(duration: duration, loop_count: loop_count)
|
51
|
+
|
52
|
+
@output.with_context(name: context.name, executable: context.executable, gems: context.gems, prelude: context.prelude) do
|
53
|
+
@output.report(values: { metric => value }, duration: duration, loop_count: loop_count)
|
54
|
+
end
|
55
|
+
|
56
|
+
warmup_loop_count = loop_count
|
57
|
+
|
58
|
+
loop_count = (loop_count.to_f * @config.run_duration / duration).floor
|
59
|
+
Job.new(**job.to_h.merge(loop_count: loop_count))
|
60
|
+
.tap {|j| j.warmup_value = value }
|
61
|
+
.tap {|j| j.warmup_duration = duration }
|
62
|
+
.tap {|j| j.warmup_loop_count = warmup_loop_count }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
.compact
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
@output.with_benchmark do
|
70
|
+
jobs.each do |job|
|
71
|
+
@output.with_job(name: job.name) do
|
72
|
+
job.runnable_contexts(@contexts).each do |context|
|
73
|
+
repeat_params = { config: @config, larger_better: true, rest_on_average: :average }
|
74
|
+
result =
|
75
|
+
if job.loop_count&.positive?
|
76
|
+
loop_count = job.loop_count
|
77
|
+
BenchmarkDriver::Repeater.with_repeat(**repeat_params) do
|
78
|
+
run_benchmark(job, context: context)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
loop_count = job.warmup_loop_count
|
82
|
+
repeater_value = [job.warmup_value, job.warmup_duration]
|
83
|
+
BenchmarkDriver::Repeater::RepeatResult.new(
|
84
|
+
value: repeater_value, all_values: [repeater_value]
|
85
|
+
)
|
86
|
+
end
|
87
|
+
value, duration = result.value
|
88
|
+
@output.with_context(name: context.name, executable: context.executable, gems: context.gems, prelude: context.prelude) do
|
89
|
+
@output.report(
|
90
|
+
values: { metric => value },
|
91
|
+
all_values: { metric => result.all_values },
|
92
|
+
duration: duration,
|
93
|
+
loop_count: loop_count,
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/BlockLength, Layout/LineLength, Layout/SpaceInsideBlockBraces, Style/BlockDelimiters
|
103
|
+
|
104
|
+
def run_warmup(job, context:)
|
105
|
+
start = Time.now
|
106
|
+
super(job, context: context)
|
107
|
+
rescue Timeout::Error
|
108
|
+
[Time.now - start, 0.0.next_float]
|
109
|
+
end
|
110
|
+
|
111
|
+
def execute(*args, exception: true)
|
112
|
+
super
|
113
|
+
rescue RuntimeError => ex
|
114
|
+
if args.include?("timeout") && $CHILD_STATUS&.exitstatus == 124
|
115
|
+
raise Timeout::Error, ex.message
|
116
|
+
end
|
117
|
+
raise ex
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
data/lib/d_heap.rb
CHANGED
@@ -1,10 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "d_heap/d_heap"
|
2
4
|
require "d_heap/version"
|
3
5
|
|
6
|
+
# A fast _d_-ary heap implementation for ruby, useful in priority queues and graph
|
7
|
+
# algorithms.
|
8
|
+
#
|
9
|
+
# The _d_-ary heap data structure is a generalization of the binary heap, in which
|
10
|
+
# the nodes have _d_ children instead of 2. This allows for "decrease priority"
|
11
|
+
# operations to be performed more quickly with the tradeoff of slower delete
|
12
|
+
# minimum. Additionally, _d_-ary heaps can have better memory cache behavior than
|
13
|
+
# binary heaps, allowing them to run more quickly in practice despite slower
|
14
|
+
# worst-case time complexity.
|
15
|
+
#
|
4
16
|
class DHeap
|
17
|
+
alias deq pop
|
18
|
+
alias enq push
|
19
|
+
alias first peek
|
20
|
+
alias pop_below pop_lt
|
21
|
+
|
22
|
+
alias length size
|
23
|
+
alias count size
|
24
|
+
|
25
|
+
# ruby 3.0+ (2.x can just use inherited initialize_clone)
|
26
|
+
if Object.instance_method(:initialize_clone).arity == -1
|
27
|
+
# @!visibility private
|
28
|
+
def initialize_clone(other, freeze: nil)
|
29
|
+
__init_clone__(other, freeze ? true : freeze)
|
30
|
+
end
|
31
|
+
end
|
5
32
|
|
6
|
-
|
7
|
-
|
33
|
+
# Consumes the heap by popping each minumum value until it is empty.
|
34
|
+
#
|
35
|
+
# If you want to iterate over the heap without consuming it, you will need to
|
36
|
+
# first call +#dup+
|
37
|
+
#
|
38
|
+
# @yieldparam value [Object] each value that would be popped
|
39
|
+
#
|
40
|
+
# @return [Enumerator] if no block is given
|
41
|
+
# @return [nil] if a block is given
|
42
|
+
def each_pop
|
43
|
+
return to_enum(__method__) unless block_given?
|
44
|
+
yield pop until empty?
|
45
|
+
nil
|
8
46
|
end
|
9
47
|
|
10
48
|
end
|
@@ -0,0 +1,112 @@
|
|
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
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "d_heap/benchmarks"
|
4
|
+
|
5
|
+
require "benchmark_driver"
|
6
|
+
require "shellwords"
|
7
|
+
require "English"
|
8
|
+
|
9
|
+
module DHeap::Benchmarks
|
10
|
+
# Benchmarks different implementations with different sizes
|
11
|
+
class Benchmarker
|
12
|
+
include Randomness
|
13
|
+
include Scenarios
|
14
|
+
|
15
|
+
N_COUNTS = [
|
16
|
+
5, # 1 + 4
|
17
|
+
21, # 1 + 4 + 16
|
18
|
+
85, # 1 + 4 + 16 + 64
|
19
|
+
341, # 1 + 4 + 16 + 64 + 256
|
20
|
+
1365, # 1 + 4 + 16 + 64 + 256 + 1024
|
21
|
+
5461, # 1 + 4 + 16 + 64 + 256 + 1024 + 4096
|
22
|
+
21_845, # 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + 16384
|
23
|
+
87_381, # 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + 16384 + 65536
|
24
|
+
].freeze
|
25
|
+
|
26
|
+
attr_reader :time
|
27
|
+
attr_reader :iterations_for_push_pop
|
28
|
+
attr_reader :io
|
29
|
+
|
30
|
+
def initialize(
|
31
|
+
time: Integer(ENV.fetch("BENCHMARK_TIME", 10)),
|
32
|
+
iterations_for_push_pop: 10_000,
|
33
|
+
io: $stdout
|
34
|
+
)
|
35
|
+
@time = time
|
36
|
+
@iterations_for_push_pop = Integer(iterations_for_push_pop)
|
37
|
+
@io = io
|
38
|
+
end
|
39
|
+
|
40
|
+
def call(queue_size: ENV.fetch("BENCHMARK_QUEUE_SIZE", :unset))
|
41
|
+
DHeap::Benchmarks.puts_version_info("Benchmarking")
|
42
|
+
sizes = (queue_size == :unset) ? N_COUNTS : [Integer(queue_size)]
|
43
|
+
sizes.each do |size|
|
44
|
+
benchmark_size(size)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def benchmark_size(size)
|
49
|
+
sep "#", "Benchmarks with N=#{size} (t=#{time}sec/benchmark)", big: true
|
50
|
+
io.puts
|
51
|
+
benchmark_push_n size
|
52
|
+
benchmark_push_n_then_pop_n size
|
53
|
+
benchmark_repeated_push_pop size
|
54
|
+
end
|
55
|
+
|
56
|
+
def benchmark_push_n(queue_size)
|
57
|
+
benchmarking("push N", "push_n", queue_size)
|
58
|
+
end
|
59
|
+
|
60
|
+
def benchmark_push_n_then_pop_n(queue_size)
|
61
|
+
benchmarking("push N then pop N", "push_n_pop_n", queue_size)
|
62
|
+
end
|
63
|
+
|
64
|
+
def benchmark_repeated_push_pop(queue_size)
|
65
|
+
benchmarking(
|
66
|
+
"Push/pop with pre-filled queue (size=N)", "push_pop", queue_size
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
# TODO: move somewhere else...
|
73
|
+
def skip_profiling?(queue_size, impl)
|
74
|
+
impl.klass == DHeap::Benchmarks::PushAndResort && 10_000 < queue_size
|
75
|
+
end
|
76
|
+
|
77
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
78
|
+
|
79
|
+
def benchmarking(name, file, size)
|
80
|
+
Bundler.with_unbundled_env do
|
81
|
+
sep "==", "#{name} (N=#{size})"
|
82
|
+
cmd = %W[
|
83
|
+
bin/benchmark-driver
|
84
|
+
--bundler
|
85
|
+
--run-duration 6
|
86
|
+
--timeout 15
|
87
|
+
--runner ips_zero_fail
|
88
|
+
benchmarks/#{file}.yml
|
89
|
+
]
|
90
|
+
if file == "push_n"
|
91
|
+
cmd << "--filter" << /dheap|\bstl\b|\bbsearch\b|\brb_heap\b/.to_s
|
92
|
+
end
|
93
|
+
env = ENV.to_h.merge(
|
94
|
+
"BENCH_N" => size.to_s,
|
95
|
+
"RUBYLIB" => File.expand_path("../..", __dir__),
|
96
|
+
)
|
97
|
+
system(env, *cmd)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def sep(sep, msg = "", width: 80, big: false)
|
102
|
+
txt = String.new
|
103
|
+
txt += "#{sep * (width / sep.length)}\n" if big
|
104
|
+
txt += sep
|
105
|
+
txt += " #{msg}" if msg && !msg.empty?
|
106
|
+
txt += " " unless big
|
107
|
+
txt += sep * ((width - txt.length) / sep.length) unless big
|
108
|
+
txt += "\n"
|
109
|
+
txt += "#{sep * (width / sep.length)}\n" if big
|
110
|
+
io.print txt
|
111
|
+
end
|
112
|
+
|
113
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|