Skip to content

perf(serialization): optimize ConcurrentObjectPool with ThreadStatic storage#10073

Open
ReubenBond wants to merge 1 commit into
dotnet:mainfrom
ReubenBond:split/threadstatic-object-pools
Open

perf(serialization): optimize ConcurrentObjectPool with ThreadStatic storage#10073
ReubenBond wants to merge 1 commit into
dotnet:mainfrom
ReubenBond:split/threadstatic-object-pools

Conversation

@ReubenBond

@ReubenBond ReubenBond commented Apr 30, 2026

Copy link
Copy Markdown
Member

Replaces ThreadLocal<T> with [ThreadStatic] storage in ConcurrentObjectPool.

Microsoft Reviewers: Open in CodeFlow

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes Orleans.Serialization’s ConcurrentObjectPool by replacing ThreadLocal<T> storage with [ThreadStatic] storage to reduce overhead in hot-path pooling used by invocation/serialization components.

Changes:

  • Replaced ThreadLocal<Stack<T>> with a [ThreadStatic] per-thread array of stacks.
  • Added per-pool-instance indexing (_poolId) to avoid state sharing across pools which may use different policies.
Show a summary per file
File Description
src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs Reworks per-thread pool storage to use [ThreadStatic] stacks indexed by pool instance id.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment on lines +19 to +43
private static int NextPoolId = -1;

private readonly int _poolId = Interlocked.Increment(ref NextPoolId);
private readonly TPoolPolicy _policy;

public ConcurrentObjectPool(TPoolPolicy policy) => _policy = policy;

public int MaxPoolSize { get; set; } = int.MaxValue;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Stack<T> GetStack()
{
var poolId = _poolId;
var stacks = PerThreadStack.Stacks;
if (stacks is null)
{
stacks = PerThreadStack.Stacks = new Stack<T>[poolId + 1];
}
else if ((uint)poolId >= (uint)stacks.Length)
{
Array.Resize(ref stacks, Math.Max(poolId + 1, stacks.Length * 2));
PerThreadStack.Stacks = stacks;
}

return stacks[poolId] ??= new();
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ReubenBond ReubenBond force-pushed the split/threadstatic-object-pools branch from 5a5c7bc to 906aef7 Compare April 30, 2026 15:34
@ReubenBond ReubenBond marked this pull request as ready for review April 30, 2026 17:50
@ReubenBond ReubenBond changed the title Optimize ConcurrentObjectPool with ThreadStatic storage perf(serialization): optimize ConcurrentObjectPool with ThreadStatic storage May 29, 2026
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