Skip to content

Switch ItemBucket to be a struct #12148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Erarndt
Copy link
Contributor

@Erarndt Erarndt commented Jul 10, 2025

Fixes #

Context

The ItemBucket type is currently a class that gets allocated fairly frequently, added to collections, and passed around. Otherwise, the class is fairly a straightforward container of a handful of items. Switching it to a struct would avoid the heap allocations here.

Before:

image

After:

image

Some things to note about the changes:

I needed to switch to having ItemBucket implement the generic IComparable<T> to avoid boxing the struct.

A class is the size of a pointer and structs can vary in size depending on how many fields are in the struct. This is why there is an increase in the ItemBucket[] allocations that back the List<ItemBucket>.

To reduce the number of ItemBucket[] allocations, I reduced the number of times we need to resize by utilizing EnsureCapacity(). While newer .NET code has this, I had to create an extension function for Framework.

There was an additional List<ItemBucket> that was being allocated just to sort the buckets in BucketSequenceNumber. We can do this in place to avoid the allocation.

Changes Made

Testing

Notes

@Copilot Copilot AI review requested due to automatic review settings July 10, 2025 18:11
Copy link
Contributor

@Copilot 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

Switches ItemBucket from a heap-allocated class to a value-type struct (with IComparable<T>) to eliminate boxing and reduce allocations, adds a .NET-Framework List<T>.EnsureCapacity extension to minimize list resizes, and optimizes BucketConsumedItems to preallocate and reorder in place.

  • Added EnsureCapacity<T> extension in Utilities.cs for .NET Framework.
  • Converted ItemBucket to a struct and updated its comparison API.
  • Updated BatchingEngine to use EnsureCapacity and perform in-place bucket ordering.

Reviewed Changes

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

File Description
src/Build/Utilities/Utilities.cs Introduce EnsureCapacity<T> extension method for lists on non-.NET platforms.
src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs Removed null check for batchBucket now that it's a struct.
src/Build/BackEnd/Components/RequestBuilder/ItemBucket.cs Change ItemBucket from class to struct and implement IComparable<ItemBucket>.
src/Build/BackEnd/Components/RequestBuilder/BatchingEngine.cs Use EnsureCapacity, remove temporary list allocation, and implement in-place bucket swap.
Comments suppressed due to low confidence (3)

src/Build/Utilities/Utilities.cs:606

  • The summary suggests multiple doublings, but the implementation only doubles once then falls back to the requested capacity. Please clarify the doc to match the code behavior. For example, "the capacity is doubled once (or set to capacity if still smaller)".
        /// the capacity is increased by continuously twice current capacity until it is at least the specified <paramref name="capacity"/>.

src/Build/BackEnd/Components/RequestBuilder/BatchingEngine.cs:372

  • [nitpick] This in-place swapping algorithm is nontrivial; consider adding a unit test to verify that buckets end up correctly ordered for various initial sequences and edge cases.
            for (int i = 0; i < buckets.Count;)

src/Build/BackEnd/Components/RequestBuilder/BatchingEngine.cs:11

  • To bring the EnsureCapacity<T> extension into scope, you may need to add the namespace that contains Utilities (e.g. using Microsoft.Build.Utilities;). Otherwise the extension method won't be discovered.
using Microsoft.Build.Internal;

@Erarndt Erarndt changed the title Dev/erarndt/item bucket Switch ItemBucket to be a struct Jul 10, 2025
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.

1 participant