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

[android] improve performance of Entry.MaxLength #15614

Merged
merged 1 commit into from
Jul 5, 2023

Conversation

jonathanpeppers
Copy link
Member

@jonathanpeppers jonathanpeppers commented Jun 13, 2023

Context: #10713

When investigating a customer sample:

  • Navigate from a Shell flyout

  • To a new page with several Entry controls

  • It feels a bit slow & laggy

When profiling on a Pixel 5, it seems one hot path is Entry.MaxLength:

18.52ms (0.22%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.UpdateMaxLength(Android.Widget.EditText,Microsoft.Maui.IEntry)
16.03ms (0.19%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.UpdateMaxLength(Android.Widget.EditText,int)
12.16ms (0.14%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.SetLengthFilter(Android.Widget.EditText,int)
  • EditTextExtensions.UpdateMaxLength() calls
    • EditText.Text getter and setter
    • EditTextExtensions.SetLengthFilter() calls
      • EditText.Get/SetFilters()

What happens is we end up marshaling strings and IInputFilter[] back and forth between C# and Java for every Entry on the page.

This seems like a prime candidate to move code from C# to Java. I tried to just port the code as-is without changing logic -- so we should get the exact same behavior as before.

Since all Entrys go through this code path (even ones with a default value for MaxLength), this improves the performance of all Entry and SearchBar on Android. With these changes in place, the calls to EditTextExtensions.UpdateMaxLength() are now so fast they are missing from the trace now, saving ~19ms when navigating to this page.

One note, is I found this was the recommended way to create a mutable List<T> from an array in Java:

List<InputFilter> currentFilters = new ArrayList<>(Arrays.asList(editText.getFilters()));

https://stackoverflow.com/a/11659198

Makes me appreciate C#! 😄

if (maxLength == -1)
maxLength = Integer.MAX_VALUE;

List<InputFilter> currentFilters = new ArrayList<>(Arrays.asList(editText.getFilters()));
Copy link
Member Author

@jonathanpeppers jonathanpeppers Jun 13, 2023

Choose a reason for hiding this comment

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

Comment on lines -49 to -50
if (e.BeforeCount == 0 && e.AfterCount == 0)
return;
Copy link
Member Author

@jonathanpeppers jonathanpeppers Jun 16, 2023

Choose a reason for hiding this comment

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

In 85b5699, it doesn't say why this check was added, but it was causing test failures when MaxLength is set to 0.

If you had an Entry with text, then set MaxLength=0 it wasn't updating Entry.Text after the platform fired the TextChanged event.

@@ -358,6 +359,7 @@ public async Task NegativeMaxLengthDoesNotClip()
, Skip = "https://github.com/dotnet/maui/issues/7939"
#endif
)]
[InlineData(0)]
Copy link
Member Author

Choose a reason for hiding this comment

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

This test case was failing without the above change to ITextInputExtensions.

@jonathanpeppers jonathanpeppers marked this pull request as ready for review June 16, 2023 21:39
@rmarinho
Copy link
Member

/rebase

Context: dotnet#10713

When investigating a customer sample:

* Navigate from a Shell flyout

* To a new page with several `Entry` controls

When profiling on a Pixel 5, it seems one hot path is `Entry.MaxLength`:

    18.52ms (0.22%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.UpdateMaxLength(Android.Widget.EditText,Microsoft.Maui.IEntry)
    16.03ms (0.19%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.UpdateMaxLength(Android.Widget.EditText,int)
    12.16ms (0.14%) microsoft.maui!Microsoft.Maui.Platform.EditTextExtensions.SetLengthFilter(Android.Widget.EditText,int)

* `EditTextExtensions.UpdateMaxLength()` calls
    * `EditText.Text` getter and setter
    * `EditTextExtensions.SetLengthFilter()` calls
        * `EditText.Get/SetFilters()`

What happens is we end up marshaling strings and `IInputFilter[]` back
and forth between C# and Java for every `Entry` on the page.

This seems like a prime candidate to move code from C# to Java. I
tried to just port the code as-is without changing logic -- so we
*should* get the exact same behavior as before.

Since all `Entry`s go through this code path (even ones with a default
value for `MaxLength`), this improves the performance of all `Entry`
and `SearchBar` on Android. With these changes in place, the calls to
`EditTextExtensions.UpdateMaxLength()` are now so fast they are
missing from the trace now, saving ~19ms when navigating to this page.

One note, is I found this was the recommended way to create a mutable
`List<T>` from an array in Java:

    List<InputFilter> currentFilters = new ArrayList<>(Arrays.asList(editText.getFilters()));

https://stackoverflow.com/a/11659198

Makes me appreciate C#! :)

Other changes:

* All platform to update empty strings

In 85b5699, it doesn't say why this check was added, but it was causing
test failures when MaxLength is set to 0.
@jonathanpeppers jonathanpeppers force-pushed the AndroidEntryMaxLength branch from ff65e09 to 7199ff8 Compare June 27, 2023 13:46
@jonathanpeppers
Copy link
Member Author

I manually rebased this. I don't know how a bot could resolve a conflict in maui.aar.

@mattleibow mattleibow merged commit 02481e6 into dotnet:main Jul 5, 2023
@jonathanpeppers jonathanpeppers deleted the AndroidEntryMaxLength branch July 5, 2023 19:27
@github-actions github-actions bot locked and limited conversation to collaborators Dec 9, 2023
@Eilon Eilon added t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf) area-controls-entry Entry and removed legacy-area-perf Startup / Runtime performance labels May 10, 2024
@samhouts samhouts added the fixed-in-8.0.0-preview.7.8842 Look for this fix in 8.0.0-preview.7.8842! label Aug 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-controls-entry Entry fixed-in-8.0.0-preview.7.8842 Look for this fix in 8.0.0-preview.7.8842! platform/android 🤖 t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants