Skip to content
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

[runtime] Move xamarin_create_managed_ref internal call to managed code. #11271

Merged

Conversation

rolfbjarne
Copy link
Member

@rolfbjarne rolfbjarne commented Apr 21, 2021

Move the xamarin_create_managed_ref internal call to managed code, to ease things
with CoreCLR.

In order to preserve performance, this wasn't a straight forward port.

  • monotouch_create_managed_ref used to detect if there already was a GCHandle for
    a native object. To avoid a managed->native transition, this logic has now been
    moved into the code that sets the GCHandle (the xamarinSetGCHandle:flags: / xamarin_set_gchandle_trampoline
    code), and these methods return a value saying whether the GCHandle was set or
    not.

  • xamarin_create_gchandle will check the retain count to determine whether to create
    a weak or a strong GCHandle for the managed object. In this particular case we
    should never need to create a strong GCHandle, which means that we don't need to
    check the retain count (saving a managed->native transition).

Performance measurements: slightly faster in all test cases I could come up with.

  • 'new NSObject ()': 3% faster
  • 'new CustomObject ()': 6% faster
  • Creating an NSObject in native code, and getting the managed wrapper: 0.6% faster
  • Creating a CustomObject in native code (the type being defined in managed code): 2% faster

All measurements done in an iOS simulator on an iMac Pro.

Using the new perftest (#11298), I get very similar numbers for both old code and new code: https://gist.github.com/rolfbjarne/e0fc2ae0f21da15062b4f051138679af (multiple runs). Sometimes the old code is faster, sometimes the new code is faster (although the old code tends to be the one who wins).

In any case there aren't any significant performance hits due to this change, so it should be good to go.


The next failure is now:

monotouchtest[91755:5770368] Xamarin.Mac: The method mono_jit_thread_attach has not been implemented for CoreCLR.

[...]
3   com.xamarin.monotouch-test    	0x000000010a2795d8 xamarin_assertion_message + 408 (runtime.m:1501)
4   com.xamarin.monotouch-test    	0x000000010a249601 mono_jit_thread_attach + 33 (mono-runtime.m:2424)
5   com.xamarin.monotouch-test    	0x000000010a27eb4e xamarin_switch_gchandle + 142 (runtime.m:1830)
6   com.xamarin.monotouch-test    	0x000000010a281cca xamarin_retain_trampoline + 42 (trampolines.m:701)
7   com.xamarin.monotouch-test    	0x000000010a2d53f0 -[Foundation_NSDispatcher retain] + 32 (Microsoft.macOS.registrar.x86_64.m:37192)
8   com.apple.Foundation          	0x00007fff2143b896 -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] + 148
9   com.apple.Foundation          	0x00007fff2143b6a1 -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:] + 124
10  com.xamarin.monotouch-test    	0x000000010a290ad9 xamarin_dyn_objc_msgSend + 217 (trampolines-x86_64-objc_msgSend.s:15)

Move the xamarin_create_managed_ref internal call to managed code, to ease things
with CoreCLR.

In order to preserve performance, this wasn't a straight forward port.

* monotouch_create_managed_ref used to detect if there already was a GCHandle for
  a native object. To avoid a managed->native transition, this logic has now been
  moved into the code that sets the GCHandle (the xamarinSetGCHandle:flags: / xamarin_set_gchandle_trampoline
  code), and these methods return a value saying whether the GCHandle was set or
  not.

* xamarin_create_gchandle will check the retain count to determine whether to create
  a weak or a strong GCHandle for the managed object. In this particular case we
  should never need to create a strong GCHandle, which means that we don't need to
  check the retain count (saving a managed->native transition).

Performance measurements: slightly faster in all test cases I could come up with.

* 'new NSObject ()': 3% faster
* 'new CustomObject ()': 6% faster
* Creating an NSObject in native code, and getting the managed wrapper: 0.6% faster
* Creating a CustomObject in native code (the type being defined in managed code): 2% faster

All measurements done in an iOS simulator on an iMac Pro.
@rolfbjarne rolfbjarne requested a review from spouliot as a code owner April 21, 2021 15:16
@rolfbjarne rolfbjarne added the not-notes-worthy Ignore for release notes label Apr 21, 2021
@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff

Test results

22 tests failed, 77 tests passed.

Failed tests

  • monotouch-test/iOS Unified 64-bits - simulator/Debug: TimedOut
  • monotouch-test/watchOS 32-bits - simulator/Debug: Failed
  • monotouch-test/watchOS 32-bits - simulator/Debug (LinkSdk): Failed
  • monotouch-test/watchOS 32-bits - simulator/Debug (static registrar): Failed
  • monotouch-test/watchOS 32-bits - simulator/Release (all optimizations): Failed
  • fsharp/iOS Unified 64-bits - simulator/Debug: TimedOut
  • fsharp/watchOS 32-bits - simulator/Debug: Failed
  • framework-test/iOS Unified 64-bits - simulator/Debug: TimedOut
  • framework-test/watchOS 32-bits - simulator/Debug: Failed
  • xcframework-test/iOS Unified 64-bits - simulator/Debug: TimedOut
  • xcframework-test/watchOS 32-bits - simulator/Debug: Failed
  • interdependent-binding-projects/watchOS 32-bits - simulator/Debug: Failed
  • introspection/watchOS 32-bits - simulator/Debug: Failed
  • introspection/watchOS 32-bits - simulator/Debug (watchOS 5.0): Failed
  • dont link/watchOS 32-bits - simulator/Debug: Failed
  • dont link/watchOS 32-bits - simulator/Release: Failed
  • link all/watchOS 32-bits - simulator/Debug: Failed
  • link all/watchOS 32-bits - simulator/Release: Failed
  • link sdk/watchOS 32-bits - simulator/Debug: Failed
  • link sdk/watchOS 32-bits - simulator/Release: Failed
  • mono-native-compat/watchOS 32-bits - simulator/Debug: Failed
  • mono-native-unified/watchOS 32-bits - simulator/Debug: Failed

Pipeline on Agent XAMBOT-1118'
Merge a1701a3 into 6d12766

@vs-mobiletools-engineering-service2
Copy link
Collaborator

✅ Tests passed on Build. ✅

Tests passed on Build.

API diff

✅ API Diff from stable

View API diff

🎉 All 102 tests passed 🎉

Pipeline on Agent XAMBOT-1101
Merge c8bccfb into e2082fd

bool
xamarin_set_gchandle_with_flags_safe (id self, GCHandle gchandle, enum XamarinGCHandleFlags flags)
{
// COOP: no managed memory access: any mode
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment sounds outdated.

Copy link
Member

@mandel-macaque mandel-macaque left a comment

Choose a reason for hiding this comment

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

Small stupid question.

enum XamarinGCHandleFlags : uint32_t {
XamarinGCHandleFlags_None = 0,
XamarinGCHandleFlags_WeakGCHandle = 1,
XamarinGCHandleFlags_HasManagedRef = 2,
XamarinGCHandleFlags_InitialSet = 4,
Copy link
Member

Choose a reason for hiding this comment

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

What happened with 3?

Copy link
Member Author

Choose a reason for hiding this comment

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

These are flags, so 1 + 2 = 3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
not-notes-worthy Ignore for release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants