Skip to content

Commit

Permalink
Add utility for performance measurement, tracking the duration of sco…
Browse files Browse the repository at this point in the history
…ped code block. (#894)

* Add common performance measurement utility.
* Update unit test.
  • Loading branch information
ms-teli authored Jan 11, 2024
1 parent f7a2c53 commit 856da54
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 0 deletions.
14 changes: 14 additions & 0 deletions Microsoft.Health.sln
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lang", "lang", "{99CA0B4C-C
lang\IsExternalInit.cs = lang\IsExternalInit.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.MeasurementUtility", "src\Microsoft.Health.MeasurementUtility\Microsoft.Health.MeasurementUtility.csproj", "{2369BE93-FF96-4270-AD08-7A45F090BD00}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.MeasurementUtility.UnitTests", "src\Microsoft.Health.MeasurementUtility.UnitTests\Microsoft.Health.MeasurementUtility.UnitTests.csproj", "{E89B5131-D8C2-4AEC-9762-A123FA4314BC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -263,6 +267,14 @@ Global
{E2D4F975-9F71-416B-96E5-F2A5101FCBCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2D4F975-9F71-416B-96E5-F2A5101FCBCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2D4F975-9F71-416B-96E5-F2A5101FCBCD}.Release|Any CPU.Build.0 = Release|Any CPU
{2369BE93-FF96-4270-AD08-7A45F090BD00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2369BE93-FF96-4270-AD08-7A45F090BD00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2369BE93-FF96-4270-AD08-7A45F090BD00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2369BE93-FF96-4270-AD08-7A45F090BD00}.Release|Any CPU.Build.0 = Release|Any CPU
{E89B5131-D8C2-4AEC-9762-A123FA4314BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E89B5131-D8C2-4AEC-9762-A123FA4314BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E89B5131-D8C2-4AEC-9762-A123FA4314BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E89B5131-D8C2-4AEC-9762-A123FA4314BC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -307,6 +319,8 @@ Global
{85EE87C1-D278-47FC-A296-633D1DBF0E87} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{C65A48AC-6832-4F5D-AEFA-D601EEE18B7C} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{E2D4F975-9F71-416B-96E5-F2A5101FCBCD} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{2369BE93-FF96-4270-AD08-7A45F090BD00} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{E89B5131-D8C2-4AEC-9762-A123FA4314BC} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {562bbd07-1817-4af5-ab66-8837cf849248}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>Unit tests for common utilities used by Microsoft Health.</Description>
<TargetFrameworks>$(SupportedFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MediatR" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="NSubstitute" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.Health.MeasurementUtility\Microsoft.Health.MeasurementUtility.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Threading;
using Xunit;

namespace Microsoft.Health.MeasurementUtility.UnitTests;

public class PerformanceTests
{
[Fact]
public void GivenTheITimed_WhenBeingDisposed_ThenHandlerShouldBeInvoked()
{
bool hasHandlerInvoked = false;
using (ITimed timedHandler = Performance.TrackDuration(duration =>
{
hasHandlerInvoked = true;
Assert.True(duration > 1000);
}))
{
Thread.Sleep(1000);
}

Assert.True(hasHandlerInvoked);
}
}
15 changes: 15 additions & 0 deletions src/Microsoft.Health.MeasurementUtility/ITimed.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;

namespace Microsoft.Health.MeasurementUtility;

public interface ITimed : IDisposable
{
TimeSpan Elapsed { get; }

ITimed Record();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>Common utilities used by Microsoft Health.</Description>
<TargetFrameworks>$(SupportedFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Ensure.That" />
</ItemGroup>

</Project>
51 changes: 51 additions & 0 deletions src/Microsoft.Health.MeasurementUtility/Performance.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using EnsureThat;

namespace Microsoft.Health.MeasurementUtility;

public static class Performance
{
/// <summary>
/// Track the duration of the execution time in the life cycle of the ITimed.
/// </summary>
/// <param name="handler">The callback to handle the duration time.</param>
/// <returns></returns>
public static ITimed TrackDuration(Action<double> handler)
{
EnsureArg.IsNotNull(handler, nameof(handler));

return new TimedHandler
{
Stopwatch = Stopwatch.StartNew(),
Handler = handler,
};
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "The struct is Private.")]
private struct TimedHandler : ITimed
{
public Stopwatch Stopwatch { get; set; }

public Action<double> Handler { get; set; }

public TimeSpan Elapsed => Stopwatch.Elapsed;

public ITimed Record()
{
Handler(Elapsed.TotalMilliseconds);
return this;
}

public void Dispose()
{
Stopwatch.Stop();
Record();
}
}
}

0 comments on commit 856da54

Please sign in to comment.