diff --git a/src/iOS/Avalonia.iOS/DispatcherImpl.cs b/src/iOS/Avalonia.iOS/DispatcherImpl.cs index b39ba1a85a..1bf4503af8 100644 --- a/src/iOS/Avalonia.iOS/DispatcherImpl.cs +++ b/src/iOS/Avalonia.iOS/DispatcherImpl.cs @@ -22,7 +22,8 @@ internal class DispatcherImpl : IDispatcherImplWithExplicitBackgroundProcessing private readonly IntPtr _mainLoop; private readonly IntPtr _mainQueue; private Thread? _loopThread; - private bool _backgroundProcessingRequested, _signaled; + private bool _backgroundProcessingRequested; + private int _signaled; private unsafe DispatcherImpl() { @@ -60,15 +61,12 @@ internal class DispatcherImpl : IDispatcherImplWithExplicitBackgroundProcessing public unsafe void Signal() { - lock (_sync) + if (Interlocked.CompareExchange(ref _signaled, 1, 0) != 0) { - if (_signaled) - return; - _signaled = true; - - Interop.dispatch_async_f(_mainQueue, IntPtr.Zero, &CheckSignaled); - Interop.CFRunLoopWakeUp(_mainLoop); + return; } + Interop.dispatch_async_f(_mainQueue, IntPtr.Zero, &CheckSignaled); + Interop.CFRunLoopWakeUp(_mainLoop); } public void UpdateTimer(long? dueTimeInMs) @@ -91,14 +89,7 @@ internal class DispatcherImpl : IDispatcherImplWithExplicitBackgroundProcessing private void CheckSignaled() { - bool signaled; - lock (_sync) - { - signaled = _signaled; - _signaled = false; - } - - if (signaled) + if (Interlocked.Exchange(ref _signaled, 0) != 0) { Signaled?.Invoke(); } diff --git a/src/iOS/Avalonia.iOS/InputHandler.cs b/src/iOS/Avalonia.iOS/InputHandler.cs index bd66d5a51e..06542cbb0d 100644 --- a/src/iOS/Avalonia.iOS/InputHandler.cs +++ b/src/iOS/Avalonia.iOS/InputHandler.cs @@ -308,7 +308,7 @@ internal sealed class InputHandler _tl.Input?.Invoke(new RawMouseWheelEventArgs( _mouseDevice, - (ulong)(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()), + (ulong)Environment.TickCount64, Root, _cachedScrollLocation ?? new Point(0, 0), new Vector(deltaX, deltaY), @@ -372,7 +372,7 @@ internal sealed class InputHandler // until the inertia stops. _tl.Input?.Invoke(new RawMouseWheelEventArgs( _mouseDevice, - (ulong)(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()), + (ulong)Environment.TickCount64, Root, _cachedScrollLocation.Value, new Vector(_momentumVelocityX, _momentumVelocityY), diff --git a/src/iOS/Avalonia.iOS/TextInputResponder.cs b/src/iOS/Avalonia.iOS/TextInputResponder.cs index 678fac8766..b2c1d1700c 100644 --- a/src/iOS/Avalonia.iOS/TextInputResponder.cs +++ b/src/iOS/Avalonia.iOS/TextInputResponder.cs @@ -84,6 +84,7 @@ partial class AvaloniaView private int _inSurroundingTextUpdateEvent; private readonly UITextPosition _beginningOfDocument = new AvaloniaTextPosition(0); private readonly UITextInputStringTokenizer _tokenizer; + private readonly NSString _textInputContextIdentifier = new NSString(Guid.NewGuid().ToString()); private bool _isInUpdate; public TextInputMethodClient? Client => _client; @@ -95,7 +96,7 @@ partial class AvaloniaView public override UIEditingInteractionConfiguration EditingInteractionConfiguration => UIEditingInteractionConfiguration.Default; - public override NSString TextInputContextIdentifier => new NSString(Guid.NewGuid().ToString()); + public override NSString TextInputContextIdentifier => _textInputContextIdentifier; public override UITextInputMode TextInputMode { diff --git a/tests/Avalonia.Benchmarks/Rendering/iOSRenderingBenchmarks.cs b/tests/Avalonia.Benchmarks/Rendering/iOSRenderingBenchmarks.cs new file mode 100644 index 0000000000..1dad432feb --- /dev/null +++ b/tests/Avalonia.Benchmarks/Rendering/iOSRenderingBenchmarks.cs @@ -0,0 +1,42 @@ +#nullable enable +using System; +using BenchmarkDotNet.Attributes; + +namespace Avalonia.Benchmarks.Rendering +{ + /// + /// Benchmarks for Avalonia.iOS hot path patterns. + /// Run with: dotnet run -c Release -- --filter *iOSRenderingBenchmarks* + /// + [MemoryDiagnoser] + public class iOSRenderingBenchmarks + { + private const int FrameCount = 1000; + + // iOS TextInputContextIdentifier: new Guid+string+wrapper vs cached (TextInputResponder.cs) + + [Benchmark] + public string? Current_TextInputContextId_NewGuidPerAccess() + { + string? last = null; + for (int i = 0; i < FrameCount; i++) + { + last = Guid.NewGuid().ToString(); + } + return last; + } + + [Benchmark] + public string? Optimized_TextInputContextId_Cached() + { + string cached = Guid.NewGuid().ToString(); + string? last = null; + for (int i = 0; i < FrameCount; i++) + { + last = cached; + } + return last; + } + + } +}