BenchmarkDotNet
BenchmarkDotNet copied to clipboard
NativeAot build fails with `ValueTask` and `UniTask`
Trying to benchmark UniTask and ValueTask in NativeAot causes the build to fail. If I comment out the UniTask code, it works to benchmark ValueTask, and likewise if I comment out the ValueTask code, it works to benchmark UniTask. But if both are present, the build fails.
Code
class Program
{
static void Main(string[] args)
{
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run("--runtimes nativeaot60 --filter *".Split(' '));
}
}
public struct Struct32
{
public long l1, l2, l3, l4;
}
public class AsyncAwait
{
[Params(true, false)]
public bool Pending;
private readonly Stack<AutoResetUniTaskCompletionSource> _completionSources = new Stack<AutoResetUniTaskCompletionSource>(1);
private void ResolveSources()
{
while (_completionSources.Count > 0)
{
_completionSources.Pop().TrySetResult();
}
}
[Benchmark]
public void UniTask()
{
UniTask_ExecuteAsync().Forget();
ResolveSources();
}
private async UniTask UniTask_ExecuteAsync()
{
await UniTask_GetAndConsumeValuesAsync<Struct32, object>();
await UniTask_GetAndConsumeValuesAsync<object, Struct32>();
}
private async UniTask UniTask_GetAndConsumeValuesAsync<T1, T2>()
{
_ = await UniTask_GetValueAsync<T1>();
_ = await UniTask_GetValueAsync<T2>();
}
private async UniTask<T> UniTask_GetValueAsync<T>()
{
await GetBaseUniTask();
return default;
}
private UniTask GetBaseUniTask()
{
if (!Pending)
{
return Cysharp.Threading.Tasks.UniTask.CompletedTask;
}
var completionSource = AutoResetUniTaskCompletionSource.Create();
_completionSources.Push(completionSource);
return completionSource.Task;
}
[Benchmark]
public void ValueTask()
{
_ = ValueTask_ExecuteAsync();
ResolveSources();
}
private async ValueTask ValueTask_ExecuteAsync()
{
await ValueTask_GetAndConsumeValuesAsync<Struct32, object>();
await ValueTask_GetAndConsumeValuesAsync<object, Struct32>();
}
private async ValueTask ValueTask_GetAndConsumeValuesAsync<T1, T2>()
{
_ = await ValueTask_GetValueAsync<T1>();
_ = await ValueTask_GetValueAsync<T2>();
}
private async ValueTask<T> ValueTask_GetValueAsync<T>()
{
await GetBaseValueTask();
return default;
}
private ValueTask GetBaseValueTask()
{
if (!Pending)
{
return new ValueTask();
}
// Using UniTask as the base source since it is convertible to ValueTask without allocating.
var completionSource = AutoResetUniTaskCompletionSource.Create();
_completionSources.Push(completionSource);
return completionSource.Task;
}
}
// Build Error: Standard output:
Standard error:
Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Generating native code
EXEC : error : Failed to load type 'Cysharp.Threading.Tasks.IUniTaskSource`1' from assembly 'UniTask, Version=2.3.1.0, Culture=neutral, PublicKeyToken=7a576c6e8
fde454a' [C:\Users\Tim\source\repos\UniTaskBenchmark\bin\Release\net472\06426ff3-2141-4880-8179-04bce4183209\BenchmarkDotNet.Autogenerated.csproj]
Internal.TypeSystem.TypeSystemException+TypeLoadException: Failed to load type 'Cysharp.Threading.Tasks.IUniTaskSource`1' from assembly 'UniTask, Version=2.3.
1.0, Culture=neutral, PublicKeyToken=7a576c6e8fde454a'
at Internal.TypeSystem.ThrowHelper.ThrowTypeLoadException(ExceptionStringID id, String typeName, String assemblyName) in ILCompiler.TypeSystem.dll:token 0x
6000426+0x8
at ILCompiler.DependencyAnalysis.NodeFactory.CreateConstructedTypeNode(TypeDesc type) in ILCompiler.Compiler.dll:token 0x6000be5+0x0
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) in System.Collections.Concurrent.dll:token 0x60000d3+0x4f
at ILCompiler.DependencyAnalysis.TentativeInstanceMethodNode.GetConditionalStaticDependencies(NodeFactory factory) in ILCompiler.Compiler.dll:token 0x60007
17+0x2f
at ILCompiler.DependencyAnalysisFramework.DependencyAnalyzer`2.GetStaticDependenciesImpl(DependencyNodeCore`1 node) in ILCompiler.DependencyAnalysisFramewo
rk.dll:token 0x6000038+0x54
at ILCompiler.DependencyAnalysisFramework.DependencyAnalyzer`2.GetStaticDependencies(DependencyNodeCore`1 node) in ILCompiler.DependencyAnalysisFramework.d
ll:token 0x6000039+0x8
at ILCompiler.DependencyAnalysisFramework.DependencyAnalyzer`2.ProcessMarkStack() in ILCompiler.DependencyAnalysisFramework.dll:token 0x600003a+0x2c
at ILCompiler.DependencyAnalysisFramework.DependencyAnalyzer`2.ComputeMarkedNodes() in ILCompiler.DependencyAnalysisFramework.dll:token 0x600003b+0x19
at ILCompiler.ILScanner.ILCompiler.IILScanner.Scan() in ILCompiler.Compiler.dll:token 0x60002ee+0x0
at ILCompiler.Program.Run(String[] args) in ilc.dll:token 0x600010f+0xb3e
at ILCompiler.Program.Main(String[] args) in ilc.dll:token 0x6000115+0x5
C:\Users\Tim\.nuget\packages\microsoft.dotnet.ilcompiler\6.0.0-rc.1.21420.1\build\Microsoft.NETCore.Native.targets(283,5): error MSB3073: The command ""C:\Users
\Tim\.nuget\packages\runtime.win-x64.microsoft.dotnet.ilcompiler\6.0.0-rc.1.21420.1\tools\ilc" @"obj\Release\net6.0\win-x64\native\06426ff3-2141-4880-8179-04bce
4183209.ilc.rsp"" exited with code 1. [C:\Users\Tim\source\repos\UniTaskBenchmark\bin\Release\net472\06426ff3-2141-4880-8179-04bce4183209\BenchmarkDotNet.Autoge
nerated.csproj]
// BenchmarkDotNet has failed to build the auto-generated boilerplate code.
// It can be found in C:\Users\Tim\source\repos\UniTaskBenchmark\bin\Release\net472\06426ff3-2141-4880-8179-04bce4183209
// Please follow the troubleshooting guide: https://benchmarkdotnet.org/articles/guides/troubleshooting.html
I thought that #2012 might fix it (since UniTask depends on a higher version of System.Threading.Tasks.Extensions), but I tried with those changes and it still fails.
bin\Release\net472\
What is the target framework moniker of this project? Could you please upload the project file as well?
<TargetFrameworks>net6.0;net472</TargetFrameworks> I tried the root project build in both, and got the same failure.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net472;net6.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="UniTask" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Documents\git\BenchmarkDotNet_net6\src\BenchmarkDotNet\BenchmarkDotNet.csproj" />
</ItemGroup>
</Project>
(I referenced a local clone for the #2012 changes.)