Open dotlogix opened 1 month ago
I just gave this a spin and my first thought was that this looked like the difference between Debug and Release Configurations.
When I run the standalone console application in Debug I get ~1:22 min of execution time. When I run it as Release it's sitting at ~22s.
However, even when exporting the project in Godot, it always stays at 1:22 min even when manually ticking "Optimize Code" in the csproj settings. Project was exported using the release export template.
While tracing I noticed a massive difference in call counts for TerrainVoxelGeometryLayer.Add
Console Release:
Godot (Edit: updated the screenshot as in the old one the trace did not run to completion):
I get a similar disproportionate high call count when running the standalone console as debug:
My uneducated guess is that something is messing with properly exporting the project as Release.
Edit: I'm also running this using .NET 8 as Godot just does not want to load my .NET 9 assemblies.
We don't use the Release
configuration, in the Godot.NET.Sdk we define 3 configurations: Debug
, ExportDebug
, and ExportRelease
:
Like the default Release
configuration, we set Optimize
to true when using the ExportRelease
configuration:
Can you check the binlogs to see if Optimize
was properly set to true? Also, can you check explicitly setting it to true in the Common.csproj
project? I suspect it may not be setting it because that project uses the Microsoft.NET.Sdk which won't recognize the ExportRelease
configuration.
We don't use the
Release
configuration, in the Godot.NET.Sdk we define 3 configurations:Debug
,ExportDebug
, andExportRelease
:Like the default
Release
configuration, we setOptimize
to true when using theExportRelease
configuration:Can you check the binlogs to see if
Optimize
was properly set to true? Also, can you check explicitly setting it to true in theCommon.csproj
project? I suspect it may not be setting it because that project uses the Microsoft.NET.Sdk which won't recognize theExportRelease
configuration.
That indeed fixed the issue. So I assume the whole solution is built with ExportRelease which then does not apply optimize true when building normal assemblies.
Good to know. Maybe sth which should be mentioned in the docs? I have to test what the minimal working setup is for this
That indeed does the trick. Down from ~20-30ms to just 2.5ms awesome <3 thank you so much
For other ppl just add a Directory.Build.props with this content:
<Project>
<PropertyGroup>
<Configurations>Debug;ExportDebug;ExportRelease;</Configurations>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' or '$(Configuration)' == 'ExportDebug' ">
<VersionSuffix>preview-0001</VersionSuffix>
<DebugSymbols Condition=" '$(DebugSymbols)' == '' ">true</DebugSymbols>
<Optimize Condition=" '$(Optimize)' == '' ">false</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'ExportRelease' ">
<Optimize Condition=" '$(Optimize)' == '' ">true</Optimize>
</PropertyGroup>
</Project>
This seems like something that could be better handled with support from upstream (see https://github.com/dotnet/sdk/issues/31918). Then we could let .NET know that ExportRelease
is meant to be a "Release" configuration, and the SDK could handle it accordingly instead of checking the configuration name like it does now.
However, we should also consider whether we actually need 3 configurations or if we can just use the default Debug
and Release
configurations. It looks like we currently check the configuration name to only add the TOOLS
constant to the non-export Debug
configuration, and avoid adding it to exported games:
But maybe there's another way to handle this. For example, a property like _IsPublishing
, although I'm not sure how I feel about using an undocumented and clearly private property (since the name starts with an underscore).
I think this is something that should gracefully work, a lot of users would probably find this behavior surprising and currently we don't document the custom Godot configurations anywhere. Let's keep this issue open until we figure something out.
Can we run our .NET code (or some of their assemblies) in release configuration while in the editor? That would be very useful.
Either way, what speaks against supporting proper "Release" for release exports? :D
Can we run our .NET code (or some of their assemblies) in release configuration while in the editor? That would be very useful.
Currently no. It's hardcoded to use the Debug
configuration.
what speaks against supporting proper "Release" for release exports?
Not sure, I wasn't around when the 3 configurations were introduced so I'm not familiar with the history. It's possible there were really good reasons to introduce them, but maybe things changed since then.
And we'd also want to make sure it doesn't break existing projects, so we may need some migration code if we change the configurations.
Tested versions
System information
Windows 11, Godot 4.4-dev, Vulkan, Jetbrains Rider, .Net 9
Issue description
In one of my tests I tried to run some benchmarks because I couldn't find any issues in my code anymore related to performance and profiling did not lead to any significant results.
In that test I executed the exact same logic from a Console app to use it with Benchmark.Net and noticed that the code running in the Console is about 5x as fast than running it in Godot.
In my actual environment these calls are running in a separate Thread pool so it shouldn't be related to Godot itself but to the .Net runtime used by Godot
Expected: Performance of C# code running in Godot is about the same as running it from a Console app
Actual: Performance of C# code running in Godot is ~5x slower than running it from a Console app
Steps to reproduce
Create a C# project and create a CPU heavy task. Run this in a tight loop ~10k times
Execute the same logic in a Console app and compare the results
Minimal reproduction project (MRP)
performancetest.zip
This is a small part of my VoxelEngine I am currently writing in pure C#, it contains quite a bit of Code but for very simple tasks I couldn't produce a huge amount of difference ~1ms per iteration.
Pls note that this code runs before anything renders at all so I would assume it should perform the same. But this project shows a HUGE difference. The results are: Console: Took 23s Godot: Took 1m 30s