-
Notifications
You must be signed in to change notification settings - Fork 518
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
Optimize calls to BlockLiteral.SetupBlock to inject the block signature. #3391
Optimize calls to BlockLiteral.SetupBlock to inject the block signature. #3391
Conversation
…the code line causing the error/warning. Add support for reporting errors/warnings that point to the code line causing the error/warning by adding ErrorHelper overloads that take the exact instruction to report (previously we defaulted to the first line/instruction in a method).
…k signature. Optimize calls to BlockLiteral.SetupBlock[Unsafe] to calculate the block signature at build time, and inject it into the call site. This makes block invocations 10-15x faster (I've added tests that asserts at least an 8x increase). It's also required in order to be able to remove the dynamic registrar code in the future (since calculating the block signature at runtime requires the dynamic registrar).
…n both XI's and XM's link all test.
…al.SetupBlock optimization.
docs/website/mmp-errors.md
Outdated
@@ -252,6 +259,15 @@ See https://msdn.microsoft.com/en-us/library/x0w2664k.aspx for more information | |||
|
|||
### <a name="MM4134">MM4134: Your application is using the '{0}' framework, which isn't included in the MacOS SDK you're using to build your app (this framework was introduced in OSX {2}, while you're building with the MacOS {1} SDK.) This configuration is not supported with the static registrar (pass --registrar:dynamic as an additional mmp argument in your project's Mac Build option to select). Alternatively select a newer SDK in your app's Mac Build options. | |||
|
|||
### <a name="MT4173"/>MT4173: The registrar can't compute the block signature for the delegate of type {delegate-type} in the method {method} because *. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/MT/MM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should figure out a way to not having to write duplicate documentation here 😒
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@VincentDondain I've now fixed the docs according to your comments.
docs/website/optimizations.md
Outdated
time, and modify the IL to call a SetupBlock variation that takes the | ||
signature as an argument instead, avoiding the need for calculating the | ||
signature at runtime. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we break this ^ down even more, the last sentence is hard to digest.
Maybe: "This might be a fairly expensive operation. This optimization will calculate the block signature at build time, and modify the IL to call a SetupBlock
variation that takes the signature as an argument instead. Doing this avoid the need for calculating the signature at runtime."
Note: let's use ` for SetupBlock -> SetupBlock
docs/website/optimizations.md
Outdated
signature as an argument instead, avoiding the need for calculating the | ||
signature at runtime. | ||
|
||
Benchmarks show that this speeds up calling a block 10-15x. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing "by"?
"Benchmarks show that this speeds up calling a block by 10-15x."
Or maybe "Benchmarks show that this speeds up calling a block by a factor of 10 to 15."
docs/website/optimizations.md
Outdated
|
||
It is is enabled by default when using the static registrar (which is enabled | ||
by default when building for device (iOS) or building for release (macOS)). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is is :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe go for "(which is itself enabled by default ..." because it's a double enabled by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I'd use something else than parenthesis for (iOS) and (macOS), dunno if nested parenthesis is a thing. Maybe [iOS], [macOS]?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise code looks good to me 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you added [BindingImpl (BindingImplOptions.Optimizable)]
to some manual bindings containing manual blocks code, when shouldn't this be added / used??
Build failure |
When there's nothing in the method that will be optimized 😄 Theoretically we could try to optimize everything, but it's time-consuming to process every method, so the attribute is really just a way to not waste time trying to optimize methods that can't be optimized (it also limits the potential for broken optimizations). |
The linker reports this warning when it can't optimize a call to BlockLiteral.SetupBlock or Block.SetupBlockUnsafe. | ||
|
||
The message will point to the method that calls BlockLiteral.SetupBlock[Unsafe], and | ||
it may also give clues as to why the call couldn't be optimized. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what would the developer action be ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The developer can probably not do much more than report a bug and ignore the warning (so I've added that to the help just below).
the registrar couldn't compute it. | ||
|
||
This means that the block signature has to be computed at runtime, which is | ||
somewhat slower. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same. Should we ask them to file an issue so we can investigate why ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: I've explained a bit below when this can happen, and what to do (for the developer).
The linker reports this warning when it can't optimize a call to BlockLiteral.SetupBlock or Block.SetupBlockUnsafe. | ||
|
||
The message will point to the method that calls BlockLiteral.SetupBlock[Unsafe], and | ||
it may also give clues as to why the call couldn't be optimized. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
the registrar couldn't compute it. | ||
|
||
This means that the block signature has to be computed at runtime, which is | ||
somewhat slower. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
@@ -207,6 +207,7 @@ public static ABAuthorizationStatus GetAuthorizationStatus () | |||
extern unsafe static void ABAddressBookRequestAccessWithCompletion (IntPtr addressbook, void * completion); | |||
|
|||
[iOS (6,0)] | |||
[BindingImpl (BindingImplOptions.Optimizable)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we can add an intro tests to detect them, e.g. based on any locals with a BlockLiteral
type ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already added such a test, but as an mtouch/mmp test (because intro would run on device as well, and that seemed wasteful for something that's clearly not needed): https://github.com/xamarin/xamarin-macios/pull/3391/files#diff-f773c4aa1cac370f711a23af6d86eb2aR29
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's weird... GitHub shows me New changes since you last viewed that are way older than what I reviewed ?!?
anyhow I see them now and it's even better the way you implemented them!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 (assuming other issues noted above are obviously fixed).
Outside my area of expertise but ❤️ the tests that give me a greater clue.
{ | ||
[Test] | ||
#if __MACOS__ | ||
[TestCase (Profile.macOSMobile)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need/want Full here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, because this is not testing any API/code inside the platform assembly, only mmp (the linker), which should not depend on the profile (note that for XI I'm not running the test for tvOS/watchOS, only iOS).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair.
|
||
[Test] | ||
#if __MACOS__ | ||
[TestCase (Profile.macOSMobile)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same 😄
…se class aren't executed twice.
The optimization tests only apply when the test assembly is linked, and that only happens in linkall, so exclude those tests in linksdk.
Fixes these test failures: 1) Failed : Xamarin.MMP.Tests.MMPTests.MM0132("inline-runtime-arch") The warning 'MM0132: Unknown optimization: 'inline-runtime-arch'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size.' was not found in the output: Message #1 did not match: actual: 'Unknown optimization: 'inline-runtime-arch'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size, blockliteral-setupblock.' expected: 'Unknown optimization: 'inline-runtime-arch'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size.' Message #2 did not match: actual: 'Unknown optimization: 'inline-runtime-arch'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size, blockliteral-setupblock.' expected: 'Unknown optimization: 'inline-runtime-arch'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size.' 2) Failed : Xamarin.MMP.Tests.MMPTests.MM0132("foo") The warning 'MM0132: Unknown optimization: 'foo'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size.' was not found in the output: Message #1 did not match: actual: 'Unknown optimization: 'foo'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size, blockliteral-setupblock.' expected: 'Unknown optimization: 'foo'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size.' Message #2 did not match: actual: 'Unknown optimization: 'foo'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size, blockliteral-setupblock.' expected: 'Unknown optimization: 'foo'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size.'
Fixes this test failure: 1) SetupBlock_CustomDelegate (Linker.Shared.BaseOptimizeGeneratedCodeTest.SetupBlock_CustomDelegate) Counter Expected: 1 But was: 2
…better) behavior. Fixes this test failure: 1) Failed : Xamarin.Registrar.GenericType_WithInvalidParameterTypes The error 'MT4136: The registrar cannot marshal the parameter type 'System.Collections.Generic.List`1<U>' of the parameter 'arg' in the method 'Open`1.Bar(System.Collections.Generic.List`1<U>)'' was not found in the output: Message #1 did not match: actual: 'The registrar cannot marshal the parameter type 'System.Collections.Generic.List`1<Foundation.NSObject>' of the parameter 'arg' in the method 'Open`1.Bar(System.Collections.Generic.List`1<U>)'' expected: 'The registrar cannot marshal the parameter type 'System.Collections.Generic.List`1<U>' of the parameter 'arg' in the method 'Open`1.Bar(System.Collections.Generic.List`1<U>)''
Build failure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Rolf! ❤️
Test failures are unrelated:
|
Optimize calls to BlockLiteral.SetupBlock[Unsafe] to calculate the block
signature at build time, and inject it into the call site.
This makes block invocations 10-15x faster (I've added tests that asserts at
least an 8x increase, along with numerous other tests for this optimization).
It's also required in order to be able to remove the dynamic registrar code in
the future (since calculating the block signature at runtime requires the
dynamic registrar).