* [core] improve Color & Clamp performance
When profiling startup of a HelloForms app on a Pixel 3 XL, I noticed:
Total(ms) Self(ms) Calls Method name
3 1 572 Xamarin.Forms.Internals.NumericExtensions:Clamp (double,double,double)
This method is called multiple times for every `Color` created and
~142 are created on startup. This is why it shows up 572 times for an
app with a single `Label`.
I found there is a `Math.Clamp` implementation in corefx:
6662a0f2fd/src/libraries/System.Private.CoreLib/src/System/Math.cs (L224-L225)
The only difference is this version can throw an exception, so we
could return the incoming value instead. That would be bad to change!
If I rework `NumericExtensions` to use corefx's implementation it is a
bit faster, I did a BenchmarkDotNet comparison running with Mono on
macOS:
Method | Mean | Error | StdDev |
------- |----------:|---------:|---------:|
Clamp2 | 53.89 ns | 0.668 ns | 0.522 ns |
Clamp1 | 61.84 ns | 1.270 ns | 2.289 ns |
Color2 | 112.50 ns | 2.643 ns | 3.705 ns |
Color1 | 129.03 ns | 2.603 ns | 4.760 ns |
Maybe every `Color` is ~13% faster?
Code for the benchmark is here:
https://github.com/jonathanpeppers/Benchmarks/blob/clamp/Benchmarks/Clamp.cs
Additionally, I reworked the list of default `Color` fields so that
they call a new private constructor that does less math and avoids
`Clamp` completely. We should still keep the original change, as it
would help any cases where the `Color.To*` methods would be used in
apps.
I seem to be able to see a small difference in a Release build running
on a Pixel 3 XL:
Before:
12-18 13:04:27.154 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +606ms
12-18 13:04:30.851 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +589ms
12-18 13:04:34.601 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +587ms
12-18 13:04:38.352 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +575ms
12-18 13:04:42.084 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +583ms
12-18 13:04:45.802 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +573ms
12-18 13:04:49.566 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +592ms
12-18 13:04:53.284 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +583ms
12-18 13:04:57.015 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +594ms
12-18 13:05:00.715 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
Average(ms): 586.3
Std Err(ms): 3.05886689260364
Std Dev(ms): 9.67298643990917
After:
12-18 13:08:16.677 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +593ms
12-18 13:08:20.377 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +577ms
12-18 13:08:24.107 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +583ms
12-18 13:08:27.827 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
12-18 13:08:31.574 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
12-18 13:08:35.324 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +584ms
12-18 13:08:39.056 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +587ms
12-18 13:08:42.773 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
12-18 13:08:46.523 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +584ms
12-18 13:08:50.256 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +587ms
Average(ms): 584.3
Std Err(ms): 1.56382721409865
Std Dev(ms): 4.94525586350753
This change seems low risk and would help all platforms.
* One last tweak byte -> int
Doing some reading: https://stackoverflow.com/a/43158214/132442
It seems `int` performs even better than `byte`. I did another test
run with just this change:
Before:
12-18 13:37:23.347 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
12-18 13:37:27.079 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +575ms
12-18 13:37:30.828 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
12-18 13:37:34.578 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +588ms
12-18 13:37:38.296 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
12-18 13:37:42.046 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +579ms
12-18 13:37:45.781 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
12-18 13:37:49.526 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
12-18 13:37:53.276 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
12-18 13:37:57.009 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +582ms
Average(ms): 580.1
Std Err(ms): 1.70912583243924
Std Dev(ms): 5.40473043833928
After:
12-18 13:35:38.745 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
12-18 13:35:42.459 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
12-18 13:35:46.209 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
12-18 13:35:49.974 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
12-18 13:35:53.724 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +574ms
12-18 13:35:57.474 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +580ms
12-18 13:36:01.207 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +573ms
12-18 13:36:04.957 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +568ms
12-18 13:36:08.707 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +566ms
12-18 13:36:12.407 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +565ms
Average(ms): 573.2
Std Err(ms): 1.87853370714738
Std Dev(ms): 5.94044517598546
When profiling startup, I started looking into the number of calls
retrieving custom attributes from assemblies:
Method call summary
Total(ms) Self(ms) Calls Method name
24 0 301 System.Reflection.RuntimeAssembly:GetCustomAttributes (System.Type,bool)
I saw a pattern such as:
object[] attributes = assembly.GetCustomAttributes(attrType, true);
var handlerAttributes = new HandlerAttribute[attributes.Length];
Array.Copy(attributes, handlerAttributes, attributes.Length);
RegisterRenderers(handlerAttributes);
We can avoid the allocation and copying of the array completely here.
We can simply cast `attributes` to `HandlerAttribute[]`.
The other thing I saw was:
string resolutionName = assembly.FullName;
var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute));
if (resolutionNameAttribute != null)
resolutionName = resolutionNameAttribute.ShortName;
This was happening even if the assembly had no `[assembly:Effect]`.
I reordered the code to not look for `[assembly: ResolutionGroupName]`
unless there was an `[assembly: Export]`.
This reduced the calls to `GetCustomAttributes` to:
Method call summary
Total(ms) Self(ms) Calls Method name
21 0 251 System.Reflection.RuntimeAssembly:GetCustomAttributes (System.Type,bool)
I also did a small amount of refactoring:
* `ReflectionExtensions.GetCustomAttributesSafe` had a variable
declaration that could be removed.
* `ReflectionExtensions.GetCustomAttributesSafe` was a nice wrapper to
avoid `#if` and also has a `try-catch` for the previewer. I used
this in places where there was duplicated code.
~~ Results ~~
Before:
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
12-17 13:08:57.119 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +588ms
12-17 13:09:00.852 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +583ms
12-17 13:09:04.602 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +573ms
12-17 13:09:08.388 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +581ms
12-17 13:09:12.137 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
12-17 13:09:15.887 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +583ms
12-17 13:09:19.621 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +578ms
12-17 13:09:23.388 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +588ms
12-17 13:09:27.123 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +587ms
12-17 13:09:30.892 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +571ms
Average(ms): 580.8
Std Err(ms): 1.94250697124446
Std Dev(ms): 6.1427463998877
After:
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
Launching: com.xamarin.forms.helloforms
12-17 13:10:29.762 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +579ms
12-17 13:10:33.514 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
12-17 13:10:37.263 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +564ms
12-17 13:10:40.996 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
12-17 13:10:44.748 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +569ms
12-17 13:10:48.467 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +573ms
12-17 13:10:52.231 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +577ms
12-17 13:10:55.981 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +558ms
12-17 13:10:59.765 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +574ms
12-17 13:11:03.499 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +569ms
Average(ms): 570.7
Std Err(ms): 1.94393644157644
Std Dev(ms): 6.1472667819844
I think this saves ~10ms on startup on Android, but this should help
all platforms.
These numbers were taken running on a Pixel 3 XL, a Blank
Xamarin.Forms app template using Xamarin.Forms/master.
Using: https://github.com/xamarin/Xamarin.Forms/pull/8867
* Added Windows Platform Specific to avoid set the default image directory
* Fixed build error
* Renamed ImageSearchDirectory to ImageDirectory
* Fixed build error
* Undo Issue8525 changes
* Revert changes in Issue8525
* Add UpdateMode to DatePicker and TimePicker on iOS
* Set the values from the Done button, not the EditingDidEnd event, for UpdateMode.WhenFinished
* Formatting
* fixes issue in android and ios
* Apply the suggested change to have page.Parent?.Parent
Apply the suggested change to fix the "A TabbedPage has no background. See Github6384." issue.
Co-authored-by: Rui Marinho <me@ruimarinho.net>
Co-authored-by: Hadi Zamani <54179804+hadi-zamani@users.noreply.github.com>
* Fixing various toolbar item display issues
* - fix csproj file
* - added UI test
* - fix possible breaks with Navigation Page
* Fix for 8741: Assert that ToolbarItem is grayed-out (PR 8889) (#8892)
* Assert that ToolbarItem is grayed-out
* Check alpha values on Android
* - fix toolbar item ordering
* - toolbar tracker improvements
* - remove whitespace
* - just use an array from the get go
* - primary
Co-authored-by: Brian Runck <brunck@users.noreply.github.com>
* [iOS] fixed "Nav Stack consistency error" on swipe to dismiss
* Revert "[iOS] fixed "Nav Stack consistency error" on swipe to dismiss"
This reverts commit f26a38ed3c81a78ba7315a78a6bc6cd14c698142.
* [iOS] fixed "Nav Stack consistency error" on swipe to dismiss
* [Shell] added UI Test for swipe to dismiss
* [iOS] fixed "Nav Stack consistency error" on swipe to dismiss
* Revert "[iOS] fixed "Nav Stack consistency error" on swipe to dismiss"
This reverts commit f26a38ed3c81a78ba7315a78a6bc6cd14c698142.
* [iOS] fixed "Nav Stack consistency error" on swipe to dismiss
* [Shell] added UI Test for swipe to dismiss
* [Shell] fixed UI Test for swipe to dismiss (iOS 11/12)
* - cleanup test a little bit
Co-authored-by: Shane Neuville <shane94@hotmail.com>
fixes#8461fixes#8944
Reviewing the memory report from the Mono profiler:
Allocation summary
Bytes Count Average Type name
13776 123 112 System.Reflection.AssemblyName
That is a lot of `AssemblyName` objects!
I found part of the culprit to be in `AndroidAppIndexProvider`:
private Assembly GetAssemblyForAppLinks(string assemblyName)
{
return Device.GetAssemblies().FirstOrDefault(assembly => assembly.GetName().Name == assemblyName);
}
Instead of using `System.Linq` to create an `AssemblyName` for every
.NET assembly, we can just use a fully-qualified name with
`Type.GetType`.
The memory results were a bit better:
Allocation summary
Bytes Count Average Type name
8176 73 112 System.Reflection.AssemblyName
Since this avoids a bit of System.Reflection & System.Linq, I was able
to see a performance improvement in a Blank Forms app template on a
Pixel 3 XL:
Before:
12-18 16:51:16.427 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +586ms
12-18 16:51:20.133 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +567ms
12-18 16:51:23.863 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +573ms
12-18 16:51:27.581 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +571ms
12-18 16:51:31.362 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +577ms
12-18 16:51:35.095 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +575ms
12-18 16:51:38.846 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +578ms
12-18 16:51:42.576 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +570ms
12-18 16:51:46.324 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +569ms
12-18 16:51:50.056 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
Average(ms): 574.2
Std Err(ms): 1.74355957741627
Std Dev(ms): 5.51361950083609
After:
12-18 16:55:04.122 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +571ms
12-18 16:55:07.805 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +570ms
12-18 16:55:11.553 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +569ms
12-18 16:55:15.303 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +574ms
12-18 16:55:19.020 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms
12-18 16:55:22.766 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +576ms
12-18 16:55:26.500 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +573ms
12-18 16:55:30.264 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +582ms
12-18 16:55:33.981 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +571ms
12-18 16:55:37.697 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +571ms
Average(ms): 572.9
Std Err(ms): 1.19675487140108
Std Dev(ms): 3.78447119452933
I also manually tested adding a reference to
`Xamarin.Forms.Platform.Android.AppLinks` and the code here was still
able to create the `AndroidAppLinks` object.
* Make sure the linker doesn't remove custom renderers, services, and effects in Control Gallery
* Add missing Preserve attribute to ShadowEffect
* Unbreak TapGestures in Spans on iOS
An assembly resolver holds opened files, and leaks if it is not disposed.
It is problematic if you run Xamarin.Forms.Xaml.UnitTests on Linux with
the default configuration because it has a small limit for the number of
opened files. It may cause stability issues also on other platforms,
depending on the situation.