Skip to content

Conversation

@etki
Copy link
Contributor

@etki etki commented Apr 26, 2025

Hey. This is a very small and simple PR aimed at a tiny performance improvement: currently, the .getTags() call always allocates a zero-sized array list and then uses a .forEach call (which results in allocating another object for lambda, and, in the worst case, non-inlined call) to populate it. PR checks if list is needed at all, and if so, asks for a list with a space for 32 elements, populating it in a classic loop. The number of 32 is only a guess with no real grounds.

This is definitely not the biggest problem around, so the change is perceptible, yet not a game changer.

Benchmarks from #6174 and Intel N100 fixed at 2GHz were used to estimate the impact. The benchmark uses identifiers with 0-64 tags, where the number of tags in the mode column occurs 90% of time, and other values are distributed evenly in the remaining space.

mode version ns/op instructions/op
0 main 43.379 ± 0.056 284.221
0 PR 44.352 ± 0.782 263.863
1 main 71.544 ± 0.188 499.757
1 PR 65.575 ± 0.480 397.938
2 main 81.493 ± 0.704 567.298
2 PR 72.908 ± 1.048 456.693
4 main 92.932 ± 0.451 669.917
4 PR 82.054 ± 1.028 552.133
8 main 120.026 ± 1.511 879.752
8 PR 104.113 ± 1.794 742.707
16 main 209.666 ± 2.159 1532.392
16 PR 143.756 ± 3.422 995.800
32 main 345.139 ± 3.130 2525.301
32 PR 244.574 ± 7.125 1921.113
64 main 618.301 ± 6.336 4458.226
64 PR 496.224 ± 14.074 3775.938

Please note that some improvements suggested in #6113 (using Collections.unmodifiableList(Arrays.asList(...).subList(...) or even creating a custom List implementation that would combine all the three) will likely bring these numbers down to tens of ns per call on arrays of any length and make this PR completely redundant.

public List<Tag> getTags() {
List<Tag> tags = new ArrayList<>();
this.tags.forEach(tags::add);
if (this.tags == Tags.empty()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to explicitly check for zero length, as it's possible to construct another instance with zero tags, but we don't have that API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth adding API for size/length to Tags. Given this is in the same package, we can make it package private. We could consider separately whether to make it public API if there's good justification for it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's possible to construct another instance with zero tags

I'd also note it's not possible with public API, so as long as we don't inadvertently do it, we shouldn't need to worry about that case.

@etki etki force-pushed the meter-get-tags-performance-improvement branch from 674a6e4 to b3fa190 Compare April 26, 2025 08:29
@jonatan-ivanov jonatan-ivanov added the performance Issues related to general performance label Apr 28, 2025
Copy link
Member

@shakuzen shakuzen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the PR with adding a package-private size method on Tags so we can exactly size the ArrayList instead of guessing. Feel free to run the benchmarks again if you have spare time and desire, but I think it's safe to say it should strictly be better this way.

We also have use for the size() API for similar improvement in DefaultMeterObservationHandler#createTags (there it would be on KeyValues), but I'll defer considering a change that requires making a new public method to outside this PR so we don't block these changes from being merged.

@shakuzen shakuzen added enhancement A general enhancement module: micrometer-core An issue that is related to our core module labels Jun 4, 2025
@shakuzen shakuzen added this to the 1.16.0-M1 milestone Jun 4, 2025
@shakuzen shakuzen merged commit 1d62cef into micrometer-metrics:main Jun 4, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement A general enhancement module: micrometer-core An issue that is related to our core module performance Issues related to general performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants