-
Notifications
You must be signed in to change notification settings - Fork 819
Add Windows disk I/O metrics to ResourceMonitoring #6181
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
Merged
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
555b98e
create an empty file for WindowsDiskMetrics
makazeu 2e8a9be
Implement Windows Disk I/O bytes metric
makazeu fe0c09b
update
makazeu 664053a
Add SupportedOSPlatform attribute for Windows in disk metrics classes
makazeu 3180f66
update
makazeu ccb3d27
Fix property name for disk I/O metrics enabling in Windows
makazeu 24e60bd
update
makazeu f6957fe
Improve error handling in disk performance counter initialization
makazeu 07ceca6
Rename disk performance counter classes
makazeu 9e12912
Implement Disk Operations metric
makazeu 37c9e8a
Style updates
makazeu 8bba5a4
Add PlatformAttributes in LegacySupport
makazeu 878e61b
Add a simple unit test
makazeu e9985af
Add interfaces for PerformanceCounter
makazeu 6d96e50
update ut
makazeu 6095dd0
Merge branch 'main' into windows-disk-metrics
makazeu 718bc13
Use TimeProvider
makazeu db2949a
Add TimeProvider as a singleton in ResourceMonitoringServiceCollectio…
makazeu 12edc8a
Add unit tests for PerformanceCounterFactory and PerformanceCounterWr…
makazeu 23a0f3d
update
makazeu 6c108da
Add Unit Tests
makazeu 080ae7d
Refine
makazeu a3efed7
Refine
makazeu 7053f3f
Refine
makazeu 93ea836
Add WindowsDiskMetricsTests
makazeu 54836ec
Refine
makazeu a1b620e
Merge branch 'main' into windows-disk-metrics
makazeu a1de91a
clean
makazeu a0395c0
Refine
makazeu c0fbc4d
Merge branch 'main' into windows-disk-metrics
makazeu d9d9194
Merge branch 'dotnet:main' into windows-disk-metrics
makazeu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
171 changes: 171 additions & 0 deletions
171
src/LegacySupport/PlatformAttributes/PlatformAttributes.cs
This file contains hidden or 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,171 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
#pragma warning disable S1694 | ||
#pragma warning disable S3996 | ||
#pragma warning disable SA1128 | ||
#pragma warning disable SA1402 | ||
#pragma warning disable SA1513 | ||
#pragma warning disable SA1649 | ||
|
||
namespace System.Runtime.Versioning | ||
{ | ||
/// <summary> | ||
/// Base type for all platform-specific API attributes. | ||
/// </summary> | ||
#pragma warning disable CS3015 // Type has no accessible constructors which use only CLS-compliant types | ||
internal abstract class OSPlatformAttribute : Attribute | ||
#pragma warning restore CS3015 | ||
{ | ||
private protected OSPlatformAttribute(string platformName) | ||
{ | ||
PlatformName = platformName; | ||
} | ||
public string PlatformName { get; } | ||
} | ||
|
||
/// <summary> | ||
/// Records the platform that the project targeted. | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Assembly, | ||
AllowMultiple = false, Inherited = false)] | ||
internal sealed class TargetPlatformAttribute : OSPlatformAttribute | ||
{ | ||
public TargetPlatformAttribute(string platformName) : base(platformName) | ||
{ | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Records the operating system (and minimum version) that supports an API. Multiple attributes can be | ||
/// applied to indicate support on multiple operating systems. | ||
/// </summary> | ||
/// <remarks> | ||
/// Callers can apply a <see cref="SupportedOSPlatformAttribute " /> | ||
/// or use guards to prevent calls to APIs on unsupported operating systems. | ||
/// | ||
/// A given platform should only be specified once. | ||
/// </remarks> | ||
[AttributeUsage(AttributeTargets.Assembly | | ||
AttributeTargets.Class | | ||
AttributeTargets.Constructor | | ||
AttributeTargets.Enum | | ||
AttributeTargets.Event | | ||
AttributeTargets.Field | | ||
AttributeTargets.Interface | | ||
AttributeTargets.Method | | ||
AttributeTargets.Module | | ||
AttributeTargets.Property | | ||
AttributeTargets.Struct, | ||
AllowMultiple = true, Inherited = false)] | ||
internal sealed class SupportedOSPlatformAttribute : OSPlatformAttribute | ||
{ | ||
public SupportedOSPlatformAttribute(string platformName) : base(platformName) | ||
{ | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Marks APIs that were removed in a given operating system version. | ||
/// </summary> | ||
/// <remarks> | ||
/// Primarily used by OS bindings to indicate APIs that are only available in | ||
/// earlier versions. | ||
/// </remarks> | ||
[AttributeUsage(AttributeTargets.Assembly | | ||
AttributeTargets.Class | | ||
AttributeTargets.Constructor | | ||
AttributeTargets.Enum | | ||
AttributeTargets.Event | | ||
AttributeTargets.Field | | ||
AttributeTargets.Interface | | ||
AttributeTargets.Method | | ||
AttributeTargets.Module | | ||
AttributeTargets.Property | | ||
AttributeTargets.Struct, | ||
AllowMultiple = true, Inherited = false)] | ||
internal sealed class UnsupportedOSPlatformAttribute : OSPlatformAttribute | ||
{ | ||
public UnsupportedOSPlatformAttribute(string platformName) : base(platformName) | ||
{ | ||
} | ||
public UnsupportedOSPlatformAttribute(string platformName, string? message) : base(platformName) | ||
{ | ||
Message = message; | ||
} | ||
public string? Message { get; } | ||
} | ||
|
||
/// <summary> | ||
/// Marks APIs that were obsoleted in a given operating system version. | ||
/// </summary> | ||
/// <remarks> | ||
/// Primarily used by OS bindings to indicate APIs that should not be used anymore. | ||
/// </remarks> | ||
[AttributeUsage(AttributeTargets.Assembly | | ||
AttributeTargets.Class | | ||
AttributeTargets.Constructor | | ||
AttributeTargets.Enum | | ||
AttributeTargets.Event | | ||
AttributeTargets.Field | | ||
AttributeTargets.Interface | | ||
AttributeTargets.Method | | ||
AttributeTargets.Module | | ||
AttributeTargets.Property | | ||
AttributeTargets.Struct, | ||
AllowMultiple = true, Inherited = false)] | ||
internal sealed class ObsoletedOSPlatformAttribute : OSPlatformAttribute | ||
{ | ||
public ObsoletedOSPlatformAttribute(string platformName) : base(platformName) | ||
{ | ||
} | ||
public ObsoletedOSPlatformAttribute(string platformName, string? message) : base(platformName) | ||
{ | ||
Message = message; | ||
} | ||
public string? Message { get; } | ||
public string? Url { get; set; } | ||
} | ||
|
||
/// <summary> | ||
/// Annotates a custom guard field, property or method with a supported platform name and optional version. | ||
/// Multiple attributes can be applied to indicate guard for multiple supported platforms. | ||
/// </summary> | ||
/// <remarks> | ||
/// Callers can apply a <see cref="SupportedOSPlatformGuardAttribute " /> to a field, property or method | ||
/// and use that field, property or method in a conditional or assert statements in order to safely call platform specific APIs. | ||
/// | ||
/// The type of the field or property should be boolean, the method return type should be boolean in order to be used as platform guard. | ||
/// </remarks> | ||
[AttributeUsage(AttributeTargets.Field | | ||
AttributeTargets.Method | | ||
AttributeTargets.Property, | ||
AllowMultiple = true, Inherited = false)] | ||
internal sealed class SupportedOSPlatformGuardAttribute : OSPlatformAttribute | ||
{ | ||
public SupportedOSPlatformGuardAttribute(string platformName) : base(platformName) | ||
{ | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Annotates the custom guard field, property or method with an unsupported platform name and optional version. | ||
/// Multiple attributes can be applied to indicate guard for multiple unsupported platforms. | ||
/// </summary> | ||
/// <remarks> | ||
/// Callers can apply a <see cref="UnsupportedOSPlatformGuardAttribute " /> to a field, property or method | ||
/// and use that field, property or method in a conditional or assert statements as a guard to safely call APIs unsupported on those platforms. | ||
/// | ||
/// The type of the field or property should be boolean, the method return type should be boolean in order to be used as platform guard. | ||
/// </remarks> | ||
[AttributeUsage(AttributeTargets.Field | | ||
AttributeTargets.Method | | ||
AttributeTargets.Property, | ||
AllowMultiple = true, Inherited = false)] | ||
internal sealed class UnsupportedOSPlatformGuardAttribute : OSPlatformAttribute | ||
{ | ||
public UnsupportedOSPlatformGuardAttribute(string platformName) : base(platformName) | ||
{ | ||
} | ||
} | ||
} |
This file contains hidden or 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,9 @@ | ||
Enables use of C# OSPlatform attributes on older frameworks. | ||
|
||
To use this source in your project, add the following to your `.csproj` file: | ||
|
||
```xml | ||
<PropertyGroup> | ||
<InjectPlatformAttributesOnLegacy>true</InjectPlatformAttributesOnLegacy> | ||
</PropertyGroup> | ||
``` |
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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
83 changes: 83 additions & 0 deletions
83
...ft.Extensions.Diagnostics.ResourceMonitoring/Windows/Disk/WindowsDiskIoRatePerfCounter.cs
This file contains hidden or 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,83 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Runtime.Versioning; | ||
|
||
namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Disk; | ||
|
||
[SupportedOSPlatform("windows")] | ||
internal sealed class WindowsDiskIoRatePerfCounter | ||
{ | ||
private readonly List<IPerformanceCounter> _counters = []; | ||
private readonly IPerformanceCounterFactory _performanceCounterFactory; | ||
private readonly TimeProvider _timeProvider; | ||
private readonly string _categoryName; | ||
private readonly string _counterName; | ||
private readonly string[] _instanceNames; | ||
private long _lastTimestamp; | ||
|
||
internal WindowsDiskIoRatePerfCounter( | ||
IPerformanceCounterFactory performanceCounterFactory, | ||
TimeProvider timeProvider, | ||
string categoryName, | ||
string counterName, | ||
string[] instanceNames) | ||
{ | ||
_performanceCounterFactory = performanceCounterFactory; | ||
_timeProvider = timeProvider; | ||
_categoryName = categoryName; | ||
_counterName = counterName; | ||
_instanceNames = instanceNames; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the disk I/O measurements. | ||
/// Key: Disk name, Value: Total count. | ||
/// </summary> | ||
internal IDictionary<string, long> TotalCountDict { get; } = new ConcurrentDictionary<string, long>(); | ||
|
||
internal void InitializeDiskCounters() | ||
{ | ||
foreach (string instanceName in _instanceNames) | ||
{ | ||
// Skip the total instance | ||
if (instanceName.Equals("_Total", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
continue; | ||
} | ||
|
||
// Create counters for each disk | ||
_counters.Add(_performanceCounterFactory.Create(_categoryName, _counterName, instanceName)); | ||
TotalCountDict.Add(instanceName, 0); | ||
} | ||
|
||
// Initialize the counters to get the first value | ||
foreach (IPerformanceCounter counter in _counters) | ||
{ | ||
_ = counter.NextValue(); | ||
} | ||
|
||
_lastTimestamp = _timeProvider.GetUtcNow().ToUnixTimeMilliseconds(); | ||
} | ||
|
||
internal void UpdateDiskCounters() | ||
{ | ||
long currentTimestamp = _timeProvider.GetUtcNow().ToUnixTimeMilliseconds(); | ||
double elapsedSeconds = (currentTimestamp - _lastTimestamp) / 1000.0; // Convert to seconds | ||
|
||
// For the kind of "rate" perf counters, this algorithm calculates the total value over a time interval | ||
// by multiplying the per-second rate (e.g., Disk Bytes/sec) by the time interval between two samples. | ||
// This effectively reverses the per-second rate calculation to a total amount (e.g., total bytes transferred) during that period. | ||
foreach (IPerformanceCounter counter in _counters) | ||
{ | ||
// total value = per-second rate * elapsed seconds | ||
double value = counter.NextValue() * elapsedSeconds; | ||
TotalCountDict[counter.InstanceName] += (long)value; | ||
} | ||
|
||
_lastTimestamp = currentTimestamp; | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.