Skip to content

Conversation

WanjohiSammy
Copy link
Member

@WanjohiSammy WanjohiSammy commented Sep 24, 2025

Issues

This pull request fixes #3352.

Description

Trying to eliminate string allocations where possible using ReadOnlySpan and String interning

Benchmark

1. Before

image

2. After

image

Benchmark project

/WanjohiSammy/ODataJsonReaderBenchmarks-3

Input data:
https://github.com/WanjohiSammy/ODataJsonReaderBenchmarks-3/blob/main/ODataJsonReaderBenchmarks/SamplePayloadWithValues.json

Checklist (Uncheck if it is not completed)

  • Test cases added
  • Build and test with one-click build and test script passed

Additional work necessary

If documentation update is needed, please add "Docs Needed" label to the issue and provide details about the required document change in the issue.

Repository notes

Team members can start a CI build by adding a comment with the text /AzurePipelines run to a PR. A bot may respond indicating that there is no pipeline associated with the pull request. This can be ignored if the build is triggered.

Team members should not trigger a build this way for pull requests coming from forked repositories. They should instead trigger the build manually by setting the "branch" to refs/pull/{prId}/merge where {prId} is the ID of the PR.

@WanjohiSammy WanjohiSammy force-pushed the fix/eliminate-avoidable-string-allocations-jsonreader branch from 106d285 to 25dc33e Compare September 24, 2025 17:06
break;

case 3: // url, @id
if (Is(span, ODataJsonConstants.ODataServiceDocumentElementUrlName))
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we care about case sensitivity in this case?

Copy link
Member Author

Choose a reason for hiding this comment

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

Since we are checking the word or string as it comes, we just need to maintain case sensitivity.

@WanjohiSammy WanjohiSammy changed the title pef: Optimize JsonReader for high-frequency usage with reduced allocations perf: Reduce memory allocations using ReadOnlySpan and String interning Sep 24, 2025
{
switch (span.Length)
{
case 2: // id, Id
Copy link
Contributor

Choose a reason for hiding this comment

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

I like the idea of this method, to avoid allocating strings from a span for common values (it doesn't seem limited to properties as the name of the methods suggest). I like that we check the length, so it's cheap to find the suitable bucket.

My concern is around the cases where we have length >= 5 and multiple candidates in the same block. This means we may have to do multiple string comparisons. I guess the obvious optimization here is to make sure that the most likely string candidate appears first in the if statement. Of course this can vary from one service to another. How are we sure this is optimal. I'd like to see what the cost of value of length 5+ is when it's not one of the list candidates (meaning that we would have to compare all candidates, i.e 9 * 5 = 45 characters) each time then fall back. I would like to compare the cost of doing that vs creating the string directly.

Another option would be to create static hashset of common words longer than some threshold (e.g. >= 5), the threshold can be picked by experimentation. Then do a lookup in the hashset and compare the cost of doing that to the cost of comparing all items. Not sure which would be faster. Could be worth the experiment, especially if this method is called each time we want to convert a span to a string. We could also try to replace the hashset with a simpler hash-based datastructure.

@WanjohiSammy WanjohiSammy force-pushed the fix/eliminate-avoidable-string-allocations-jsonreader branch 2 times, most recently from bb23156 to e0ca212 Compare September 25, 2025 08:07
@WanjohiSammy
Copy link
Member Author

/AzurePipelines run

Copy link

No pipelines are associated with this pull request.

@WanjohiSammy WanjohiSammy marked this pull request as ready for review September 26, 2025 08:44
xuzhg
xuzhg previously approved these changes Oct 2, 2025
@WanjohiSammy WanjohiSammy force-pushed the fix/eliminate-avoidable-string-allocations-jsonreader branch from d655931 to e21801c Compare October 6, 2025 21:55
@WanjohiSammy
Copy link
Member Author

/AzurePipelines run

@WanjohiSammy WanjohiSammy force-pushed the fix/eliminate-avoidable-string-allocations-jsonreader branch from b238c80 to 55e24ea Compare October 9, 2025 13:59
@WanjohiSammy
Copy link
Member Author

/AzurePipelines run

@WanjohiSammy WanjohiSammy requested a review from habbes October 9, 2025 14:00
xuzhg
xuzhg previously approved these changes Oct 9, 2025
@WanjohiSammy WanjohiSammy force-pushed the fix/eliminate-avoidable-string-allocations-jsonreader branch from 55e24ea to df0c7c6 Compare October 11, 2025 07:10
@WanjohiSammy WanjohiSammy force-pushed the fix/eliminate-avoidable-string-allocations-jsonreader branch from df0c7c6 to b2b13d6 Compare October 11, 2025 07:10
@WanjohiSammy
Copy link
Member Author

/AzurePipelines run

@WanjohiSammy WanjohiSammy requested review from xuzhg October 14, 2025 08:37
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.

Eliminate avoidable string allocations in JsonReader when parsing common property names

3 participants