Skip to content

[generator.c] Mark ensure_valid_encoding as ALWAYS_INLINE.#975

Merged
byroot merged 1 commit intoruby:masterfrom
samyron:sm/lift-valid_json_string_p
Apr 20, 2026
Merged

[generator.c] Mark ensure_valid_encoding as ALWAYS_INLINE.#975
byroot merged 1 commit intoruby:masterfrom
samyron:sm/lift-valid_json_string_p

Conversation

@samyron
Copy link
Copy Markdown
Contributor

@samyron samyron commented Apr 20, 2026

This PR forces ensure_valid_encoding to be inlined.

Saving the functional call overhead seems to provide a decent speedup in some of the realworld benchmarks.

Benchmarks

Benchmarks run on an M1 Macbook Air.

Compiled with:

 % cc -v
Apple clang version 17.0.0 (clang-1700.0.13.3)
Target: arm64-apple-darwin24.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
== Encoding activitypub.json (52595 bytes)
ruby 3.4.8 (2025-12-17 revision 995b59f666) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
               after     2.894k i/100ms
Calculating -------------------------------------
               after     30.089k (± 2.0%) i/s   (33.24 μs/i) -    150.488k in   5.003480s

Comparison:
              before:    29256.1 i/s
               after:    30088.5 i/s - same-ish: difference falls within error


== Encoding citm_catalog.json (500298 bytes)
ruby 3.4.8 (2025-12-17 revision 995b59f666) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
               after   150.000 i/100ms
Calculating -------------------------------------
               after      1.494k (± 1.0%) i/s  (669.39 μs/i) -      7.500k in   5.020958s

Comparison:
              before:     1424.5 i/s
               after:     1493.9 i/s - 1.05x  faster


== Encoding twitter.json (466906 bytes)
ruby 3.4.8 (2025-12-17 revision 995b59f666) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
               after   314.000 i/100ms
Calculating -------------------------------------
               after      3.153k (± 1.6%) i/s  (317.16 μs/i) -     16.014k in   5.080214s

Comparison:
              before:     3027.7 i/s
               after:     3153.0 i/s - 1.04x  faster


== Encoding ohai.json (20145 bytes)
ruby 3.4.8 (2025-12-17 revision 995b59f666) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
               after     3.976k i/100ms
Calculating -------------------------------------
               after     39.558k (± 1.4%) i/s   (25.28 μs/i) -    198.800k in   5.026466s

Comparison:
              before:    38107.3 i/s
               after:    39558.4 i/s - 1.04x  faster

@byroot
Copy link
Copy Markdown
Member

byroot commented Apr 20, 2026

Could we achieve the same with force-inline instead?

@samyron
Copy link
Copy Markdown
Contributor Author

samyron commented Apr 20, 2026

Could we achieve the same with force-inline instead?

Admittedly I didn't try that, I was trying to be surgical. However... good question, so I tried it now. Looks like the answer is "yes".

I'm not sure if this is random variation in benchmarks or if that's actually even better... I'll take it either way. I'll push that update in a second...

Edit: Done.

== Encoding activitypub.json (52595 bytes)
ruby 3.4.8 (2025-12-17 revision 995b59f666) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
               after     3.031k i/100ms
Calculating -------------------------------------
               after     30.610k (± 2.4%) i/s   (32.67 μs/i) -    154.581k in   5.053074s

Comparison:
              before:    29423.4 i/s
               after:    30610.2 i/s - 1.04x  faster


== Encoding citm_catalog.json (500298 bytes)
ruby 3.4.8 (2025-12-17 revision 995b59f666) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
               after   151.000 i/100ms
Calculating -------------------------------------
               after      1.502k (± 1.8%) i/s  (665.80 μs/i) -      7.550k in   5.028440s

Comparison:
              before:     1434.0 i/s
               after:     1501.9 i/s - 1.05x  faster


== Encoding twitter.json (466906 bytes)
ruby 3.4.8 (2025-12-17 revision 995b59f666) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
               after   306.000 i/100ms
Calculating -------------------------------------
               after      3.198k (± 1.4%) i/s  (312.70 μs/i) -     16.218k in   5.072481s

Comparison:
              before:     3038.3 i/s
               after:     3197.9 i/s - 1.05x  faster


== Encoding ohai.json (20145 bytes)
ruby 3.4.8 (2025-12-17 revision 995b59f666) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
               after     3.996k i/100ms
Calculating -------------------------------------
               after     40.035k (± 2.8%) i/s   (24.98 μs/i) -    203.796k in   5.095176s

Comparison:
              before:    37413.0 i/s
               after:    40035.0 i/s - 1.07x  faster

@samyron samyron force-pushed the sm/lift-valid_json_string_p branch from 8839958 to 73320d6 Compare April 20, 2026 03:49
@samyron samyron changed the title [generator.c] Lift valid_json_string_p conditional into json_object_i. [generator.c] Mark ensure_valid_encoding as ALWAYS_INLINE. Apr 20, 2026
@byroot
Copy link
Copy Markdown
Member

byroot commented Apr 20, 2026

Admittedly I didn't try that, I was trying to be surgical.

Right. I was on my phone, so I didn't look at ensure_valid_encoding, it's bigger than I remembered.

We can probably assume that we almost never receive invalid encoding, so we definitely want to inline the check, but the rest of the function probably shouldn't.

The reason I suggested ALWAYS_INLINE is because there are other callsites that could benefit from inlining the fast check.

I'll force-push your PR to do that.

And move the encoding convertion logic in another function with NOINLINE.

The overwelming majority of strings are correctly encoded, so we
want to inline the very cheap check, however we don't want to
inline the much larger piece of code required to re-encode the string.

Co-Authored-By: Jean Boussier <jean.boussier@gmail.com>
@byroot byroot force-pushed the sm/lift-valid_json_string_p branch from 73320d6 to 2562c06 Compare April 20, 2026 04:24
@byroot
Copy link
Copy Markdown
Member

byroot commented Apr 20, 2026

Updated. Let me know what you think.

@samyron
Copy link
Copy Markdown
Contributor Author

samyron commented Apr 20, 2026

That change looks good, thank you!

I confirmed that ensure_valid_encoding inlines into json_object_i and the benchmarks are the same as above.

@byroot byroot merged commit cfbe356 into ruby:master Apr 20, 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.

2 participants