From 31334b5caeba73765f1db590ebcf881b44a6f89c Mon Sep 17 00:00:00 2001 From: NAITOH Jun Date: Fri, 5 Jan 2024 09:51:47 +0900 Subject: [PATCH] Add parse benchmark --- .github/workflows/benchmark.yml | 29 ++++++++++++++++++ Rakefile | 39 ++++++++++++++++++++++++ benchmark/parse.yaml | 53 +++++++++++++++++++++++++++++++++ rexml.gemspec | 1 + 4 files changed, 122 insertions(+) create mode 100644 .github/workflows/benchmark.yml create mode 100644 benchmark/parse.yaml diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 00000000..52349b44 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,29 @@ +name: Benchmark + +on: + - push + - pull_request + +jobs: + benchmark: + name: "Benchmark: Ruby ${{ matrix.ruby-version }}: ${{ matrix.runs-on }}" + strategy: + fail-fast: false + matrix: + ruby-version: + - '3.3' + runs-on: + - ubuntu-latest + runs-on: ${{ matrix.runs-on }} + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + - name: Install dependencies + run: | + bundle install + gem install rexml -v 3.2.6 + - name: Benchmark + run: | + rake benchmark diff --git a/Rakefile b/Rakefile index 7143e754..ffdbccdb 100644 --- a/Rakefile +++ b/Rakefile @@ -28,3 +28,42 @@ RDoc::Task.new do |rdoc| end load "#{__dir__}/tasks/tocs.rake" + +benchmark_tasks = [] +namespace :benchmark do + Dir.glob("benchmark/*.yaml").sort.each do |yaml| + name = File.basename(yaml, ".*") + env = { + "RUBYLIB" => nil, + "BUNDLER_ORIG_RUBYLIB" => nil, + } + command_line = [ + RbConfig.ruby, "-v", "-S", "benchmark-driver", File.expand_path(yaml), + ] + + desc "Run #{name} benchmark" + task name do + puts("```") + sh(env, *command_line) + puts("```") + end + benchmark_tasks << "benchmark:#{name}" + + case name + when /\Aparse/, "shift" + namespace name do + desc "Run #{name} benchmark: small" + task :small do + puts("```") + sh(env.merge("N_LINES" => "1000", "N_ATTRIBUTES" => "2"), + *command_line) + puts("```") + end + benchmark_tasks << "benchmark:#{name}:small" + end + end + end +end + +desc "Run all benchmarks" +task :benchmark => benchmark_tasks diff --git a/benchmark/parse.yaml b/benchmark/parse.yaml new file mode 100644 index 00000000..48c4fdcc --- /dev/null +++ b/benchmark/parse.yaml @@ -0,0 +1,53 @@ +loop_count: 100 +contexts: + - gems: + rexml: 3.2.6 + require: false + prelude: require 'rexml' + - name: 3.2.6(YJIT) + gems: + rexml: 3.2.6 + require: false + prelude: | + require 'rexml' + RubyVM::YJIT.enable + - name: master + prelude: | + $LOAD_PATH.unshift(File.expand_path("lib")) + require 'rexml' + - name: master(YJIT) + prelude: | + $LOAD_PATH.unshift(File.expand_path("lib")) + require 'rexml' + RubyVM::YJIT.enable + +prelude: | + require 'rexml/document' + require 'rexml/parsers/sax2parser' + require 'rexml/parsers/pullparser' + require 'rexml/parsers/streamparser' + require 'rexml/streamlistener' + + n_lines = Integer(ENV.fetch("N_LINES", "10000"), 10) + n_attributes = Integer(ENV.fetch("N_ATTRIBUTES", "10"), 10) + + def build_xml(n_lines, n_attributes) + xml = '' + n_lines.times do |i| + xml << '' + end + xml << '' + end + xml = build_xml(n_lines, n_attributes) + + class Listener + include REXML::StreamListener + end + +benchmark: + 'dom' : REXML::Document.new(xml).elements.each("root/child") {|_|} + 'sax' : REXML::Parsers::SAX2Parser.new(xml).parse + 'pull' : p = REXML::Parsers::PullParser.new(xml); while p.has_next?; res = p.pull; end + 'stream' : REXML::Parsers::StreamParser.new(xml, Listener.new).parse diff --git a/rexml.gemspec b/rexml.gemspec index ceb77047..9a54609c 100644 --- a/rexml.gemspec +++ b/rexml.gemspec @@ -57,5 +57,6 @@ Gem::Specification.new do |spec| spec.add_development_dependency "bundler" spec.add_development_dependency "rake" + spec.add_development_dependency "benchmark_driver" spec.add_development_dependency "test-unit" end