-
Notifications
You must be signed in to change notification settings - Fork 516
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
iOS. Metal rendering. .Net worse performance than Xamarin when use IMTLDevice.CreateBuffer #21290
Comments
…eturn retained objects. Instead of doing this: ```cs var obj = Runtime.GetINativeObject<T>(handle, false); NSObject.ReleaseDangerous (handle); ``` we now do this: ```cs var obj = Runtime.GetINativeObject<T>(handle, true); ``` Less generated code, and better performance too. This was found while investigating #21290.
Can you try adding the following to your csproj to see if it makes a difference? <PropertyGroup>
<MtouchExtraArgs>--require-pinvoke-wrappers=true</MtouchExtraArgs>
<Registrar>managed-static</Registrar>
</PropertyGroup> You didn't provide a Xamarin sample, so I can't compare your .NET project to see if these changes makes it reach the Xamarin performance. |
Hi, I've tested additional parameters. Did not observe any changes in performance. Attaching xamarin and updated dotnet samples. I'm unable to run xamarin sample on my local machine now so apologize for not providing compare logs. Please give a link to a documentation regarding |
I've found a minor performance improvement we can do (#21297), and that cuts down a little bit of the difference between your factory implementation and the built-in Runtime.GetINativeObject implementation. Additionally, your profiling is also not entirely accurate, there will be one more loop for one of the scenarios than the other, skewing the results somewhat. Something like this solves that: var counter = 10000;
var factoryItems = new IDisposable [counter];
var apiItems = new IDisposable [counter];
Stopwatch sw;
// test CreateBuffer call performance
var apiTime = Stopwatch.StartNew();
for (var i = 0; i < counter; i++)
{
apiItems [i] = _device.CreateBuffer(bufferPtr, (UIntPtr)size, MTLResourceOptions.CpuCacheModeDefault);
}
apiTime.Stop ();
// test CreateBuffer call with cached constructor performance
var factoryTime = Stopwatch.StartNew();
for (var i = 0; i < counter; i++)
{
factoryItems [i] = _cachedFactory.CreateBuffer(bufferPtr, (UIntPtr)size, MTLResourceOptions.CpuCacheModeDefault, _device.Handle);
}
factoryTime.Stop ();
for (var i = 0; i < counter; i++) {
factoryItems [i].Dispose ();
apiItems [i].Dispose ();
}
Console.WriteLine($"Time spent with regular CreateBuffer call: {(long) apiTime.Elapsed.TotalMilliseconds} ms");
Console.WriteLine($"Time spent with constructor cached: {(long) factoryTime.Elapsed.TotalMilliseconds} ms"); With these two changes (and the ones in the csproj I previously mentioned) the Runtime.GetINativeObject implementation is 85-90% of your factory implementation according to the timing in the code. Interestingly the numbers I get in Instruments are different, the Runtime.GetINativeObject implementation is 96-97% of your factory implementation: Digging further into each of these callstacks reveal that the difference in time is actually low-level iOS code, so I have no idea what's going on here. |
I modified these a bit to make sure they test exactly the same thing: https://gist.github.com/rolfbjarne/1c6239078d9cfd186c4e9d8f145ae9c4 And the output I get with the Xamarin sample is something like this:
and the output I get with the .NET sample is:
In other words: the .NET version is performing better than the Xamarin version. Could there be something else in your .NET app that's slower than the Xamarin app now? |
Are these numbers with these additions to the csproj? <PropertyGroup>
<MtouchExtraArgs>--require-pinvoke-wrappers=true</MtouchExtraArgs>
<Registrar>managed-static</Registrar>
</PropertyGroup> |
Without additions to the csproj. I will do measurement with them added to my real project but it will take time. |
OK, sounds good. If this issue ends up auto-closing before you get the results, feel free to comment once you've got the results and we'll reopen. |
…eturn retained objects. (#21297) Instead of doing this: ```cs var obj = Runtime.GetINativeObject<T>(handle, false); NSObject.ReleaseDangerous (handle); ``` we now do this: ```cs var obj = Runtime.GetINativeObject<T>(handle, true); ``` Less generated code, and better performance too. This was found while investigating #21290.
Hi @Alexandr-Gurinovich. Due to inactivity, we will be closing this issue. Please feel free to re-open this issue if the issue persists. For enhanced visibility, if over 7 days have passed, please open a new issue and link this issue there. Thank you. |
Apple platform
iOS
Framework version
net8.0-*
Affected platform version
17.11.4.40609, dotnet 8.0.401
Description
In my Xamarin.iOS project I use Metal for rendering.
After migrating from Xamarin to .Net8 I noticed some performance issues with rendering. In particular I seen FPS drop on low devices, higher energy consumption and device heating increased (according to users complaints).
I profiled render loop and found that
IMTLDevice.CreateBuffer(IntPtr pointer, UIntPtr length, MTLResourceOptions options)
executed much longer after migration to .Net8.Steps to Reproduce
IMTLDevice.CreateBuffer(IntPtr pointer, UIntPtr length, MTLResourceOptions options)
several times every frame written on Xamarin platformResult: Render loop works slower and cause performance issues
Did you find any workaround?
Probably Xamarin implementation have some cacheing layer when Buffer is created. Sample solution attached in sample. Caching native constructor saves around 35% of execution time.
MetalSample.zip
Relevant log output
No response
The text was updated successfully, but these errors were encountered: