From cea6f704dbf4c1f658bbeac2d26cde0004fd0a22 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Sat, 20 Jan 2024 01:26:18 -0600 Subject: [PATCH 1/8] reduce LINQ usage --- src/Controls/src/Core/View/View.cs | 56 ++++++++++++++++++------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/Controls/src/Core/View/View.cs b/src/Controls/src/Core/View/View.cs index 3d8d52d22de4..4bb3f561e0a2 100644 --- a/src/Controls/src/Core/View/View.cs +++ b/src/Controls/src/Core/View/View.cs @@ -100,21 +100,31 @@ void AddItems(IEnumerable elements) { foreach (IElementDefinition item in elements) { - ValidateGesture(item as IGestureRecognizer); - item.Parent = this; - GestureController.CompositeGestureRecognizers.Add(item as IGestureRecognizer); + AddItem(item); } } + void AddItem(IElementDefinition item) + { + ValidateGesture(item as IGestureRecognizer); + item.Parent = this; + GestureController.CompositeGestureRecognizers.Add(item as IGestureRecognizer); + } + void RemoveItems(IEnumerable elements) { foreach (IElementDefinition item in elements) { - item.Parent = null; - GestureController.CompositeGestureRecognizers.Remove(item as IGestureRecognizer); + RemoveItem(item); } } + void RemoveItem(IElementDefinition item) + { + item.Parent = null; + GestureController.CompositeGestureRecognizers.Remove(item as IGestureRecognizer); + } + switch (args.Action) { case NotifyCollectionChangedAction.Add: @@ -129,30 +139,30 @@ void RemoveItems(IEnumerable elements) break; case NotifyCollectionChangedAction.Reset: - List remove = new List(); - List add = new List(); - - foreach (IElementDefinition item in _gestureRecognizers.OfType()) + foreach (IGestureRecognizer gestureRecognizer in _gestureRecognizers) { - if (!_gestureRecognizers.Contains((IGestureRecognizer)item)) - add.Add(item); - item.Parent = this; + if (gestureRecognizer is IElementDefinition item) + { + if (!_gestureRecognizers.Contains(gestureRecognizer)) + AddItem(item); + item.Parent = this; + } } - foreach (IElementDefinition item in GestureController.CompositeGestureRecognizers.OfType()) + foreach (IGestureRecognizer gestureRecognizer in GestureController.CompositeGestureRecognizers.ToArray()) { - if (item == _recognizerForPointerOverState) - continue; - - if (_gestureRecognizers.Contains((IGestureRecognizer)item)) - item.Parent = this; - else - remove.Add(item); + if (gestureRecognizer is IElementDefinition item) + { + if (item == _recognizerForPointerOverState) + continue; + + if (_gestureRecognizers.Contains(gestureRecognizer)) + item.Parent = this; + else + RemoveItem(item); + } } - AddItems(add); - RemoveItems(remove); - break; } }; From 0a0fc53471387dfc996e31dd31aa84d93b1a9fbd Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Sat, 20 Jan 2024 02:12:09 -0600 Subject: [PATCH 2/8] Remove useless check that will always be false --- src/Controls/src/Core/View/View.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Controls/src/Core/View/View.cs b/src/Controls/src/Core/View/View.cs index 4bb3f561e0a2..79282eddcd4a 100644 --- a/src/Controls/src/Core/View/View.cs +++ b/src/Controls/src/Core/View/View.cs @@ -143,8 +143,6 @@ void RemoveItem(IElementDefinition item) { if (gestureRecognizer is IElementDefinition item) { - if (!_gestureRecognizers.Contains(gestureRecognizer)) - AddItem(item); item.Parent = this; } } From cc9c54415eddddf78a66fc24a5e5dbdec2418aae Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Sat, 20 Jan 2024 02:14:56 -0600 Subject: [PATCH 3/8] use HashSet --- src/Controls/src/Core/View/View.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/src/Core/View/View.cs b/src/Controls/src/Core/View/View.cs index 79282eddcd4a..29edfbc58532 100644 --- a/src/Controls/src/Core/View/View.cs +++ b/src/Controls/src/Core/View/View.cs @@ -147,7 +147,7 @@ void RemoveItem(IElementDefinition item) } } - foreach (IGestureRecognizer gestureRecognizer in GestureController.CompositeGestureRecognizers.ToArray()) + foreach (IGestureRecognizer gestureRecognizer in GestureController.CompositeGestureRecognizers.ToHashSet()) { if (gestureRecognizer is IElementDefinition item) { From 238163763f0b5359d97ebe54834d885dda6ad40a Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Sat, 20 Jan 2024 10:21:56 -0600 Subject: [PATCH 4/8] reduce enumerations and casting --- src/Controls/src/Core/View/View.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Controls/src/Core/View/View.cs b/src/Controls/src/Core/View/View.cs index 29edfbc58532..dab7d47aafce 100644 --- a/src/Controls/src/Core/View/View.cs +++ b/src/Controls/src/Core/View/View.cs @@ -147,7 +147,9 @@ void RemoveItem(IElementDefinition item) } } - foreach (IGestureRecognizer gestureRecognizer in GestureController.CompositeGestureRecognizers.ToHashSet()) + var compositeGestureRecognizers = GestureController.CompositeGestureRecognizers.ToHashSet(); + + foreach (IGestureRecognizer gestureRecognizer in compositeGestureRecognizers) { if (gestureRecognizer is IElementDefinition item) { @@ -155,9 +157,14 @@ void RemoveItem(IElementDefinition item) continue; if (_gestureRecognizers.Contains(gestureRecognizer)) + { item.Parent = this; + } else - RemoveItem(item); + { + item.Parent = null; + GestureController.CompositeGestureRecognizers.Remove(gestureRecognizer); + } } } From b0f2c4f2edd783d9fadc80a5ed39c89e5aff047d Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Sat, 20 Jan 2024 10:22:27 -0600 Subject: [PATCH 5/8] reduce LINQ usage --- src/Controls/src/Core/View/View.cs | 38 +++++++++++------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/src/Controls/src/Core/View/View.cs b/src/Controls/src/Core/View/View.cs index dab7d47aafce..1fa51df066da 100644 --- a/src/Controls/src/Core/View/View.cs +++ b/src/Controls/src/Core/View/View.cs @@ -1,10 +1,10 @@ #nullable disable using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; -using Microsoft.Maui; using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; @@ -96,46 +96,36 @@ protected internal View() _gestureManager = new GestureManager(this); _gestureRecognizers.CollectionChanged += (sender, args) => { - void AddItems(IEnumerable elements) + void AddItems(IList newItems) { - foreach (IElementDefinition item in elements) + foreach (IElementDefinition item in newItems) { - AddItem(item); + ValidateGesture(item as IGestureRecognizer); + item.Parent = this; + GestureController.CompositeGestureRecognizers.Add(item as IGestureRecognizer); } } - void AddItem(IElementDefinition item) + void RemoveItems(IList oldItems) { - ValidateGesture(item as IGestureRecognizer); - item.Parent = this; - GestureController.CompositeGestureRecognizers.Add(item as IGestureRecognizer); - } - - void RemoveItems(IEnumerable elements) - { - foreach (IElementDefinition item in elements) + foreach (IElementDefinition item in oldItems) { - RemoveItem(item); + item.Parent = null; + GestureController.CompositeGestureRecognizers.Remove(item as IGestureRecognizer); } } - void RemoveItem(IElementDefinition item) - { - item.Parent = null; - GestureController.CompositeGestureRecognizers.Remove(item as IGestureRecognizer); - } - switch (args.Action) { case NotifyCollectionChangedAction.Add: - AddItems(args.NewItems.OfType()); + AddItems(args.NewItems); break; case NotifyCollectionChangedAction.Remove: - RemoveItems(args.OldItems.OfType()); + RemoveItems(args.OldItems); break; case NotifyCollectionChangedAction.Replace: - AddItems(args.NewItems.OfType()); - RemoveItems(args.OldItems.OfType()); + AddItems(args.NewItems); + RemoveItems(args.OldItems); break; case NotifyCollectionChangedAction.Reset: From eb4eac84a3282ad9f74d55d2b40aff39927b721d Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Sun, 21 Jan 2024 01:47:01 -0600 Subject: [PATCH 6/8] only cast once --- src/Controls/src/Core/View/View.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Controls/src/Core/View/View.cs b/src/Controls/src/Core/View/View.cs index 1fa51df066da..3ecb179d51f0 100644 --- a/src/Controls/src/Core/View/View.cs +++ b/src/Controls/src/Core/View/View.cs @@ -100,9 +100,10 @@ void AddItems(IList newItems) { foreach (IElementDefinition item in newItems) { - ValidateGesture(item as IGestureRecognizer); + var gestureRecognizer = item as IGestureRecognizer; + ValidateGesture(gestureRecognizer); item.Parent = this; - GestureController.CompositeGestureRecognizers.Add(item as IGestureRecognizer); + GestureController.CompositeGestureRecognizers.Add(gestureRecognizer); } } From 7cd48320a9699386ef48d8784f42f7898266c9f8 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Sun, 21 Jan 2024 01:47:14 -0600 Subject: [PATCH 7/8] add benchmarks --- .../GestureRecognizerBenchmarker.cs | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/Core/tests/Benchmarks/Benchmarks/GestureRecognizerBenchmarker.cs diff --git a/src/Core/tests/Benchmarks/Benchmarks/GestureRecognizerBenchmarker.cs b/src/Core/tests/Benchmarks/Benchmarks/GestureRecognizerBenchmarker.cs new file mode 100644 index 000000000000..b433675048e9 --- /dev/null +++ b/src/Core/tests/Benchmarks/Benchmarks/GestureRecognizerBenchmarker.cs @@ -0,0 +1,123 @@ +using BenchmarkDotNet.Attributes; +using Microsoft.Maui.Controls; + +namespace Microsoft.Maui.Handlers.Benchmarks; + +[MemoryDiagnoser] +public class GestureRecognizerBenchmarker +{ + View[] _views = null; + IGestureRecognizer[] _gestureRecognizers = null; + + [GlobalSetup] + public void Setup() + { + _views = [ + new Border(), new BoxView(), new CarouselView(), new Grid(), new Entry(), new Picker(), new CollectionView(), + new CheckBox(), new DatePicker(), new Stepper(), new Slider(), new ActivityIndicator(), new Frame(), + new ContentView(), new ProgressBar(), new SearchBar(), new Switch(), new TimePicker(), new WebView(), new Button(), + ]; + + _gestureRecognizers = [ + new PointerGestureRecognizer(), new TapGestureRecognizer(), new PanGestureRecognizer(), + new SwipeGestureRecognizer(), new DragGestureRecognizer(), new DropGestureRecognizer(), + ]; + } + + [Benchmark] + public void AddLotsOfGestureRecognizers() + { + var layout = new VerticalStackLayout(); + + AddGestureRecognizers(layout, _gestureRecognizers); + + for (int i = 0; i < 100; i++) + { + var childLayout = new VerticalStackLayout(); + + AddGestureRecognizers(childLayout, _gestureRecognizers); + + foreach (var view in _views) + { + AddGestureRecognizers(view, _gestureRecognizers); + + childLayout.Add(view); + } + + layout.Add(childLayout); + } + } + + + [Benchmark] + public void ClearLotsOfGestureRecognizers() + { + var layout = new VerticalStackLayout(); + + for (int i = 0; i < 1000; i++) + { + AddGestureRecognizers(layout, _gestureRecognizers); + } + + layout.GestureRecognizers.Clear(); + } + + + [Benchmark] + public void RemoveLotsOfGestureRecognizers() + { + var layout = new VerticalStackLayout(); + + foreach (var gestureRecognizer in _gestureRecognizers) + { + for (int i = 0; i < 1000; i++) + { + layout.GestureRecognizers.Remove(gestureRecognizer); + } + } + } + + [Benchmark] + public void AddOneGestureRecognizer() + { + var gestureRecognizer = new PointerGestureRecognizer(); + + for (int i = 0; i < 1000; i++) + { + var button = new Button(); + button.GestureRecognizers.Add(gestureRecognizer); + } + } + + [Benchmark] + public void RemoveOneGestureRecognizer() + { + var gestureRecognizer = new PointerGestureRecognizer(); + + for (int i = 0; i < 1000; i++) + { + var button = new Button(); + button.GestureRecognizers.Remove(gestureRecognizer); + } + } + + [Benchmark] + public void ClearOneGestureRecognizer() + { + for (int i = 0; i < 1000; i++) + { + var button = new Button(); + var gestureRecognizer = new PointerGestureRecognizer(); + button.GestureRecognizers.Add(gestureRecognizer); + button.GestureRecognizers.Clear(); + } + } + + private static void AddGestureRecognizers(View view, params IGestureRecognizer[] gestureRecognizers) + { + foreach (var gestureRecognizer in gestureRecognizers) + { + view.GestureRecognizers.Add(gestureRecognizer); + } + } +} From 80127203cdcbc8cccf590aad1094063cb8a8ab5f Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Sun, 21 Jan 2024 01:47:19 -0600 Subject: [PATCH 8/8] fix build --- src/Controls/src/Core/View/View.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/src/Core/View/View.cs b/src/Controls/src/Core/View/View.cs index 3ecb179d51f0..48a88634bf16 100644 --- a/src/Controls/src/Core/View/View.cs +++ b/src/Controls/src/Core/View/View.cs @@ -138,7 +138,7 @@ void RemoveItems(IList oldItems) } } - var compositeGestureRecognizers = GestureController.CompositeGestureRecognizers.ToHashSet(); + HashSet compositeGestureRecognizers = new(GestureController.CompositeGestureRecognizers); foreach (IGestureRecognizer gestureRecognizer in compositeGestureRecognizers) {