benchcc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +6 -0
  4. data/Gemfile +13 -0
  5. data/LICENSE.md +25 -0
  6. data/README.md +3 -0
  7. data/Rakefile +11 -0
  8. data/benchcc.gemspec +24 -0
  9. data/benchmarks/Rakefile +78 -0
  10. data/benchmarks/fmap/_env.rb +3 -0
  11. data/benchmarks/fmap/_main.erb +7 -0
  12. data/benchmarks/fmap/hana_list.erb.cpp +18 -0
  13. data/benchmarks/fmap/mpl11_list.erb.cpp +15 -0
  14. data/benchmarks/fmap/mpl_list.erb.cpp +15 -0
  15. data/benchmarks/fmap/mpl_vector.erb.cpp +15 -0
  16. data/benchmarks/include/_env.rb +1 -0
  17. data/benchmarks/include/hana.erb.cpp +1 -0
  18. data/benchmarks/include/mpl.erb.cpp +185 -0
  19. data/benchmarks/include/mpl11.erb.cpp +1 -0
  20. data/benchmarks/include/mpl11.min.erb.cpp +1 -0
  21. data/benchmarks/sum/_env.rb +3 -0
  22. data/benchmarks/sum/_main.erb +4 -0
  23. data/benchmarks/sum/constexpr.erb.cpp +24 -0
  24. data/benchmarks/sum/mpl11_variadic_foldl.erb.cpp +16 -0
  25. data/benchmarks/tuple_create/_env.rb +3 -0
  26. data/benchmarks/tuple_create/boost_tuple.erb.cpp +6 -0
  27. data/benchmarks/tuple_create/fusion_tuple.erb.cpp +6 -0
  28. data/benchmarks/tuple_create/hana_list.erb.cpp +6 -0
  29. data/benchmarks/tuple_create/std_tuple.erb.cpp +6 -0
  30. data/benchmarks/tuple_last/_env.rb +3 -0
  31. data/benchmarks/tuple_last/boost_tuple.erb.cpp +7 -0
  32. data/benchmarks/tuple_last/fusion_tuple.erb.cpp +7 -0
  33. data/benchmarks/tuple_last/hana_list.erb.cpp +7 -0
  34. data/benchmarks/tuple_last/std_tuple.erb.cpp +7 -0
  35. data/benchmarks/type_foldl/_env.rb +3 -0
  36. data/benchmarks/type_foldl/_main.erb +18 -0
  37. data/benchmarks/type_foldl/hana_list.erb.cpp +15 -0
  38. data/benchmarks/type_foldl/mpl11_cons.erb.cpp +10 -0
  39. data/benchmarks/type_foldl/mpl11_list.erb.cpp +8 -0
  40. data/benchmarks/type_foldl/mpl_list.erb.cpp +7 -0
  41. data/benchmarks/type_foldl/mpl_vector.erb.cpp +7 -0
  42. data/benchmarks/value_foldl/_env.rb +3 -0
  43. data/benchmarks/value_foldl/_main.erb +17 -0
  44. data/benchmarks/value_foldl/fusion_cons.erb.cpp +8 -0
  45. data/benchmarks/value_foldl/fusion_list.erb.cpp +9 -0
  46. data/benchmarks/value_foldl/fusion_vector.erb.cpp +9 -0
  47. data/benchmarks/value_foldl/hana_list.erb.cpp +6 -0
  48. data/lib/benchcc/benchmark.rb +53 -0
  49. data/lib/benchcc/compiler.rb +134 -0
  50. data/lib/benchcc/ext/enumerable.rb +7 -0
  51. data/lib/benchcc/ext/file.rb +16 -0
  52. data/lib/benchcc/ext/gnuplot.rb +8 -0
  53. data/lib/benchcc/ext/numeric.rb +15 -0
  54. data/lib/benchcc/ext/string.rb +5 -0
  55. data/lib/benchcc/fusion.rb +54 -0
  56. data/lib/benchcc/mpl.rb +48 -0
  57. data/lib/benchcc/plot.rb +44 -0
  58. data/lib/benchcc/version.rb +3 -0
  59. data/lib/benchcc.rb +6 -0
  60. data/spec/benchmark_spec.rb +23 -0
  61. data/spec/compiler_spec.rb +69 -0
  62. data/spec/numeric_spec.rb +23 -0
  63. data/spec/plot_spec.rb +29 -0
  64. data/spec/src/invalid.cpp +1 -0
  65. data/spec/src/plot.csv +3 -0
  66. data/spec/src/valid.cpp +1 -0
  67. metadata +166 -0
@@ -0,0 +1,8 @@
1
+ #define BOOST_MPL11_NO_ASSERTIONS
2
+ #include <boost/mpl11/list.hpp>
3
+
4
+
5
+ <%= render('_main.erb') do |f, state, xs|
6
+ list = "boost::mpl11::list<#{xs.join(', ')}>"
7
+ "boost::mpl11::foldl<#{f}, #{state}, #{list}>::type"
8
+ end %>
@@ -0,0 +1,7 @@
1
+ #include <boost/mpl/fold.hpp>
2
+ <%= Benchcc::MPL::List.new(0...depth).includes %>
3
+
4
+
5
+ <%= render('_main.erb') do |f, state, xs|
6
+ "boost::mpl::fold<#{Benchcc::MPL::List.new(xs)}, #{state}, #{f}>::type"
7
+ end %>
@@ -0,0 +1,7 @@
1
+ #include <boost/mpl/fold.hpp>
2
+ <%= Benchcc::MPL::Vector.new(0...depth).includes %>
3
+
4
+
5
+ <%= render('_main.erb') do |f, state, xs|
6
+ "boost::mpl::fold<#{Benchcc::MPL::Vector.new(xs)}, #{state}, #{f}>::type"
7
+ end %>
@@ -0,0 +1,3 @@
1
+ (0..1000).step(5).map { |depth|
2
+ { breadth: 1, depth: depth }
3
+ }
@@ -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,8 @@
1
+ #include <boost/fusion/algorithm/iteration/fold.hpp>
2
+ <%= Benchcc::Fusion::Cons.new(0...depth).includes %>
3
+
4
+
5
+ <%= render('_main.erb') do |f, state, xs|
6
+ cons = Benchcc::Fusion::Cons.new(xs)
7
+ "boost::fusion::fold(#{cons}{}, #{state}, #{f})"
8
+ end %>
@@ -0,0 +1,9 @@
1
+ <%= Benchcc::Fusion::List.new(0...depth).includes %>
2
+
3
+ #include <boost/fusion/algorithm/iteration/fold.hpp>
4
+
5
+
6
+ <%= render('_main.erb') do |f, state, xs|
7
+ list = Benchcc::Fusion::List.new(xs)
8
+ "boost::fusion::fold(#{list}{}, #{state}, #{f})"
9
+ end %>
@@ -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,6 @@
1
+ #include <boost/hana/list.hpp>
2
+
3
+ <%= render('_main.erb') do |f, state, xs|
4
+ xs = xs.map { |x| "#{x}{}" }.join(', ')
5
+ "boost::hana::foldl(#{f}, #{state}, boost::hana::list(#{xs}))"
6
+ 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,7 @@
1
+ module Enumerable
2
+ def foldr(state, &block)
3
+ reverse.inject(state) { |state, x| block.call(x, state) }
4
+ end
5
+
6
+ alias_method(:foldl, :inject)
7
+ 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,8 @@
1
+ require 'gnuplot'
2
+
3
+
4
+ class Gnuplot::DataSet
5
+ def self.from_file(file, using: [1, 2], &block)
6
+ self.new("\"#{file}\" using #{using.join(':')}", &block)
7
+ end
8
+ 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,5 @@
1
+ class String
2
+ def quote(char = '"')
3
+ char + self + char
4
+ end
5
+ 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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Benchcc
2
+ VERSION = "0.0.1"
3
+ end
data/lib/benchcc.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'benchcc/benchmark'
2
+ require 'benchcc/compiler'
3
+ require 'benchcc/fusion'
4
+ require 'benchcc/mpl'
5
+ require 'benchcc/plot'
6
+ require 'benchcc/version'
@@ -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
@@ -0,0 +1,3 @@
1
+ x, peak_memusg, wall_time
2
+ 0, 1, , 2
3
+ 1, 2, , 3
@@ -0,0 +1 @@
1
+ int main() {}