Skip to content

Commit 841e102

Browse files
authored
feat: add benchmark suite
Only a single benchmark has been added so far. To execute a benchmark, use the `just bench` target which accepts a benchmark name. The reference outputs of the benchmarked programs are larger and we manage them with git LFS.
1 parent 27c2d7d commit 841e102

File tree

6 files changed

+86
-0
lines changed

6 files changed

+86
-0
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test/benchmarks/fixtures/*.json filter=lfs diff=lfs merge=lfs -text

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
*.json
22
!.devcontainer/devcontainer.json
33
!test/fixtures/*.json
4+
!test/benchmarks/fixtures/*.json
45
test/tmp/
56
.direnv/

Justfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ alias t := test
22

33
test:
44
ruby -Itest test/test_tracer.rb
5+
6+
bench name="heavy_work":
7+
ruby test/benchmarks/run_benchmark.rb {{name}}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:912fc0347cb8a57abd94a7defd76b147f3a79e556745e45207b89529f8a59d8b
3+
size 8203587
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
def prime?(n)
2+
return false if n < 2
3+
(2..Math.sqrt(n).floor).each do |i|
4+
return false if n % i == 0
5+
end
6+
true
7+
end
8+
9+
def primes(n)
10+
arr = []
11+
i = 2
12+
while arr.length < n
13+
arr << i if prime?(i)
14+
i += 1
15+
end
16+
arr
17+
end
18+
19+
def compute
20+
arr = primes(100)
21+
hash = arr.each_with_index.to_h
22+
sum = arr.reduce(:+)
23+
str = arr.map(&:to_s).join(',')
24+
[sum, str, hash[arr.size]]
25+
end
26+
27+
compute

test/benchmarks/run_benchmark.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
require 'json'
2+
require 'fileutils'
3+
require 'digest'
4+
require 'benchmark'
5+
6+
USAGE = "Usage: ruby run_benchmark.rb BENCHMARK_NAME"
7+
8+
BENCHMARK = ARGV.shift || abort(USAGE)
9+
HASHES = {
10+
'heavy_work' => '912fc0347cb8a57abd94a7defd76b147f3a79e556745e45207b89529f8a59d8b'
11+
}
12+
13+
unless HASHES.key?(BENCHMARK)
14+
abort("Unknown benchmark '#{BENCHMARK}'")
15+
end
16+
17+
PROGRAM = File.expand_path("programs/#{BENCHMARK}.rb", __dir__)
18+
FIXTURE = File.expand_path("fixtures/#{BENCHMARK}_trace.json", __dir__)
19+
TMP_DIR = File.expand_path('tmp', __dir__)
20+
OUTPUT = File.join(TMP_DIR, "#{BENCHMARK}_trace.json")
21+
EXPECTED_HASH = HASHES[BENCHMARK]
22+
23+
FileUtils.mkdir_p(TMP_DIR)
24+
25+
unless File.exist?(FIXTURE) && Digest::SHA256.file(FIXTURE).hexdigest == EXPECTED_HASH
26+
warn "Reference trace missing or corrupt. Attempting to fetch via git lfs..."
27+
system('git', 'lfs', 'pull', '--include', FIXTURE)
28+
end
29+
30+
raise 'reference trace unavailable' unless File.exist?(FIXTURE)
31+
raise 'reference trace hash mismatch' unless Digest::SHA256.file(FIXTURE).hexdigest == EXPECTED_HASH
32+
33+
elapsed = Benchmark.realtime do
34+
env = { 'CODETRACER_DB_TRACE_PATH' => OUTPUT }
35+
system(env, 'ruby', File.expand_path('../../src/trace.rb', __dir__), PROGRAM)
36+
raise 'trace failed' unless $?.success?
37+
end
38+
puts "Benchmark runtime: #{(elapsed * 1000).round} ms"
39+
40+
def files_identical?(a, b)
41+
cmp_result = system('cmp', '-s', a, b)
42+
return $?.success? if !cmp_result.nil?
43+
File.binread(a) == File.binread(b)
44+
end
45+
46+
if files_identical?(FIXTURE, OUTPUT)
47+
puts 'Trace matches reference.'
48+
else
49+
warn 'Trace differs from reference!'
50+
exit 1
51+
end

0 commit comments

Comments
 (0)