Skip to content

Guard performance with Duel benchmarks - #78

Merged
sferik merged 1 commit into
mainfrom
duel
Oct 25, 2026
Merged

sferik merged 1 commit into
mainfrom
duel

Conversation

@sferik

@sferik sferik commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

This adds Duel, a gem I wrote to catch performance regressions in CI. On every pull request it runs the benchmarks in duel/ against main and the branch side by side, and fails the build if the branch is slower or allocates more.

There are 23 benchmarks. Most of them parse documents with the shapes from benchmark.rb (shallow, deep, attribute-heavy, mixed content, namespaced) at sizes from a tiny document up to a ~55 KB catalog, plus the dasherize, symbolize, typecast, and IO paths. There's one for each backend besides Ox, and one for how long require "multi_xml" takes.

The benchmarks pin MultiXML.parser = :ox. Without that, which parser a worker used depended on which XML libraries an earlier benchmark had loaded, and the allocation counts jumped around between runs. The downside is that a change to parser auto-detection isn't covered.

To check that it actually catches things, I added an extra allocation to the SAX handler, and Duel failed exactly the libxml SAX and Nokogiri SAX benchmarks. Extra work in the Ox handler failed all 16 parse and typecast benchmarks. Comparing main with itself passed three times in a row.

I also excluded duel/ and .duel.rb from the gemspec, so they don't end up in the gem.

Duel requires Ruby 3.4, so the Gemfile only adds it on 3.4 and newer, and the Rake task is skipped when it isn't installed. Everything else still works on older Rubies.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T15:57:34.688179Z 7ddd2b2 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown

Duel: nothing to compare

duel: lib, ext unchanged since the baseline, so there's nothing to compare (--force to anyway)

Add Duel, with 23 benchmarks in duel/ that fail CI when a change makes
parsing slower: MultiXML.parse on documents from tiny to large, each
shape from benchmark.rb, the namespace, symbolize and typecast options,
an IO input, every backend other than Ox, and requiring the library.

The Perf workflow compares each pull request with main, each push with
the commit before it, and the last release on a schedule. RuboCop now
checks .duel.rb too.

Duel needs Ruby 3.4 or later, so the Gemfile and Rakefile skip it on
older Rubies.
@sferik
sferik merged commit 2822344 into main Oct 25, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant