From 4520f79eba1317c16449af75a2d4ddbdcbf967ba Mon Sep 17 00:00:00 2001 From: Randy Stauner Date: Tue, 11 Feb 2025 11:44:11 -0700 Subject: [PATCH] Add a benchmark for rubyboy's headless emulator The repo is a gem so we can just use it from our Gemfile. The rom is included. The current loop produces results similar to our optcarrot benchmark. cruby: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin23] yjit: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin23] --------- ---------- ---------- --------- ---------- ------------ ---------- bench cruby (ms) stddev (%) yjit (ms) stddev (%) yjit 1st itr cruby/yjit optcarrot 3100.0 0.6 800.8 1.7 3.599 3.871 rubyboy 2764.1 0.5 991.9 1.0 2.606 2.787 --------- ---------- ---------- --------- ---------- ------------ ---------- Legend: - yjit 1st itr: ratio of cruby/yjit time for the first benchmarking iteration. - cruby/yjit: ratio of cruby/yjit time. Higher is better for yjit. Above 1 represents a speedup. --- benchmarks.yml | 2 ++ benchmarks/rubyboy/Gemfile | 5 +++++ benchmarks/rubyboy/Gemfile.lock | 40 +++++++++++++++++++++++++++++++++ benchmarks/rubyboy/benchmark.rb | 28 +++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 benchmarks/rubyboy/Gemfile create mode 100644 benchmarks/rubyboy/Gemfile.lock create mode 100644 benchmarks/rubyboy/benchmark.rb diff --git a/benchmarks.yml b/benchmarks.yml index 65465a90..aa85d7ed 100644 --- a/benchmarks.yml +++ b/benchmarks.yml @@ -71,6 +71,8 @@ rack: desc: test the performance of the Rack framework with barely any routing. ruby-json: desc: an optimized version of the json_pure gem's pure Ruby JSON parser. +rubyboy: + desc: Rubyboy is a functional headless GameBoy emulator, run on a specific game cartridge for a specific number of frames. rubykon: desc: Ruby solver for Go (the boardgame.) Runs many iterations forward from an initial starting board. tinygql: diff --git a/benchmarks/rubyboy/Gemfile b/benchmarks/rubyboy/Gemfile new file mode 100644 index 00000000..940de805 --- /dev/null +++ b/benchmarks/rubyboy/Gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gem "rubyboy", git: "https://github.com/sacckey/rubyboy" diff --git a/benchmarks/rubyboy/Gemfile.lock b/benchmarks/rubyboy/Gemfile.lock new file mode 100644 index 00000000..e545e291 --- /dev/null +++ b/benchmarks/rubyboy/Gemfile.lock @@ -0,0 +1,40 @@ +GIT + remote: https://github.com/sacckey/rubyboy + revision: e6c7d1d64ed7c6edb0ec6bae25ae3e7ec4cc9319 + specs: + rubyboy (1.5.0) + ffi (~> 1.16, >= 1.16.3) + +GEM + remote: https://rubygems.org/ + specs: + ffi (1.17.1) + ffi (1.17.1-aarch64-linux-gnu) + ffi (1.17.1-aarch64-linux-musl) + ffi (1.17.1-arm-linux-gnu) + ffi (1.17.1-arm-linux-musl) + ffi (1.17.1-arm64-darwin) + ffi (1.17.1-x86-linux-gnu) + ffi (1.17.1-x86-linux-musl) + ffi (1.17.1-x86_64-darwin) + ffi (1.17.1-x86_64-linux-gnu) + ffi (1.17.1-x86_64-linux-musl) + +PLATFORMS + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + x86-linux-gnu + x86-linux-musl + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + rubyboy! + +BUNDLED WITH + 2.4.19 diff --git a/benchmarks/rubyboy/benchmark.rb b/benchmarks/rubyboy/benchmark.rb new file mode 100644 index 00000000..e00eb616 --- /dev/null +++ b/benchmarks/rubyboy/benchmark.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require_relative "../../harness/loader" + +Dir.chdir(__dir__) +use_gemfile + +# Rubyboy has a Bench module which is just a loop around `emulator.step`. +# https://github.com/sacckey/rubyboy/blob/e6c7d1d64ed7c6edb0ec6bae25ae3e7ec4cc9319/lib/bench.rb + +require 'rubyboy/emulator_headless' + +# The rom is included in the gem in a sibling directory to the rubyboy code. +rom_path = File.expand_path("../../roms/tobu.gb", $".detect { |x| x.end_with?("/rubyboy/emulator_headless.rb") }) + +# A count of 500 produces results similar to our optcarrot benchmark. +# It's possible there is a number that produces a consistent benchmark without +# needing to re-initialize but not sure how to determine that. +count = 500 + +run_benchmark(200) do + # Results are much more consistent if we re-initialize each time. + # Reusing the same eumlator increases stddev by 65x. + emulator = Rubyboy::EmulatorHeadless.new(rom_path) + count.times do + emulator.step + end +end