Skip to content

Commit

Permalink
Add parse benchmark (#104)
Browse files Browse the repository at this point in the history
I want to improve the parsing process and would like to add a parsing
benchmark.

The benchmark process just parses the XML from beginning to end.

Since performance differs depending on whether YJIT is ON or OFF, both
are measured.
  • Loading branch information
naitoh authored Jan 6, 2024
1 parent 6a0dd49 commit 72a26d6
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 0 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -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
39 changes: 39 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -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/
namespace name do
desc "Run #{name} benchmark: small"
task :small do
puts("```")
sh(env.merge("N_ELEMENTS" => "500", "N_ATTRIBUTES" => "1"),
*command_line)
puts("```")
end
benchmark_tasks << "benchmark:#{name}:small"
end
end
end
end

desc "Run all benchmarks"
task :benchmark => benchmark_tasks
57 changes: 57 additions & 0 deletions benchmark/parse.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
loop_count: 100
contexts:
- gems:
rexml: 3.2.6
require: false
prelude: require 'rexml'
- name: master
prelude: |
$LOAD_PATH.unshift(File.expand_path("lib"))
require 'rexml'
- name: 3.2.6(YJIT)
gems:
rexml: 3.2.6
require: false
prelude: |
require 'rexml'
RubyVM::YJIT.enable
- 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_elements = Integer(ENV.fetch("N_ELEMENTS", "5000"), 10)
n_attributes = Integer(ENV.fetch("N_ATTRIBUTES", "2"), 10)
def build_xml(n_elements, n_attributes)
xml = '<?xml version="1.0"?><root>'
n_elements.times do |i|
xml << '<child '
n_attributes.times {|j| xml << "id#{j}=\"#{i}\" " }
xml << '/>'
end
xml << '</root>'
end
xml = build_xml(n_elements, 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' : |
parser = REXML::Parsers::PullParser.new(xml)
while parser.has_next?
parser.pull
end
'stream' : REXML::Parsers::StreamParser.new(xml, Listener.new).parse
1 change: 1 addition & 0 deletions rexml.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = '>= 2.5.0'

spec.add_development_dependency "benchmark_driver"
spec.add_development_dependency "bundler"
spec.add_development_dependency "rake"
spec.add_development_dependency "test-unit"
Expand Down

0 comments on commit 72a26d6

Please sign in to comment.