-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
049ec59
commit 274481a
Showing
4 changed files
with
257 additions
and
0 deletions.
There are no files selected for viewing
38 changes: 38 additions & 0 deletions
38
src/Controls/tests/TestCases.HostApp/Issues/RenderingPerformance.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
xmlns:issues="clr-namespace:Maui.Controls.Sample.Issues" | ||
x:Class="Maui.Controls.Sample.Issues.RenderingPerformance" | ||
Title="RenderingPerformance"> | ||
|
||
<Grid Padding="24" RowDefinitions="Auto,*" RowSpacing="8"> | ||
<Button x:Name="StartButton" Clicked="ButtonClicked" Text="Start" AutomationId="StartButton" /> | ||
|
||
<ScrollView Grid.Row="1"> | ||
<ContentView> | ||
<ContentView> | ||
<VerticalStackLayout x:Name="BindableContainer" BindableLayout.ItemsSource="{Binding Models}"> | ||
<BindableLayout.ItemTemplate> | ||
<DataTemplate> | ||
<Grid RowDefinitions="Auto,Auto,Auto" CompressedLayout.IsHeadless="True"> | ||
<Label Text="{Binding Header}" /> | ||
<Label Text="{Binding Content}" Grid.Row="1" /> | ||
<VerticalStackLayout Grid.Row="2" BindableLayout.ItemsSource="{Binding SubModels}" CompressedLayout.IsHeadless="True"> | ||
<BindableLayout.ItemTemplate> | ||
<DataTemplate> | ||
<VerticalStackLayout CompressedLayout.IsHeadless="True"> | ||
<Label Text="{Binding Header}" /> | ||
<issues:MeasuredLabel IsMeasured="{Binding IsMeasured}" Text="{Binding Content}" /> | ||
</VerticalStackLayout> | ||
</DataTemplate> | ||
</BindableLayout.ItemTemplate> | ||
</VerticalStackLayout> | ||
</Grid> | ||
</DataTemplate> | ||
</BindableLayout.ItemTemplate> | ||
</VerticalStackLayout> | ||
</ContentView> | ||
</ContentView> | ||
</ScrollView> | ||
</Grid> | ||
</ContentPage> |
180 changes: 180 additions & 0 deletions
180
src/Controls/tests/TestCases.HostApp/Issues/RenderingPerformance.xaml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
using System; | ||
using System.Collections.ObjectModel; | ||
using System.Diagnostics; | ||
using System.Globalization; | ||
using Microsoft.Maui; | ||
using Microsoft.Maui.Controls; | ||
using Microsoft.Maui.Controls.Xaml; | ||
using ILayout = Microsoft.Maui.ILayout; | ||
|
||
namespace Maui.Controls.Sample.Issues; | ||
|
||
public class MeasuredLabel : Label | ||
{ | ||
private static readonly TimeSpan ArrangedThreshold = TimeSpan.FromSeconds(1); | ||
public static readonly BindableProperty IsMeasuredProperty = BindableProperty.Create(nameof(IsMeasured), typeof(bool), typeof(MeasuredLabel), false); | ||
|
||
public bool IsMeasured | ||
{ | ||
get => (bool)GetValue(IsMeasuredProperty); | ||
set => SetValue(IsMeasuredProperty, value); | ||
} | ||
|
||
public long? LastArrangedTicks { get; set; } | ||
|
||
public long? GetArrangeTicks() { | ||
if (LastArrangedTicks is { } ticks) | ||
{ | ||
var elapsed = Stopwatch.GetElapsedTime(ticks); | ||
if (elapsed > ArrangedThreshold) | ||
{ | ||
return ticks; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
|
||
public static class RenderingPerformanceExtensions | ||
{ | ||
public static MauiAppBuilder RenderingPerformanceAddMappers(this MauiAppBuilder builder) | ||
{ | ||
builder.ConfigureMauiHandlers(handlers => | ||
{ | ||
Microsoft.Maui.Handlers.LabelHandler.CommandMapper.AppendToMapping(nameof(IView.Frame), (handler, view, arg) => | ||
{ | ||
if (view is MeasuredLabel { IsMeasured: true } measuredLabel) | ||
{ | ||
measuredLabel.LastArrangedTicks = Stopwatch.GetTimestamp(); | ||
} | ||
}); | ||
}); | ||
|
||
return builder; | ||
} | ||
} | ||
|
||
[XamlCompilation(XamlCompilationOptions.Compile)] | ||
[Issue(IssueTracker.None, 0, "Rendering performance", PlatformAffected.All)] | ||
public partial class RenderingPerformance : ContentPage | ||
{ | ||
public List<Model> Models { get; set; } | ||
|
||
public RenderingPerformance() | ||
{ | ||
Models = GenerateMeasuredItem(); | ||
BindingContext = this; | ||
InitializeComponent(); | ||
} | ||
|
||
private async void ButtonClicked(object sender, EventArgs e) | ||
{ | ||
var capturedTimes = new List<int[]>(); | ||
|
||
var test1Models = GenerateItems(50, "Test1"); | ||
var test2Models = GenerateItems(25, "Test2"); | ||
var resetModel = GenerateMeasuredItem(); | ||
|
||
await GetArrangeTicksAsync(); | ||
|
||
for (var i = 0; i < 6; i++) | ||
{ | ||
await Task.Delay(200); | ||
|
||
Models = test1Models; | ||
var startTicks = Stopwatch.GetTimestamp(); | ||
OnPropertyChanged(nameof(Models)); | ||
var endTicks = await Task.Run(GetArrangeTicksAsync); | ||
var t1 = (int)Stopwatch.GetElapsedTime(startTicks, endTicks).TotalMilliseconds; | ||
|
||
await Task.Delay(200); | ||
|
||
Models = test2Models; | ||
startTicks = Stopwatch.GetTimestamp(); | ||
OnPropertyChanged(nameof(Models)); | ||
endTicks = await Task.Run(GetArrangeTicksAsync); | ||
var t2 = (int)Stopwatch.GetElapsedTime(startTicks, endTicks).TotalMilliseconds; | ||
|
||
await Task.Delay(200); | ||
|
||
startTicks = Stopwatch.GetTimestamp(); | ||
BindableContainer.Clear(); | ||
Models = resetModel; | ||
OnPropertyChanged(nameof(Models)); | ||
endTicks = await Task.Run(GetArrangeTicksAsync); | ||
var t3 = (int)Stopwatch.GetElapsedTime(startTicks, endTicks).TotalMilliseconds; | ||
|
||
capturedTimes.Add([t1, t2, t3]); | ||
} | ||
|
||
var avg1 = (int)capturedTimes.Average(t => t[0]); | ||
var avg2 = (int)capturedTimes.Average(t => t[1]); | ||
var avg3 = (int)capturedTimes.Average(t => t[2]); | ||
StartButton.Text = $"{avg1},{avg2},{avg3}"; | ||
} | ||
|
||
async Task<long> GetArrangeTicksAsync() | ||
{ | ||
while (true) | ||
{ | ||
await Task.Delay(100); | ||
IView view = BindableContainer; | ||
while (view is ILayout { Count: > 0 } layout) | ||
{ | ||
view = layout[^1]; | ||
} | ||
|
||
if (view is MeasuredLabel measuredLabel && measuredLabel.GetArrangeTicks() is { } arrangeTicks) | ||
{ | ||
measuredLabel.LastArrangedTicks = null; | ||
return arrangeTicks; | ||
} | ||
} | ||
} | ||
|
||
static List<Model> GenerateItems(int count, string prefix) | ||
{ | ||
return | ||
[ | ||
..Enumerable.Range(0, count).Select(i => new Model | ||
{ | ||
Content = $"{prefix} Content {i}", | ||
Header = $"Header {i}", | ||
SubModels = Enumerable.Range(0, 10).Select(j => new SubModel | ||
{ | ||
Content = $"{prefix} SubContent {j}", Header = $"{prefix} SubHeader {j}" | ||
}).ToArray() | ||
}), | ||
..GenerateMeasuredItem() | ||
]; | ||
} | ||
|
||
static List<Model> GenerateMeasuredItem() | ||
{ | ||
return | ||
[ | ||
new Model | ||
{ | ||
Content = "Measured", | ||
Header = "Measured", | ||
SubModels = | ||
[ | ||
new SubModel { Content = "Measured", Header = "Measured", IsMeasured = true } | ||
] | ||
} | ||
]; | ||
} | ||
|
||
public class Model : SubModel | ||
{ | ||
public SubModel[] SubModels { get; set; } | ||
} | ||
|
||
public class SubModel | ||
{ | ||
public string Header { get; set; } | ||
public string Content { get; set; } | ||
public bool IsMeasured { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/RenderingPerformance.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using NUnit.Framework; | ||
using UITest.Appium; | ||
using UITest.Core; | ||
|
||
namespace Microsoft.Maui.TestCases.Tests.Issues | ||
{ | ||
public class RenderingPerformance : _IssuesUITest | ||
{ | ||
public RenderingPerformance(TestDevice device) : base(device) { } | ||
|
||
public override string Issue => "Rendering performance"; | ||
|
||
[Test] | ||
[Category(UITestCategories.Performance)] | ||
public async Task RenderingPerformanceRun() | ||
{ | ||
var button = App.WaitForElement("StartButton"); | ||
App.Tap("StartButton"); | ||
|
||
string? text; | ||
while (true) | ||
{ | ||
text = button.GetText(); | ||
if (string.IsNullOrEmpty(text) || text == "Start") | ||
{ | ||
await Task.Delay(1000); | ||
continue; | ||
} | ||
|
||
break; | ||
} | ||
|
||
var times = text.Split(','); | ||
|
||
TestContext.WriteLine(@$"RenderingPerformance: [{times[0]}, {times[1]}, {times[2]}]"); | ||
} | ||
} | ||
} |