Skip to content

Commit

Permalink
Add Performance Benchmarks (#287)
Browse files Browse the repository at this point in the history
* Add Benchmarks

* Add `BenchmarkDotNet.Artifacts/` to `.gitignore`

* Add Benchmarks to Build Pipeline

* Update .gitignore

* Only publish artifacts on Windows

* Segregate View-to-ViewModel Bindings from ViewModel-To-View Bindings

* Add missing setters

* Update azure-pipelines.yml

* Update Pipeline Order + Display Name

* Move Benchmarks + Sample App to Separate Job Pipeline

Running these in parallel optimizes our pipeline speeds

* Update azure-pipelines.yml

* Add `CommunityToolkit.Maui.Markup.Benchmarks.csproj`

* Update azure-pipelines.yml

* Update azure-pipelines.yml

* Update Benchmark CI

* Use `--project`

* Update azure-pipelines.yml

* Publish Benchmark Results to `$(Build.ArtifactStagingDirectory)`

* Disable Code Signing

* Update azure-pipelines.yml

* Update azure-pipelines.yml

* Update azure-pipelines.yml

* Update azure-pipelines.yml

* Update azure-pipelines.yml

* Update azure-pipelines.yml
  • Loading branch information
TheCodeTraveler authored Jun 21, 2024
1 parent 4146d1f commit 5d9ab90
Show file tree
Hide file tree
Showing 17 changed files with 662 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

**/.vscode*

**/.meteor*

### fastlane ###
# fastlane - A streamlined workflow tool for Cocoa deployment

Expand Down Expand Up @@ -671,6 +673,9 @@ hs_err_pid*
# MFractor
.mfractor/

# Benchmarkdot
BenchmarkDotNet.Artifacts/

### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
Expand Down
123 changes: 111 additions & 12 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ variables:
PathToCommunityToolkitCsproj: 'src/CommunityToolkit.Maui.Markup/CommunityToolkit.Maui.Markup.csproj'
PathToCommunityToolkitSampleCsproj: 'samples/CommunityToolkit.Maui.Markup.Sample/CommunityToolkit.Maui.Markup.Sample.csproj'
PathToCommunityToolkitUnitTestCsproj: 'src/CommunityToolkit.Maui.Markup.UnitTests/CommunityToolkit.Maui.Markup.UnitTests.csproj'
PathToCommunityToolkitBenchmarkCsproj: 'src/CommunityToolkit.Maui.Markup.Benchmarks/CommunityToolkit.Maui.Markup.Benchmarks.csproj'
PathToCommunityToolkitSourceGeneratorsCsproj: 'src/CommunityToolkit.Maui.Markup.SourceGenerators/CommunityToolkit.Maui.Markup.SourceGenerators.csproj'
XcodeVersion: '15.2.0'
CommunityToolkitSampleApp_Xcode_Version: '15.2.0'
CommunityToolkitLibrary_Xcode_Version: '15.3.0'
ShouldCheckDependencies: true

trigger:
Expand Down Expand Up @@ -41,15 +43,62 @@ schedules:
include:
- main

jobs:
jobs:
- job: build_sample
displayName: Build Sample App
strategy:
matrix:
'Windows':
image: 'windows-latest'
'macOS':
image: 'macos-14'
pool:
vmImage: $(image)
steps:
- script: |
sudo xcode-select -s /Applications/Xcode_$(CommunityToolkitSampleApp_Xcode_Version).app
sudo xcode-select -p
displayName: 'Set Xcode v$(CommunityToolkitSampleApp_Xcode_Version)'
condition: eq(variables['Agent.OS'], 'Darwin') # Only run this step on macOS
- task: UseDotNet@2
displayName: 'Install .NET SDK'
inputs:
packageType: 'sdk'
version: '$(NET_VERSION)'
includePreviewVersions: false

- task: CmdLine@2
displayName: 'Install .NET MAUI Workload'
inputs:
script : 'dotnet workload install maui'

- pwsh: |
Invoke-WebRequest 'https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1' -OutFile 'workload-install.ps1'
.\workload-install.ps1
displayName: Install Tizen Workload
# Print Information on the .NET SDK Used By the CI Build Host
# These logs are useful information when debugging CI Builds
# Note: This step doesn't execute nor modify any code; it is strictly used for logging + debugging purposes
- task: CmdLine@2
displayName: 'Display dotnet --info'
inputs:
script: dotnet --info

- task: CmdLine@2
displayName: 'Build CommunityToolkit.Maui.Markup.Sample'
inputs:
script: 'dotnet build -c Release $(PathToCommunityToolkitSampleCsproj)'

- job: build_library
displayName: Build Library
strategy:
matrix:
'Windows':
image: 'windows-latest'
'macOS':
image: 'macos-13'
image: 'macos-14'
pool:
vmImage: $(image)
steps:
Expand All @@ -73,11 +122,11 @@ jobs:
displayName: Set NuGet Version to PR Version
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['build.reason'], 'PullRequest'))
- task: CmdLine@2
displayName: 'Set Xcode v$(XcodeVersion)'
- script: |
sudo xcode-select -s /Applications/Xcode_$(CommunityToolkitLibrary_Xcode_Version).app
sudo xcode-select -p
displayName: 'Set Xcode v$(CommunityToolkitLibrary_Xcode_Version)'
condition: eq(variables['Agent.OS'], 'Darwin') # Only run this step on macOS
inputs:
script: echo '##vso[task.setvariable variable=MD_APPLE_SDK_ROOT;]'/Applications/Xcode_$(XcodeVersion).app;sudo xcode-select --switch /Applications/Xcode_$(XcodeVersion).app/Contents/Developer
- task: UseDotNet@2
displayName: 'Install .NET SDK'
Expand Down Expand Up @@ -115,11 +164,6 @@ jobs:
inputs:
script: 'dotnet build -c Release $(PathToCommunityToolkitCsproj)'

- task: CmdLine@2
displayName: 'Build CommunityToolkit.Maui.Markup.Sample'
inputs:
script: 'dotnet build -c Release $(PathToCommunityToolkitSampleCsproj)'

- task: CmdLine@2
displayName: 'Build CommunityToolkit.Maui.Markup.UnitTests'
inputs:
Expand Down Expand Up @@ -197,3 +241,58 @@ jobs:
inputs:
artifactName: nuget
pathToPublish: '$(Build.ArtifactStagingDirectory)'

- job: run_benchmarks
displayName: Run Benchmarks
strategy:
matrix:
'Windows':
image: 'windows-latest'
'macOS':
image: 'macos-14'
pool:
vmImage: $(image)
steps:
- script: |
sudo xcode-select -s /Applications/Xcode_$(CommunityToolkitLibrary_Xcode_Version).app
sudo xcode-select -p
displayName: 'Set Xcode v$(CommunityToolkitLibrary_Xcode_Version)'
condition: eq(variables['Agent.OS'], 'Darwin') # Only run this step on macOS
- task: UseDotNet@2
displayName: 'Install .NET SDK'
inputs:
packageType: 'sdk'
version: '$(NET_VERSION)'
includePreviewVersions: false

- task: CmdLine@2
displayName: 'Install .NET MAUI Workload'
inputs:
script : 'dotnet workload install maui'

- pwsh: |
Invoke-WebRequest 'https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1' -OutFile 'workload-install.ps1'
.\workload-install.ps1
displayName: Install Tizen Workload
# Print Information on the .NET SDK Used By the CI Build Host
# These logs are useful information when debugging CI Builds
# Note: This step doesn't execute nor modify any code; it is strictly used for logging + debugging purposes
- task: CmdLine@2
displayName: 'Display dotnet --info'
inputs:
script: dotnet --info

- task: CmdLine@2
displayName: 'Run Benchmarks'
inputs:
script : 'dotnet run --project $(PathToCommunityToolkitBenchmarkCsproj) -c Release -- -a $(Build.ArtifactStagingDirectory)'

# publish the Benchmark Results
- task: PublishBuildArtifacts@1
condition: eq(variables['Agent.OS'], 'Windows_NT') # Only run this step on Windows
displayName: 'Publish Benchmark Artifacts'
inputs:
artifactName: benchmarks
pathToPublish: '$(Build.ArtifactStagingDirectory)'
6 changes: 6 additions & 0 deletions samples/CommunityToolkit.Maui.Markup.Sample.sln
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{A919
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommunityToolkit.Maui.Markup.SourceGenerators", "..\src\CommunityToolkit.Maui.Markup.SourceGenerators\CommunityToolkit.Maui.Markup.SourceGenerators.csproj", "{533792FE-99CD-4B5B-A8B2-51A8BE3852A5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Maui.Markup.Benchmarks", "..\src\CommunityToolkit.Maui.Markup.Benchmarks\CommunityToolkit.Maui.Markup.Benchmarks.csproj", "{8C1B7D06-75D7-40AC-9FDB-344BF5FCCD5E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -44,6 +46,10 @@ Global
{533792FE-99CD-4B5B-A8B2-51A8BE3852A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{533792FE-99CD-4B5B-A8B2-51A8BE3852A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{533792FE-99CD-4B5B-A8B2-51A8BE3852A5}.Release|Any CPU.Build.0 = Release|Any CPU
{8C1B7D06-75D7-40AC-9FDB-344BF5FCCD5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C1B7D06-75D7-40AC-9FDB-344BF5FCCD5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C1B7D06-75D7-40AC-9FDB-344BF5FCCD5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C1B7D06-75D7-40AC-9FDB-344BF5FCCD5E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
60 changes: 60 additions & 0 deletions src/CommunityToolkit.Maui.Markup.Benchmarks/BaseTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using CommunityToolkit.Maui.Markup.Benchmarks.Mocks;

namespace CommunityToolkit.Maui.Markup.Benchmarks;

public abstract class BaseTest
{
protected BaseTest()
{
CreateAndSetMockApplication(out var serviceProvider);
ServiceProvider = serviceProvider;
}

protected IServiceProvider ServiceProvider { get; }

protected static TElementHandler CreateElementHandler<TElementHandler>(IElement view, bool hasMauiContext = true)
where TElementHandler : IElementHandler, new()
{
var mockElementHandler = new TElementHandler();
mockElementHandler.SetVirtualView(view);

if (hasMauiContext)
{
mockElementHandler.SetMauiContext(Application.Current?.Handler?.MauiContext ?? throw new NullReferenceException());
}

return mockElementHandler;
}

protected static TViewHandler CreateViewHandler<TViewHandler>(IView view, bool hasMauiContext = true)
where TViewHandler : IViewHandler, new()
{
var mockViewHandler = new TViewHandler();
mockViewHandler.SetVirtualView(view);

if (hasMauiContext)
{
mockViewHandler.SetMauiContext(Application.Current?.Handler?.MauiContext ?? throw new NullReferenceException());
}

return mockViewHandler;
}

static void CreateAndSetMockApplication(out IServiceProvider serviceProvider)
{
var appBuilder = MauiApp.CreateBuilder()
.UseMauiApp<MockApplication>();

appBuilder.Services.AddSingleton<IDispatcher>(_ => new MockDispatcherProvider().GetForCurrentThread());

var mauiApp = appBuilder.Build();

var application = mauiApp.Services.GetRequiredService<IApplication>();
serviceProvider = mauiApp.Services;

IPlatformApplication.Current = (IPlatformApplication)application;

application.Handler = new ApplicationHandlerStub();
application.Handler.SetMauiContext(new HandlersContextStub(mauiApp.Services));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using CommunityToolkit.Maui.Markup.Benchmarks.Extensions;

namespace CommunityToolkit.Maui.Markup.Benchmarks;

public abstract class ExecuteBindingsBase : BaseTest
{
protected const string helloWorldText = "Hello World";

protected ExecuteBindingsBase()
{
DefaultBindingsLabel = new()
{
BindingContext = DefaultBindingsLabelViewModel
};
DefaultBindingsLabel.SetBinding(Label.TextProperty, nameof(LabelViewModel.Text), mode: BindingMode.TwoWay);
DefaultBindingsLabel.SetBinding(Label.TextColorProperty, nameof(LabelViewModel.TextColor), mode: BindingMode.TwoWay);
DefaultBindingsLabel.EnableAnimations();

DefaultMarkupBindingsLabel = new Label
{
BindingContext = DefaultMarkupBindingsLabelViewModel
}.Bind(Label.TextProperty, nameof(LabelViewModel.Text), mode: BindingMode.TwoWay)
.Bind(Label.TextColorProperty, nameof(LabelViewModel.TextColor), mode: BindingMode.TwoWay);
DefaultMarkupBindingsLabel.EnableAnimations();

TypedMarkupBindingsLabel = new Label
{
BindingContext = TypedMarkupBindingsLabelViewModel
}.Bind(Label.TextProperty,
getter: (LabelViewModel vm) => vm.Text,
setter: (LabelViewModel vm, string text) => vm.Text = text,
mode: BindingMode.TwoWay)
.Bind(Label.TextColorProperty,
getter: (LabelViewModel vm) => vm.TextColor,
setter: (LabelViewModel vm, Color textColor) => vm.TextColor = textColor,
mode: BindingMode.TwoWay);
TypedMarkupBindingsLabel.EnableAnimations();
}

protected LabelViewModel DefaultBindingsLabelViewModel { get; } = new();
protected LabelViewModel DefaultMarkupBindingsLabelViewModel { get; } = new();
protected LabelViewModel TypedMarkupBindingsLabelViewModel { get; } = new();

protected Label DefaultBindingsLabel { get; }
protected Label DefaultMarkupBindingsLabel{ get; }
protected Label TypedMarkupBindingsLabel{ get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using BenchmarkDotNet.Attributes;

namespace CommunityToolkit.Maui.Markup.Benchmarks;

[MemoryDiagnoser]
public class ExecuteBindings_ViewModelToView : ExecuteBindingsBase
{
[Benchmark(Baseline = true)]
public void ExecuteDefaultBindings_ViewModelToView()
{
DefaultBindingsLabelViewModel.TextColor = Colors.Green;
DefaultBindingsLabelViewModel.Text = helloWorldText;
}

[Benchmark]
public void ExecuteDefaultBindingsMarkup_ViewModelToView()
{
DefaultMarkupBindingsLabelViewModel.TextColor = Colors.Green;
DefaultMarkupBindingsLabelViewModel.Text = helloWorldText;
}

[Benchmark]
public void ExecuteTypedBindingsMarkup_ViewModelToView()
{
TypedMarkupBindingsLabelViewModel.TextColor = Colors.Green;
TypedMarkupBindingsLabelViewModel.Text = helloWorldText;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using BenchmarkDotNet.Attributes;

namespace CommunityToolkit.Maui.Markup.Benchmarks;

[MemoryDiagnoser]
public class ExecuteBindings_ViewToViewModel : ExecuteBindingsBase
{
[Benchmark(Baseline = true)]
public void ExecuteDefaultBindings_ViewToViewModel()
{
DefaultBindingsLabel.TextColor = Colors.Green;
DefaultBindingsLabel.Text = helloWorldText;
}

[Benchmark]
public void ExecuteDefaultBindingsMarkup_ViewToViewModel()
{
DefaultMarkupBindingsLabel.TextColor = Colors.Green;
DefaultMarkupBindingsLabel.Text = helloWorldText;
}

[Benchmark]
public void ExecuteTypedBindingsMarkup_ViewToViewModel()
{
TypedMarkupBindingsLabel.TextColor = Colors.Green;
TypedMarkupBindingsLabel.Text = helloWorldText;
}
}
Loading

0 comments on commit 5d9ab90

Please sign in to comment.