Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit 6d90430

Browse files
[xamlc] add a new ResourceLoader.IsEnabled check (#11754)
Context: https://github.com/jonathanpeppers/Xamarin.Forms.Benchmarks I noticed a C# binding by hand is still a bit faster than bindings written in Xaml in various forms: | Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | |--------------- |---------:|----------:|----------:|-------:|-------:|------:|----------:| | ByHandOneTime | 3.210 us | 0.0836 us | 0.0553 us | 0.5531 | 0.0038 | - | 3.42 KB | | TypedOneTime | 4.087 us | 0.0560 us | 0.0370 us | 0.8163 | 0.0076 | - | 5.05 KB | | RegularOneTime | 5.375 us | 0.0117 us | 0.0077 us | 0.9079 | 0.0076 | - | 5.61 KB | | ByHand | 5.552 us | 0.6508 us | 0.4305 us | 0.5951 | 0.1450 | - | 3.71 KB | | Typed | 6.992 us | 0.4679 us | 0.3095 us | 0.9155 | 0.3052 | - | 5.67 KB | | Regular | 7.822 us | 0.3988 us | 0.2638 us | 0.9460 | 0.3128 | - | 5.86 KB | Looking at the code that XamlC generates for any `Page` or `View` created from Xaml: private void InitializeComponent() { if (ResourceLoader.CanProvideContentFor(new ResourceLoader.ResourceLoadingQuery { AssemblyName = typeof(BindingLabel).GetTypeInfo().Assembly.GetName(), ResourcePath = "Views/BindingLabel.xaml.xaml", Instance = this })) { __InitComponentRuntime(); return; } //... This is produced for a simple view such as: <?xml version="1.0" encoding="UTF-8"?> <Label xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Benchmarks.BindingLabel" Text="{Binding Text}" /> The `ResourceLoader` check was originally for the Xamarin.Forms previewer -- and is now used by Hot Reload. The call that seems relatively expensive here: typeof(BindingLabel).GetTypeInfo().Assembly.GetName() If you created N `BindingLabel` objects, this would get called N times. A complex Xamarin.Forms app would potentially have a lot of Xaml views & pages like this. If we added a new `ResourceLoader.IsEnabled` property, we could make the check instead do: if (ResourceLoader.IsEnabled && ResourceLoader.CanProvideContentFor(...)) This skips the `Assembly.GetName()` call completely now. ~~ Results ~~ Using this benchmark: https://github.com/jonathanpeppers/Xamarin.Forms.Benchmarks/blob/xamarin.forms-resourceloader/Xamarin.Forms.Benchmarks/Benchmarks/Bindings.cs | Method | Mean | Error | StdDev | Median | Gen 0 | Gen 1 | Gen 2 | Allocated | |--------- |---------:|----------:|----------:|---------:|------:|------:|------:|----------:| | ByHand | 3.546 us | 0.0565 us | 0.1613 us | 3.502 us | - | - | - | 3.76 KB | | Regular2 | 4.542 us | 0.0696 us | 0.1985 us | 4.541 us | - | - | - | 4.88 KB | | Regular | 6.041 us | 0.0531 us | 0.1490 us | 6.065 us | - | - | - | 5.92 KB | `Regular2` has an equivalent of the changes here and is a bit closer to being on par with the "by hand" binding. If I time the startup time for this page on Android: Before: 08-11 15:27:34.005 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +679ms 08-11 15:27:37.797 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +648ms 08-11 15:27:41.551 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +622ms 08-11 15:27:45.436 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +649ms 08-11 15:27:49.234 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +648ms 08-11 15:27:53.048 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +633ms 08-11 15:27:56.864 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +635ms 08-11 15:28:00.686 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +629ms 08-11 15:28:04.466 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +634ms 08-11 15:28:08.265 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +636ms Average(ms): 641.3 Std Err(ms): 5.03774640974403 Std Dev(ms): 15.930752929127 After: 08-11 15:30:22.575 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +644ms 08-11 15:30:26.341 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +614ms 08-11 15:30:30.126 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +624ms 08-11 15:30:33.907 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +626ms 08-11 15:30:37.708 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +621ms 08-11 15:30:41.493 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +616ms 08-11 15:30:45.290 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +636ms 08-11 15:30:49.157 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +623ms 08-11 15:30:52.955 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +632ms 08-11 15:30:56.738 1391 1448 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +627ms Average(ms): 626.3 Std Err(ms): 2.8715075405709 Std Dev(ms): 9.08050414655241 Using the project here on a Pixel 3 XL: https://github.com/jonathanpeppers/Xamarin.Forms/tree/resourceloader-benchmark/HelloForms/HelloForms
1 parent c1d1d52 commit 6d90430

File tree

2 files changed

+9
-6
lines changed

2 files changed

+9
-6
lines changed

Xamarin.Forms.Build.Tasks/XamlCTask.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ bool TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime,
282282
//First using the ResourceLoader
283283
var nop = Instruction.Create(Nop);
284284

285+
// if (ResourceLoader.IsEnabled && ...
286+
il.Emit(Call, module.ImportPropertyGetterReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "ResourceLoader"), "IsEnabled", isStatic: true));
287+
il.Emit(Brfalse, nop);
288+
285289
il.Emit(Newobj, module.ImportCtorReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "ResourceLoader/ResourceLoadingQuery"), 0));
286290

287291
//AssemblyName

Xamarin.Forms.Core/Internals/ResourceLoader.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,11 @@ internal set {
3434

3535
[Obsolete("Can't touch this")]
3636
[EditorBrowsable(EditorBrowsableState.Never)]
37-
public static bool CanProvideContentFor(ResourceLoadingQuery rlq)
38-
{
39-
if (_resourceProvider2 == null)
40-
return false;
41-
return _resourceProvider2(rlq) != null;
42-
}
37+
public static bool IsEnabled => _resourceProvider2 != null;
38+
39+
[Obsolete("Can't touch this")]
40+
[EditorBrowsable(EditorBrowsableState.Never)]
41+
public static bool CanProvideContentFor(ResourceLoadingQuery rlq) => _resourceProvider2?.Invoke(rlq) != null;
4342

4443
public class ResourceLoadingQuery
4544
{

0 commit comments

Comments
 (0)