Open
Conversation
moberegger
commented
Sep 29, 2025
|
|
||
| BLANK = Blank.new | ||
| BLANK = Blank.new.freeze | ||
| EMPTY_ARRAY = [].freeze |
Contributor
Author
There was a problem hiding this comment.
There were quite a few spots allocating a new empty array when dealing with an empty collection. Figured it was worthwhile to re-use the same Array instance. This does assume that no call sites attempt to mutate the output from Jbuilder#target!.
moberegger
commented
Sep 29, 2025
Comment on lines
+243
to
+251
| if _blank?(value) | ||
| # json.comments { ... } | ||
| # { "comments": ... } | ||
| _merge_block key, &block | ||
| else | ||
| # json.comments @post.comments { |comment| ... } | ||
| # { "comments": [ { ... }, { ... } ] } | ||
| _scope { _array value, &block } | ||
| end |
Contributor
Author
There was a problem hiding this comment.
This condition used to be the inverse, with a if !_blank?. I think this improves control flow, and it saves a tiny bit in processing.
moberegger
commented
Sep 29, 2025
| if _blank?(value) | ||
| # json.comments { ... } | ||
| # { "comments": ... } | ||
| _merge_block key, &block |
Contributor
Author
There was a problem hiding this comment.
Used to be
_merge_block(key){ yield self }
moberegger
commented
Sep 29, 2025
| def call(object, *attributes, &block) | ||
| if ::Kernel.block_given? | ||
| array! object, &block | ||
| if block |
Contributor
Author
There was a problem hiding this comment.
A quick micro benchmark to show the difference between these
module Foo
def self.if_block_given?
block_given? ? true : false
end
def self.if_kernel_block_given?
::Kernel.block_given? ? true : false
end
def self.if_block?(&block)
block ? true : false
end
end
Benchmark.ips do |x|
x.report('block_given?') { Foo.if_block_given? }
x.report('Kernel.block_given?') { Foo.if_kernel_block_given? }
x.report('block?') { Foo.if_block? }
x.compare!
endruby 3.4.5 (2025-07-16 revision 20cda200d3) +YJIT +PRISM [arm64-darwin24]
Warming up --------------------------------------
block_given? 2.450M i/100ms
Kernel.block_given? 2.270M i/100ms
block? 2.516M i/100ms
Calculating -------------------------------------
block_given? 44.851M (± 1.9%) i/s (22.30 ns/i) - 225.368M in 5.026585s
Kernel.block_given? 39.434M (± 1.5%) i/s (25.36 ns/i) - 197.469M in 5.008676s
block? 45.037M (± 2.8%) i/s (22.20 ns/i) - 226.436M in 5.032194s
Comparison:
block?: 45036992.5 i/s
block_given?: 44851312.9 i/s - same-ish: difference falls within error
Kernel.block_given?: 39434092.2 i/s - 1.14x slower
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Some small adjustments to reduce latency and memory allocations on calls to
set!andarray!. A summary of changes:_extractin (link PR), private_arrayand_setmethods have been added to save on a memory allocation resulting from the extra*argssplat that would happen whenJbuilderTemplate#array!andJbuilderTemplate#set!'s called back up tosuper. With the new setup, the splat happens a single time.::Kernel.block_given?showed up as hotspots in our profiling. These have been replaced with a simpleif blockcheck, which performs a little bit faster. Normally you wouldn't see a difference withblock_given?, but sinceJbuilderis aBasicObject,::Kernel.block_given?had to be used, and the extra module resolution apparently has some overhead.one?showed up as hotspots in our profiling, which I believe is an O(n) operation. Theargs.one?guards have been removed, as they appeared to not actually be necessary. There were guards likeif args.one? && _partial_options?(options), and I presume theone?was intended to short circuit the checks against theoptionshash, but it's actually faster to just forgo theone?call. If the intent was to check if only one argument was provided, this isn't actually doing that; it is actually checking if one truthy argument was provided.Some benchmarks against
JbuilderTemplatecomparingmain(before) with this branch (after):set!The simplest benchmark to exercise the changes under
set!.Simple benchmark when
set!is provided a collection. Additionally benchmarks the underlying call to_arrayA benchmark for when
set!is provided a list of attributes. Intent here to measure theargs.one?change. Was hoping to see a larger improvement in IPS.array!A simple benchmark for
array!to exercise the changes. Was hoping for a larger improvement in IPS. This does still save on memory, though.A benchmark for when
array!is provided a list of attributes. Intent here to measure theargs.one?change. Was hoping to see a larger improvement in IPS.via
method_missingTo showcase that the optimizations impact the DSL offered via
method_missing. Not sure why there is a larger improvement here compared toset!.