benchcc 0.0.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 +7 -0
- data/.gitignore +18 -0
- data/.gitmodules +6 -0
- data/Gemfile +13 -0
- data/LICENSE.md +25 -0
- data/README.md +3 -0
- data/Rakefile +11 -0
- data/benchcc.gemspec +24 -0
- data/benchmarks/Rakefile +78 -0
- data/benchmarks/fmap/_env.rb +3 -0
- data/benchmarks/fmap/_main.erb +7 -0
- data/benchmarks/fmap/hana_list.erb.cpp +18 -0
- data/benchmarks/fmap/mpl11_list.erb.cpp +15 -0
- data/benchmarks/fmap/mpl_list.erb.cpp +15 -0
- data/benchmarks/fmap/mpl_vector.erb.cpp +15 -0
- data/benchmarks/include/_env.rb +1 -0
- data/benchmarks/include/hana.erb.cpp +1 -0
- data/benchmarks/include/mpl.erb.cpp +185 -0
- data/benchmarks/include/mpl11.erb.cpp +1 -0
- data/benchmarks/include/mpl11.min.erb.cpp +1 -0
- data/benchmarks/sum/_env.rb +3 -0
- data/benchmarks/sum/_main.erb +4 -0
- data/benchmarks/sum/constexpr.erb.cpp +24 -0
- data/benchmarks/sum/mpl11_variadic_foldl.erb.cpp +16 -0
- data/benchmarks/tuple_create/_env.rb +3 -0
- data/benchmarks/tuple_create/boost_tuple.erb.cpp +6 -0
- data/benchmarks/tuple_create/fusion_tuple.erb.cpp +6 -0
- data/benchmarks/tuple_create/hana_list.erb.cpp +6 -0
- data/benchmarks/tuple_create/std_tuple.erb.cpp +6 -0
- data/benchmarks/tuple_last/_env.rb +3 -0
- data/benchmarks/tuple_last/boost_tuple.erb.cpp +7 -0
- data/benchmarks/tuple_last/fusion_tuple.erb.cpp +7 -0
- data/benchmarks/tuple_last/hana_list.erb.cpp +7 -0
- data/benchmarks/tuple_last/std_tuple.erb.cpp +7 -0
- data/benchmarks/type_foldl/_env.rb +3 -0
- data/benchmarks/type_foldl/_main.erb +18 -0
- data/benchmarks/type_foldl/hana_list.erb.cpp +15 -0
- data/benchmarks/type_foldl/mpl11_cons.erb.cpp +10 -0
- data/benchmarks/type_foldl/mpl11_list.erb.cpp +8 -0
- data/benchmarks/type_foldl/mpl_list.erb.cpp +7 -0
- data/benchmarks/type_foldl/mpl_vector.erb.cpp +7 -0
- data/benchmarks/value_foldl/_env.rb +3 -0
- data/benchmarks/value_foldl/_main.erb +17 -0
- data/benchmarks/value_foldl/fusion_cons.erb.cpp +8 -0
- data/benchmarks/value_foldl/fusion_list.erb.cpp +9 -0
- data/benchmarks/value_foldl/fusion_vector.erb.cpp +9 -0
- data/benchmarks/value_foldl/hana_list.erb.cpp +6 -0
- data/lib/benchcc/benchmark.rb +53 -0
- data/lib/benchcc/compiler.rb +134 -0
- data/lib/benchcc/ext/enumerable.rb +7 -0
- data/lib/benchcc/ext/file.rb +16 -0
- data/lib/benchcc/ext/gnuplot.rb +8 -0
- data/lib/benchcc/ext/numeric.rb +15 -0
- data/lib/benchcc/ext/string.rb +5 -0
- data/lib/benchcc/fusion.rb +54 -0
- data/lib/benchcc/mpl.rb +48 -0
- data/lib/benchcc/plot.rb +44 -0
- data/lib/benchcc/version.rb +3 -0
- data/lib/benchcc.rb +6 -0
- data/spec/benchmark_spec.rb +23 -0
- data/spec/compiler_spec.rb +69 -0
- data/spec/numeric_spec.rb +23 -0
- data/spec/plot_spec.rb +29 -0
- data/spec/src/invalid.cpp +1 -0
- data/spec/src/plot.csv +3 -0
- data/spec/src/valid.cpp +1 -0
- metadata +166 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
template <typename ...>
|
2
|
+
struct result { };
|
3
|
+
|
4
|
+
constexpr struct {
|
5
|
+
template <typename State, typename X>
|
6
|
+
constexpr result<State, X> operator()(State, X) const
|
7
|
+
{ return {}; }
|
8
|
+
} f{};
|
9
|
+
|
10
|
+
<%= (0...breadth).map { |breadth|
|
11
|
+
xs = (0...depth).map { |depth| "x#{breadth}<#{depth}>" }
|
12
|
+
<<-EOS
|
13
|
+
constexpr struct { } state#{breadth}{};
|
14
|
+
template <int> struct x#{breadth} { };
|
15
|
+
static const auto go#{breadth} = #{yield 'f', "state#{breadth}", xs};
|
16
|
+
EOS
|
17
|
+
}.join("\n") %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<%= Benchcc::Fusion::Vector.new(0...depth).includes %>
|
2
|
+
|
3
|
+
#include <boost/fusion/algorithm/iteration/fold.hpp>
|
4
|
+
|
5
|
+
|
6
|
+
<%= render('_main.erb') do |f, state, xs|
|
7
|
+
vector = Benchcc::Fusion::Vector.new(xs)
|
8
|
+
"boost::fusion::fold(#{vector}{}, #{state}, #{f})"
|
9
|
+
end %>
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'compiler'
|
2
|
+
require 'csv'
|
3
|
+
require 'pathname'
|
4
|
+
require 'ruby-progressbar'
|
5
|
+
require 'tilt'
|
6
|
+
require 'timeout'
|
7
|
+
|
8
|
+
|
9
|
+
module Benchcc
|
10
|
+
class Renderer
|
11
|
+
def initialize(relative_to)
|
12
|
+
@relative_to = Pathname.new(relative_to)
|
13
|
+
@locals = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def render(file, **locals, &block)
|
17
|
+
@locals.merge!(locals)
|
18
|
+
file = Pathname.new(file).expand_path(@relative_to)
|
19
|
+
Tilt::ERBTemplate.new(file).render(self, **@locals, &block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def benchmark(file, envs, timeout: 10, relative_to: File.dirname(file), &block)
|
24
|
+
progress = ProgressBar.create(format: "#{file} %p%% | %B |",
|
25
|
+
total: envs.size)
|
26
|
+
consecutive_errors, data = 0, []
|
27
|
+
envs.each do |env|
|
28
|
+
break if consecutive_errors >= 2
|
29
|
+
code = Renderer.new(relative_to).render(file, **env)
|
30
|
+
begin
|
31
|
+
Timeout::timeout(timeout) { data << env.merge(block.call(code)) }
|
32
|
+
consecutive_errors = 0
|
33
|
+
rescue CompilationError, Timeout::Error => e
|
34
|
+
$stderr << e
|
35
|
+
consecutive_errors += 1
|
36
|
+
end
|
37
|
+
progress.increment
|
38
|
+
end
|
39
|
+
return data
|
40
|
+
ensure
|
41
|
+
progress.finish
|
42
|
+
end
|
43
|
+
module_function :benchmark
|
44
|
+
|
45
|
+
def benchmark_to_csv(file, envs, out, timeout: 10, relative_to: File.dirname(file), &block)
|
46
|
+
data = benchmark(file, envs, timeout: timeout, relative_to: relative_to, &block)
|
47
|
+
CSV.open(out, 'wb') do |csv|
|
48
|
+
csv << data.first.keys unless data.empty?
|
49
|
+
data.each { |line| csv << line.values }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
module_function :benchmark_to_csv
|
53
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'pathname'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
|
6
|
+
module Benchcc
|
7
|
+
class CompilationError < RuntimeError
|
8
|
+
def initialize(command_line, code, compiler_error_message)
|
9
|
+
@cli = command_line
|
10
|
+
@code = code
|
11
|
+
@compiler_stderr = compiler_error_message
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
<<-EOS
|
16
|
+
compilation failed when invoking "#{@cli}"
|
17
|
+
compiler error message was:
|
18
|
+
#{'-' * 80}
|
19
|
+
#{@compiler_stderr}
|
20
|
+
|
21
|
+
full compiled file was:
|
22
|
+
#{'-' * 80}
|
23
|
+
#{@code}
|
24
|
+
EOS
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Basic interface to compiler frontends.
|
29
|
+
class Compiler
|
30
|
+
# Maximum template recursion depth supported by the compiler.
|
31
|
+
def template_depth
|
32
|
+
raise NotImplementedError
|
33
|
+
end
|
34
|
+
|
35
|
+
# Maximum constexpr recursion depth supported by the compiler.
|
36
|
+
def constexpr_depth
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
# Show the name and the version of the compiler.
|
41
|
+
def to_s
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
44
|
+
|
45
|
+
# compile_file: Path -> Hash
|
46
|
+
#
|
47
|
+
# Compile the given file and return compilation statistics.
|
48
|
+
#
|
49
|
+
# Additional compiler-specific arguments may be specified.
|
50
|
+
#
|
51
|
+
# A `CompilationError` is be raised if the compilation fails for
|
52
|
+
# whatever reason. Either this method or `compile_code` must be
|
53
|
+
# implemented in subclasses.
|
54
|
+
def compile_file(file, *args)
|
55
|
+
raise ArgumentError, "invalid filename #{file}" unless File.file? file
|
56
|
+
code = File.read(file)
|
57
|
+
compile_code(code, *args)
|
58
|
+
end
|
59
|
+
|
60
|
+
# compile_code: String -> Hash
|
61
|
+
#
|
62
|
+
# Compile the given string and return compilation statistics.
|
63
|
+
#
|
64
|
+
# This method has the same behavior as `compile_file`, except the code
|
65
|
+
# is given as-is instead of being in a file. Either this method or
|
66
|
+
# `compile_file` must be implemented in subclasses.
|
67
|
+
def compile_code(code, *args)
|
68
|
+
tmp = Tempfile.new(["", '.cpp'])
|
69
|
+
tmp.write(code)
|
70
|
+
tmp.close
|
71
|
+
compile_file(tmp.path, *args)
|
72
|
+
ensure
|
73
|
+
tmp.unlink
|
74
|
+
end
|
75
|
+
end # class Compiler
|
76
|
+
|
77
|
+
class Clang < Compiler
|
78
|
+
def initialize(binary)
|
79
|
+
@exe = `which #{binary}`.strip
|
80
|
+
raise "#{binary} not found" unless $?.success?
|
81
|
+
end
|
82
|
+
|
83
|
+
def compile_file(file, *args)
|
84
|
+
file = Pathname.new(file).expand_path
|
85
|
+
command = "time -l #{@exe} #{args.join(' ')} -ftime-report #{file}"
|
86
|
+
stdout, stderr, status = Open3.capture3(command)
|
87
|
+
raise CompilationError.new(command, file.read, stderr) unless status.success?
|
88
|
+
|
89
|
+
return {
|
90
|
+
peak_memusg: stderr.match(/(\d+)\s+maximum/)[1].to_i,
|
91
|
+
wall_time: stderr.match(/.+Total/).to_s.split[-3].to_f
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def template_depth; 256; end
|
96
|
+
def constexpr_depth; 512; end
|
97
|
+
end
|
98
|
+
|
99
|
+
class GCC < Compiler
|
100
|
+
def initialize(binary)
|
101
|
+
@exe = `which #{binary}`.strip
|
102
|
+
raise "#{binary} not found" unless $?.success?
|
103
|
+
end
|
104
|
+
|
105
|
+
def compile_file(file, *args)
|
106
|
+
file = Pathname.new(file).expand_path
|
107
|
+
command = "time -l #{@exe} #{args.join(' ')} -ftime-report #{file}"
|
108
|
+
stdout, stderr, status = Open3.capture3(command)
|
109
|
+
raise CompilationError.new(command, file.read, stderr) unless status.success?
|
110
|
+
|
111
|
+
return {
|
112
|
+
peak_memusg: stderr.match(/(\d+)\s+maximum/)[1].to_i,
|
113
|
+
wall_time: stderr.match(/TOTAL.+/).to_s.split[-3].to_f
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def template_depth; 900; end
|
118
|
+
def constexpr_depth; 512; end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Compiler
|
122
|
+
def self.guess_from_binary(binary)
|
123
|
+
stdout, stderr, status = Open3.capture3("#{binary} --version")
|
124
|
+
case stdout
|
125
|
+
when /\(GCC\)/
|
126
|
+
return GCC.new(binary)
|
127
|
+
when /clang/
|
128
|
+
return Clang.new(binary)
|
129
|
+
else
|
130
|
+
raise ArgumentError("unknown compiler #{binary}")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
|
4
|
+
class File
|
5
|
+
def self.remove_ext(path)
|
6
|
+
path.chomp(extname(path))
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.sub_ext(path, ext)
|
10
|
+
Pathname.new(path).sub_ext(ext).to_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.basename_we(path)
|
14
|
+
File.basename(File.remove_ext(path))
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Numeric
|
2
|
+
# round_up: Numeric -> Numeric
|
3
|
+
#
|
4
|
+
# Round up the integer to a given precision in decimal digits (default 0
|
5
|
+
# digits). This is similar to `round`, except that rounding is always done
|
6
|
+
# upwards.
|
7
|
+
def round_up(ndigits = 0)
|
8
|
+
k = 10 ** ndigits
|
9
|
+
if self % k == 0
|
10
|
+
self
|
11
|
+
else
|
12
|
+
(1 + self/k) * k
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative 'ext/enumerable'
|
2
|
+
require_relative 'ext/numeric'
|
3
|
+
require 'delegate'
|
4
|
+
|
5
|
+
|
6
|
+
module Benchcc
|
7
|
+
module Fusion
|
8
|
+
class List < SimpleDelegator
|
9
|
+
def includes
|
10
|
+
inc = ["#define FUSION_MAX_LIST_SIZE 50"]
|
11
|
+
inc << headers.map { |hdr| "#include <#{hdr}>" }
|
12
|
+
inc.join("\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
def headers
|
16
|
+
["boost/fusion/container/list/list.hpp"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"boost::fusion::list<#{join(', ')}>"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Cons < SimpleDelegator
|
25
|
+
def includes
|
26
|
+
headers.map { |hdr| "#include <#{hdr}>" }.join("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
def headers
|
30
|
+
["boost/fusion/container/list/cons.hpp"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
foldr('boost::fusion::nil_') do |head, tail|
|
35
|
+
"boost::fusion::cons<#{head}, #{tail}>"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Vector < SimpleDelegator
|
41
|
+
def includes
|
42
|
+
headers.map { |hdr| "#include <#{hdr}>" }.join("\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
def headers
|
46
|
+
["boost/fusion/container/vector/vector#{[10, size.round_up(1)].max}.hpp"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
"boost::fusion::vector#{size}<#{join(', ')}>"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/benchcc/mpl.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative 'ext/numeric'
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
|
5
|
+
module Benchcc
|
6
|
+
module MPL
|
7
|
+
class Sequence < SimpleDelegator
|
8
|
+
def includes
|
9
|
+
headers.map { |hdr| "#include <#{hdr}>" }.join("\n")
|
10
|
+
end
|
11
|
+
|
12
|
+
def headers(name)
|
13
|
+
[
|
14
|
+
"boost/mpl/#{name}/#{name}#{[size.round_up(1), 50].min}.hpp",
|
15
|
+
size > 50 ? "boost/mpl/#{name}/aux_/item.hpp" : nil
|
16
|
+
].compact
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Vector < Sequence
|
21
|
+
def to_s
|
22
|
+
initial, rest = map(&:to_s).take(50), map(&:to_s).drop(50)
|
23
|
+
vectorN = "boost::mpl::vector#{initial.size}<#{initial.join(', ')}>"
|
24
|
+
rest.reduce(vectorN) do |tail, x|
|
25
|
+
"boost::mpl::v_item<#{x}, #{tail}, 0>" # we emulate mpl::push_back
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def headers; super 'vector'; end
|
30
|
+
end
|
31
|
+
|
32
|
+
class List < Sequence
|
33
|
+
def to_s
|
34
|
+
tail = map(&:to_s).last(50)
|
35
|
+
init = map(&:to_s).first([size - tail.size, 0].max)
|
36
|
+
listN = "boost::mpl::list#{tail.size}<#{tail.join(', ')}>"
|
37
|
+
|
38
|
+
init.reverse.zip(51..Float::INFINITY).reduce(listN) do |tail, x_size|
|
39
|
+
x, size = x_size
|
40
|
+
# we emulate mpl::push_front
|
41
|
+
"boost::mpl::l_item<boost::mpl::long_<#{size}>, #{x}, #{tail}>"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def headers; super 'list'; end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/benchcc/plot.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'gnuplot'
|
3
|
+
|
4
|
+
|
5
|
+
module Benchcc
|
6
|
+
def plot_memusg(output, *inputs)
|
7
|
+
Gnuplot.open do |io|
|
8
|
+
Gnuplot::Plot.new(io) do |plot|
|
9
|
+
plot.ylabel 'Memory usage'
|
10
|
+
plot.decimal "locale 'en_US.UTF-8'"
|
11
|
+
plot.format 'y "%.2e kb"'
|
12
|
+
plot.term 'png'
|
13
|
+
plot.output output
|
14
|
+
plot.data = inputs.map { |file|
|
15
|
+
csv = CSV.table(file)
|
16
|
+
Gnuplot::DataSet.new([csv[:x], csv[:peak_memusg]]) { |ds|
|
17
|
+
ds.title = file
|
18
|
+
ds.with = 'lines'
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
module_function :plot_memusg
|
25
|
+
|
26
|
+
def plot_time(output, *inputs)
|
27
|
+
Gnuplot.open do |io|
|
28
|
+
Gnuplot::Plot.new(io) do |plot|
|
29
|
+
plot.ylabel 'Compilation time'
|
30
|
+
plot.format 'y "%.2g s"'
|
31
|
+
plot.term 'png'
|
32
|
+
plot.output output
|
33
|
+
plot.data = inputs.map { |file|
|
34
|
+
csv = CSV.table(file)
|
35
|
+
Gnuplot::DataSet.new([csv[:x], csv[:wall_time]]) { |ds|
|
36
|
+
ds.title = file
|
37
|
+
ds.with = 'lines'
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
module_function :plot_time
|
44
|
+
end
|
data/lib/benchcc.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'benchcc/benchmark'
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'timeout'
|
6
|
+
|
7
|
+
|
8
|
+
describe Benchcc.method(:benchmark) do
|
9
|
+
it('time outs are ignored') {
|
10
|
+
timeout = 0.3
|
11
|
+
envs = [{time: timeout + 0.1}, {time: timeout - 0.1},
|
12
|
+
{time: timeout + 0.2}, {time: timeout - 0.2}]
|
13
|
+
Tempfile.create('') do |file|
|
14
|
+
file.write('<%= time %>')
|
15
|
+
file.flush
|
16
|
+
data = Benchcc.benchmark(file.path, envs, timeout: timeout) do |code|
|
17
|
+
sleep(code.to_f)
|
18
|
+
{time: code.to_f}
|
19
|
+
end
|
20
|
+
expect(data).to eq(envs.select { |env| env[:time] < timeout })
|
21
|
+
end
|
22
|
+
}
|
23
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'benchcc/compiler'
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'rspec'
|
5
|
+
require 'tempfile'
|
6
|
+
|
7
|
+
|
8
|
+
describe Benchcc::Compiler do
|
9
|
+
describe :compile_file do
|
10
|
+
it {
|
11
|
+
class Mock < Benchcc::Compiler
|
12
|
+
def compile_code(code); code; end
|
13
|
+
end
|
14
|
+
|
15
|
+
file = Tempfile.new('')
|
16
|
+
file.write("whatever")
|
17
|
+
expect(Mock.new.compile_file(file.path)).to eq(file.read)
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
describe :compile_code do
|
22
|
+
it {
|
23
|
+
class Mock < Benchcc::Compiler
|
24
|
+
def compile_file(file); File.read(file); end
|
25
|
+
end
|
26
|
+
|
27
|
+
expect(Mock.new.compile_code("whatever")).to eq("whatever")
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
describe :guess_from_binary do
|
32
|
+
it('can guess clang') {
|
33
|
+
expect(Benchcc::Compiler.guess_from_binary(`which clang`.strip)).to be_instance_of(Benchcc::Clang)
|
34
|
+
}
|
35
|
+
|
36
|
+
# GCC is aliased to clang on OSX, so this test fails.
|
37
|
+
# it('can guess gcc') {
|
38
|
+
# expect(Benchcc::Compiler.guess_from_binary(`which gcc`.strip)).to be_instance_of(Benchcc::GCC)
|
39
|
+
# }
|
40
|
+
|
41
|
+
it('fails otherwise') {
|
42
|
+
expect { Benchcc::Compiler.guess_from_binary('not_a_compiler') }.to raise_error
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
[[Benchcc::Clang, 'clang++'], [Benchcc::GCC, 'g++']].each do |compiler, which|
|
48
|
+
describe compiler do
|
49
|
+
before(:each) {
|
50
|
+
@cc = compiler.new(which)
|
51
|
+
@invalid = Pathname.new('src/invalid.cpp').expand_path(File.dirname(__FILE__))
|
52
|
+
@valid = Pathname.new('src/valid.cpp').expand_path(File.dirname(__FILE__))
|
53
|
+
}
|
54
|
+
|
55
|
+
describe :compile_file do
|
56
|
+
it('fails cleanly on invalid input') {
|
57
|
+
expect {
|
58
|
+
@cc.compile_file(@invalid)
|
59
|
+
}.to raise_error(Benchcc::CompilationError)
|
60
|
+
}
|
61
|
+
|
62
|
+
it('returns statistics on valid input') {
|
63
|
+
result = @cc.compile_file(@valid, '-o /dev/null')
|
64
|
+
expect(result).to have_key(:peak_memusg)
|
65
|
+
expect(result).to have_key(:wall_time)
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "benchcc/ext/numeric"
|
2
|
+
|
3
|
+
require "rspec"
|
4
|
+
|
5
|
+
|
6
|
+
describe Numeric do
|
7
|
+
describe :round_up do
|
8
|
+
it {
|
9
|
+
-150.upto(150) do |n|
|
10
|
+
expect(n.round_up).to eq(n)
|
11
|
+
end
|
12
|
+
}
|
13
|
+
|
14
|
+
it {
|
15
|
+
(10..150).step(10) do |tenths|
|
16
|
+
tenths.downto(tenths-9) do |n|
|
17
|
+
expect(n.round_up(1)).to eq(tenths)
|
18
|
+
end
|
19
|
+
expect((tenths-10).round_up(1)).to eq(tenths-10)
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
data/spec/plot_spec.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'benchcc/plot'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'rspec'
|
5
|
+
|
6
|
+
|
7
|
+
describe 'plots' do
|
8
|
+
before :each do
|
9
|
+
@tmpdir = Dir.mktmpdir
|
10
|
+
@out = File.join(@tmpdir, 'plot.png')
|
11
|
+
@csv = Pathname.new('src/plot.csv').expand_path(File.dirname(__FILE__))
|
12
|
+
end
|
13
|
+
|
14
|
+
after :each do
|
15
|
+
FileUtils.remove_entry(@tmpdir)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe Benchcc.method(:plot_memusg) do
|
19
|
+
it {
|
20
|
+
expect { Benchcc.plot_memusg(@out, @csv) }.not_to raise_error
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
describe Benchcc.method(:plot_time) do
|
25
|
+
it {
|
26
|
+
expect { Benchcc.plot_time(@out, @csv) }.not_to raise_error
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
int main() {
|
data/spec/src/plot.csv
ADDED
data/spec/src/valid.cpp
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
int main() {}
|