Skip to content

[StaticWebAssets] Cleanup ApplyCompressionNegotiation.cs and ResolveCompressedAssets.cs #48082

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

Merged
merged 5 commits into from
Apr 22, 2025

Conversation

javiercn
Copy link
Member

@javiercn javiercn commented Apr 1, 2025

  • Removes LINQ usages.
  • Avoids excessive array amortization.
  • Reduces allocations

@ghost ghost added Area-AspNetCore RazorSDK, BlazorWebAssemblySDK, dotnet-watch untriaged Request triage from a team member labels Apr 1, 2025
Copy link
Contributor

Thanks for your PR, @@javiercn.
To learn about the PR process and branching schedule of this repo, please take a look at the SDK PR Guide.

@javiercn javiercn changed the base branch from javiercn/reuse-original-task-item-for-unmodified-assets-and-endpoints to main April 1, 2025 19:43
@javiercn javiercn force-pushed the javiercn/more-cleanups branch from 4c1beb7 to 9e1de78 Compare April 4, 2025 09:39
@@ -115,16 +115,22 @@ public override bool Execute()
// Process the final set of candidate assets, deduplicating assets to be compressed in the same format multiple times and
// generating new a static web asset definition for each compressed item.
var formats = SplitPattern(Formats);
var assetsToCompress = new List<ITaskItem>();
var assetsToCompress = new ITaskItem[matchingCandidateAssets.Count * formats.Length];
Copy link
Member Author

Choose a reason for hiding this comment

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

Instead of creating a list and having to turn it into an array, we create an array of the max size we expect to hold and return that directly.

This takes advantage of the fact that MSBuild will ignore any item that is null when reading the outputs from a task, which save us from having to reallocate the list and convert it back into an array of contiguous elements

@javiercn javiercn changed the title Javiercn/more cleanups [StaticWebAssets] Improve allocations on ApplyCompressionNegotiation.cs and ResolveCompressedAssets.cs Apr 4, 2025
@javiercn javiercn changed the title [StaticWebAssets] Improve allocations on ApplyCompressionNegotiation.cs and ResolveCompressedAssets.cs [StaticWebAssets] Cleanup ApplyCompressionNegotiation.cs and ResolveCompressedAssets.cs Apr 4, 2025
@javiercn javiercn marked this pull request as ready for review April 4, 2025 17:00
@javiercn javiercn requested a review from a team as a code owner April 4, 2025 17:00
@javiercn javiercn requested a review from MackinnonBuck April 4, 2025 17:00
Copy link
Member

@MackinnonBuck MackinnonBuck left a comment

Choose a reason for hiding this comment

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

Looks great - just a few small things!

@@ -141,6 +141,25 @@ public StaticWebAssetEndpointProperty[] EndpointProperties

public static IEqualityComparer<StaticWebAssetEndpoint> RouteAndAssetComparer { get; } = new RouteAndAssetEqualityComparer();

internal static IDictionary<string, List<StaticWebAssetEndpoint>> ToAssetFileDictionary(ITaskItem[] candidateEndpoints)
{
var result = new Dictionary<string, List<StaticWebAssetEndpoint>>(candidateEndpoints.Length / 2);
Copy link
Member

Choose a reason for hiding this comment

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

Why the / 2? I'm guessing it's because we expect there to be multiple endpoints per asset file, but why 2 specifically? Do we know that will give us a conservative upper bound for the number of entries?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, this is because for a given file there is the fingerprinted endpoint and the non-fingerprinted endpoint. For compressed files there's also the versions that have the encoding selector, so when we are grouping them, we are going to have a few less than half of them.


var preservedEndpoints = new Dictionary<(string, string), StaticWebAssetEndpoint>();
var compressionHeadersByEncoding = new Dictionary<string, StaticWebAssetEndpointResponseHeader[]>(2);
Copy link
Member

Choose a reason for hiding this comment

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

Is 2 the expected maximum capacity? If so, might a dictionary be overkill instead of, e.g., a fixed-size buffer and linear search?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's fair, but the main goal here was to remove the allocations. We can do a further pass in the future if needed

],
EndpointProperties = relatedEndpointCandidate.EndpointProperties
};
var headers = new List<StaticWebAssetEndpointResponseHeader>(7);
Copy link
Member

Choose a reason for hiding this comment

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

Why 7? How would we know when to update this in the future?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's the number of headers we add at most by default.

@javiercn javiercn force-pushed the javiercn/more-cleanups branch from ac3e381 to 829e3e3 Compare April 22, 2025 09:54
@javiercn javiercn enabled auto-merge (squash) April 22, 2025 10:42
@javiercn javiercn merged commit fc7f6e8 into main Apr 22, 2025
39 checks passed
@javiercn javiercn deleted the javiercn/more-cleanups branch April 22, 2025 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-AspNetCore RazorSDK, BlazorWebAssemblySDK, dotnet-watch untriaged Request triage from a team member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants