-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Open
Labels
Area-CompilersCode Gen QualityRoom for improvement in the quality of the compiler's generated codeRoom for improvement in the quality of the compiler's generated codeFeature Request
Milestone
Description
Version Used:
.NET Command Line Tools (2.0.0-preview1-005805)
Product Information:
Version: 2.0.0-preview1-005805
Commit SHA-1 hash: 78868ad33a
Runtime Environment:
OS Name: Windows
OS Version: 10.0.16179
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\2.0.0-preview1-005805\
Microsoft .NET Core Shared Framework Host
Version : 2.0.0-preview1-002021-00
Build : e9456614cfe65b6dc7c5326a597337159142c84c
Steps to Reproduce:
https://github.com/benaadams/Issues/tree/master/LocalFunctionAllocations
Pass via params: No allocations
public ValueTask<int> GetTotalQuantityAsync()
{
{
int total = 0;
for (int i = 0; i < Orders.Count; i++)
{
var task = Orders[i].GetOrderQuantityAsync();
if (!task.IsCompletedSuccessfully) return Awaited(task, total, i);
total += task.Result;
}
return new ValueTask<int>(total);
}
async ValueTask<int> Awaited(ValueTask<int> task, int total, int i)
{
total += await task;
for (i++; i < Orders.Count; i++)
{
task = Orders[i].GetOrderQuantityAsync();
total += (task.IsCompletedSuccessfully) ? task.Result : await task;
}
return total;
}
}Pass via locals: Allocations (even when Local function is never called)
public ValueTask<int> GetTotalQuantityLocalsAsync()
{
int total = 0;
int i = 0;
ValueTask<int> task;
for (; i < Orders.Count; i++)
{
task = Orders[i].GetOrderQuantityLocalsAsync();
if (!task.IsCompletedSuccessfully) return Awaited();
total += task.Result;
}
return new ValueTask<int>(total);
async ValueTask<int> Awaited()
{
total += await task;
for (i++; i < Orders.Count; i++)
{
task = Orders[i].GetOrderQuantityLocalsAsync();
total += (task.IsCompletedSuccessfully) ? task.Result : await task;
}
return total;
}
}Expected Behavior:
No allocations
Actual Behavior:
2.45 kB of allocations (and performance impact)
Method | Mean | StdDev | Op/s | Scaled | Allocated |
------------------------------------- |--------------:|-----------:|-----------:|-------:|----------:|
Sync | 599.9187 ns | 2.1857 ns | 1666892.40 | 1.00 | 0 kB |
'ValueTask + Local Async via Params' | 668.2087 ns | 4.8867 ns | 1496538.39 | 1.11 | 0 kB |
'ValueTask + Local Async via Locals' | 1,525.9064 ns | 9.9561 ns | 655348.19 | 2.54 | 2.45 kB |
'ValueTask Pure Async' | 5,606.6241 ns | 18.2806 ns | 178360.45 | 9.35 | 0 kB |
The ValueTask path is pretty close to the sync path when passing to the local function async fallback via params; but not when using locals; even though the fallback is never used.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Area-CompilersCode Gen QualityRoom for improvement in the quality of the compiler's generated codeRoom for improvement in the quality of the compiler's generated codeFeature Request