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

Optimize calls to BlockLiteral.SetupBlock to inject the block signature. #3391

Merged

Conversation

rolfbjarne
Copy link
Member

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).

…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).
@@ -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 *.
Copy link
Contributor

Choose a reason for hiding this comment

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

s/MT/MM

Copy link
Member Author

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 😒

Copy link
Member Author

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.

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.

Copy link
Contributor

@VincentDondain VincentDondain Feb 5, 2018

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

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.
Copy link
Contributor

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."


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)).

Copy link
Contributor

Choose a reason for hiding this comment

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

is is :P

Copy link
Contributor

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.

Copy link
Contributor

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]?

Copy link
Contributor

@VincentDondain VincentDondain left a 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 👍

Copy link
Member

@dalexsoto dalexsoto left a 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??

@monojenkins
Copy link
Collaborator

Build failure

@rolfbjarne
Copy link
Member Author

rolfbjarne commented Feb 5, 2018

I see you added [BindingImpl (BindingImplOptions.Optimizable)] to some manual bindings containing manual blocks code, when shouldn't this be added / used??

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.
Copy link
Contributor

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 ?

Copy link
Member Author

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.
Copy link
Contributor

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 ?

Copy link
Member Author

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.
Copy link
Contributor

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.
Copy link
Contributor

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)]
Copy link
Contributor

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 ?

Copy link
Member Author

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

Copy link
Contributor

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!

Copy link
Contributor

@chamons chamons left a 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)]
Copy link
Contributor

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?

Copy link
Member Author

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).

Copy link
Contributor

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)]
Copy link
Contributor

Choose a reason for hiding this comment

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

same

Copy link
Member Author

Choose a reason for hiding this comment

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

Same 😄

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>)''
@monojenkins
Copy link
Collaborator

Build failure

Copy link
Member

@dalexsoto dalexsoto left a comment

Choose a reason for hiding this comment

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

Thanks Rolf! ❤️

@rolfbjarne
Copy link
Member Author

@rolfbjarne rolfbjarne merged commit 97230c2 into xamarin:master Feb 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants