Skip to content

Encoder: write the key of a map of strings by the opcode of the map entry - #641

Merged
goccy merged 1 commit into
masterfrom
perf/encoder-map-string-key
Sep 22, 2026
Merged

goccy merged 1 commit into
masterfrom
perf/encoder-map-string-key

Conversation

@goccy

@goccy goccy commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

An entry of a map was four opcodes: OpMapKey gave the key to the opcode of the key, which wrote it, OpMapValue gave the value to the opcode of the value, which wrote it, and OpMapKey again. For a map whose key is a plain string (not a pointer, not json.Number, no marshaler), OpMapKey writes the key itself and gives the value to its opcode: two dispatches per entry are saved. The header begins the first entry the same way, by falling through to OpMapKey with the next opcode and the flags of one.

A key of another kind is still written by its opcode, followed by OpMapValue, so the VM's code for them is unchanged.

TestEncodeMapKeys compares maps of every kind of a key, nested and in structs, sorted and with an indent, against encoding/json; TestEncodeMapUnordered checks the unsorted option.

Results (CI)

Encode_MapInterface vs master: -4.6% (EPYC 9V74 runner), -5.9% (A/B against the parent commit on the EPYC 9V45 runner). The other benchmarks are within the noise (the A/B shows LargeStructCached +6% on one runner and +0.7% on the other; the struct opcodes are unchanged).

Against sonic on the EPYC 9V45, with SONIC_MAX_INLINE_DEPTH=10:

go-json sonic
MapInterface, unordered (go-json UnorderedMap vs sonic default) 246.5 253.6 -2.5%
MapInterface, sorted (go-json default vs sonic ConfigStd) 293.0 342.7 -14.5%

With this, every benchmark of the comparison is at or below sonic's best configuration on that runner (LargeStructCached +3%, within its noise).

Test plan

  • go test ./... on arm64 and amd64, make lint
  • CI benchmark comparison vs master and vs sonic

🤖 Generated with Claude Code

An entry of a map was four opcodes: OpMapKey gave the key to the opcode
of the key, which wrote it, OpMapValue gave the value to the opcode of
the value, which wrote it, and OpMapKey again. For a map whose key is a
plain string, which most of the maps are, OpMapKey writes the key itself
and gives the value to its opcode: two dispatches per entry are saved.
The header begins the first entry the same way, by falling through to
OpMapKey with the next opcode and the flags of one.

A key of another kind is still written by its opcode, followed by
OpMapValue, so that the code of the VM stays as it was for them.

arm64: MapInterface 217 -> 214 ns sorted, 183 -> 176 ns unordered.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.74%. Comparing base (29cb5ef) to head (e9b1718).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #641      +/-   ##
==========================================
+ Coverage   81.69%   81.74%   +0.04%     
==========================================
  Files          59       59              
  Lines       10745    10774      +29     
==========================================
+ Hits         8778     8807      +29     
  Misses       1967     1967              
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@goccy
goccy marked this pull request as ready for review September 22, 2026 10:41
@goccy
goccy merged commit d19bdb0 into master Sep 22, 2026
14 checks passed
@goccy
goccy deleted the perf/encoder-map-string-key branch September 22, 2026 11:13
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.

2 participants