Skip to content

Conversation

@KenitoInc
Copy link
Contributor

@KenitoInc KenitoInc commented Dec 2, 2025

Issues

*This pull request fixes #3434 *

Description

  • Eliminate unnecessary allocations, such as avoiding async state machine initialization when operations complete synchronously.
  • Leverage ValueTask where appropriate to reduce GC pressure.
<style> </style>
Method Job Server PayloadVariant Mean Error StdDev Min Max P95 Ratio RatioSD Completed Work Items Lock Contentions Gen0 Gen1 Allocated Alloc Ratio
------------------ ---------------------------------------------------- ------- --------------- ---------: --------: --------: ---------: ---------: ---------: ------: --------: ---------------------: -----------------: --------: -------: ----------: ------------:
ReadDeltaAsync_V0 Runtime=.NET 8.0, IterationCount=30, WarmupCount=10 False Delta 161.0 us 4.09 us 5.87 us 149.4 us 174.5 us 171.2 us 1 0.05 2.0044 0.0054 11.2305 1.9531 138.49 KB 1
ReadDeltaAsync_V1 Runtime=.NET 8.0, IterationCount=30, WarmupCount=10 False Delta 164.8 us 6.44 us 9.24 us 148.7 us 186.4 us 181.2 us 1.02 0.07 2.0024 0.0068 11.2305 1.9531 138.42 KB 1
                                   
ReadDeltaAsync_V0 ServerGC True Delta 157.6 us 2.05 us 3.01 us 153.2 us 165.0 us 162.9 us 1 0.03 2.0005 0.001 - - 138.49 KB 1
ReadDeltaAsync_V1 ServerGC True Delta 146.3 us 1.52 us 2.18 us 143.2 us 151.3 us 150.2 us 0.93 0.02 2 0.0029 - - 138.42 KB 1
<style> </style>
Method Job Server PayloadVariant Mean Error StdDev Median Min Max P95 Ratio RatioSD Completed Work Items Lock Contentions Gen0 Gen1 Gen2 Allocated Alloc Ratio
------------- ---------------------------------------------------- ------- --------------- ------------: ------------: ------------: ------------: ------------: ------------: ------------: ------: --------: ---------------------: -----------------: ----------: ----------: --------: ------------: ------------:
ReadAsync_V0 Runtime=.NET 8.0, IterationCount=30, WarmupCount=10 False Base 580.1 us 5.41 us 7.92 us 579.9 us 564.4 us 596.6 us 590.6 us 1 0.02 6.0059 0.0029 36.1328 9.7656 - 449.8 KB 1
ReadAsync_V1 Runtime=.NET 8.0, IterationCount=30, WarmupCount=10 False Base 489.0 us 10.34 us 15.15 us 485.5 us 468.5 us 523.0 us 519.0 us 0.84 0.03 6.0039 0.002 36.1328 10.7422 - 448 KB 1
                                       
ReadAsync_V0 ServerGC True Base 502.8 us 6.46 us 8.62 us 500.4 us 490.5 us 518.5 us 517.9 us 1 0.02 6.0049 0.0088 0.9766 - - 448.59 KB 1
ReadAsync_V1 ServerGC True Base 553.7 us 24.19 us 36.21 us 573.2 us 499.0 us 600.2 us 593.9 us 1.1 0.07 6.002 0.0049 0.9766 - - 447.69 KB 1
                                       
ReadAsync_V0 Runtime=.NET 8.0, IterationCount=30, WarmupCount=10 False Large 21,056.3 us 388.51 us 581.51 us 20,816.5 us 20,359.5 us 22,431.3 us 22,060.3 us 1 0.04 227 - 1593.75 1000 31.25 19603.83 KB 1
ReadAsync_V1 Runtime=.NET 8.0, IterationCount=30, WarmupCount=10 False Large 21,107.5 us 286.68 us 429.09 us 21,142.8 us 20,301.6 us 21,941.1 us 21,779.6 us 1 0.03 227.0313 - 1593.75 1000 62.5 19566.76 KB 1
                                       
ReadAsync_V0 ServerGC True Large 19,490.5 us 198.80 us 297.55 us 19,443.7 us 19,036.0 us 20,156.5 us 20,048.6 us 1 0.02 227.0313 - 31.25 - - 19599.65 KB 1
ReadAsync_V1 ServerGC True Large 23,718.7 us 2,919.87 us 4,187.59 us 21,451.5 us 20,599.1 us 36,722.4 us 30,782.9 us 1.22 0.21 227.1875 - 31.25 - - 19562.26 KB 1
                                       
ReadAsync_V0 Runtime=.NET 8.0, IterationCount=30, WarmupCount=10 False EscapedHeavy 1,484.2 us 126.39 us 185.26 us 1,550.5 us 1,086.6 us 1,823.9 us 1,731.1 us 1.02 0.19 16 0.0078 62.5 19.5313 - 808.52 KB 1
ReadAsync_V1 Runtime=.NET 8.0, IterationCount=30, WarmupCount=10 False EscapedHeavy 1,254.1 us 71.96 us 107.71 us 1,281.3 us 1,046.3 us 1,409.2 us 1,388.9 us 0.86 0.14 16.0156 0.002 64.4531 19.5313 - 807.97 KB 1
                                       
ReadAsync_V0 ServerGC True EscapedHeavy 1,436.5 us 107.32 us 160.63 us 1,505.7 us 1,170.8 us 1,643.5 us 1,616.0 us 1.01 0.16 16.0137 0.0039 1.9531 - - 808.58 KB 1
ReadAsync_V1 ServerGC True EscapedHeavy 1,209.0 us 171.41 us 256.56 us 1,083.7 us 914.1 us 1,610.0 us 1,597.4 us 0.85 0.21 16.0078 0.0039 - - - 807.95 KB 1

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.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements performance optimizations for ODataJsonResourceDeserializer by converting several async methods from Task to ValueTask return types and implementing synchronous fast-path optimizations using IsCompletedSuccessfully checks to avoid async state machine overhead when operations complete synchronously.

Key Changes:

  • Converted return types from Task/Task<T> to ValueTask/ValueTask<T> for several methods
  • Added synchronous fast-path checks using IsCompletedSuccessfully to avoid async overhead
  • Refactored async paths into local static helper functions

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 11 comments.

File Description
src/Microsoft.OData.Core/Json/ODataJsonResourceDeserializer.cs Refactored multiple async methods to use ValueTask and added synchronous fast-path optimizations with IsCompletedSuccessfully checks
test/UnitTests/Microsoft.OData.Core.Tests/Json/ODataJsonResourceDeserializerTests.cs Added .AsTask() calls to convert ValueTask to Task for compatibility with test assertion methods

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@KenitoInc KenitoInc force-pushed the kemunga/perf-ODataJsonResourceDeserializer branch from 36bdede to 492b0ca Compare December 3, 2025 07:14
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@KenitoInc KenitoInc marked this pull request as ready for review December 3, 2025 11:08
}
catch (ODataException ex)
{
return Task.FromException<object>(ex);
Copy link
Member

Choose a reason for hiding this comment

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

To be consistency with other parts of code, this should likely be Task.FromException(ex) without the generic parameter.

Suggested change
return Task.FromException<object>(ex);
return Task.FromException(ex);

///
/// This method fills the ODataDelta(Deleted)Link.Target property if the id is found in the payload.
/// </remarks>
internal async Task ReadDeltaLinkTargetAsync(ODataDeltaLinkBase link)
Copy link
Member

Choose a reason for hiding this comment

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

why do you remove async here?

///
/// This method fills the ODataDelta(Deleted)Link.Source property if the id is found in the payload.
/// </remarks>
internal async Task ReadDeltaLinkSourceAsync(ODataDeltaLinkBase link)
Copy link
Member

Choose a reason for hiding this comment

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

We have the similar issue (change Task to use ValueTask). Do you think we should extend your PR (not just one PR) to other APIs?

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.

Refactor ODataJsonResourceDeserializer for improved performance and memory utilization

3 participants