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

[release/5.0] Fix reading performance counters on Windows ARM64 #46590

Merged
merged 4 commits into from
Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eng/packaging.props
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<PackageVersion Condition="'$(PackageVersion)' == ''">$(ProductVersion)</PackageVersion>
<!-- major.minor.release version of the platforms package we're currently building
Pre-release will be appended during build -->
<PlatformPackageVersion>$(ProductVersion)</PlatformPackageVersion>
<PlatformPackageVersion>5.0.0</PlatformPackageVersion>
<SkipValidatePackageTargetFramework>true</SkipValidatePackageTargetFramework>
<SkipGenerationCheck>true</SkipGenerationCheck>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal static partial class Libraries
internal const string Odbc32 = "odbc32.dll";
internal const string Ole32 = "ole32.dll";
internal const string OleAut32 = "oleaut32.dll";
internal const string PerfCounter = "perfcounter.dll";
internal const string Pdh = "pdh.dll";
Copy link
Member

Choose a reason for hiding this comment

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

pdh [](start = 37, length = 3)

just wondering, does pdh.dll exist on all Windows skus we support? I guess so but wanted to ensure we looked at that.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. It was already being used by perfcounter.dll so it will exist everywhere this worked before. It's been present in Windows since XP/2k3. It's also part of nano and server core.

Copy link
Member

Choose a reason for hiding this comment

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

perfcounter.dll (which it was using before) imports PdhFormatFromRaw value, which MSDN says back to Windows XP, eg
https://docs.microsoft.com/en-us/windows/win32/api/pdh/nf-pdh-pdhformatfromrawvalue

As for SKU's, the tests exclude only Nano server so it apparently is available on Server Core.

Copy link
Member

@danmoseley danmoseley Jan 5, 2021

Choose a reason for hiding this comment

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

Having said that, the old code presumably failed on Nano with Win32Exception here

and the new code presumably fails with EntrypointNotFoundException() ? Not sure that is important but just pointing it out.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, our comments crossed. Why do the tests exclude nano?

Copy link
Member

Choose a reason for hiding this comment

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

I guess Nano not carrying the full framework which means the PerfCounter.dll is absent there. but maybe after this change we can try to enable the test there and look if it will succeed.

Copy link
Member

Choose a reason for hiding this comment

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

Ah - of course. Well, that would be a happy result if it worked.

Copy link
Member Author

@ericstj ericstj Jan 5, 2021

Choose a reason for hiding this comment

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

My change did enable many test cases which read perf counters on nano. See many of the test cases which removed conditions completely. These tests are running and passing on nano.

I still conditioned a few tests which failed to write to perfcounters. I can't recall if I tried removing the write condition for nano or not. I can try this in master and see if we can enable more tests. It's somewhat irrelevant since folks won't be able to read the counters there due to lack of perfcounter.dll, but no harm in getting that coverage.

internal const string Secur32 = "secur32.dll";
internal const string Shell32 = "shell32.dll";
internal const string SspiCli = "sspicli.dll";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

internal partial class Interop
{
internal partial class PerfCounter
internal partial class Pdh
{
[DllImport(Libraries.PerfCounter, CharSet = CharSet.Unicode)]
public static extern unsafe int FormatFromRawValue(
[DllImport(Libraries.Pdh, CharSet = CharSet.Unicode)]
public static extern int PdhFormatFromRawValue(
uint dwCounterType,
uint dwFormat,
ref long pTimeBase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
<PropertyGroup>
<StrongNameKeyId>Open</StrongNameKeyId>
<IsWindowsSpecific>true</IsWindowsSpecific>
<PackageVersion>5.0.1</PackageVersion>
<AssemblyVersion>5.0.0.1</AssemblyVersion>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@
Link="Common\Interop\Windows\Kernel32\Interop.VirtualQuery.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.WaitForSingleObject.cs"
Link="Common\Interop\Windows\Kernel32\Interop.WaitForSingleObject.cs" />
<Compile Include="$(CommonPath)Interop\Windows\PerfCounter\Interop.FormatFromRawValue.cs"
Link="Common\Interop\Windows\PerfCounter\Interop.FormatFromRawValue.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Pdh\Interop.PdhFormatFromRawValue.cs"
Link="Common\Interop\Windows\Pdh\Interop.PdhFormatFromRawValue.cs" />
<Compile Include="$(CommonPath)Interop\Windows\PerfCounter\Interop.PerformanceData.cs"
Link="Common\Interop\Windows\PerfCounter\Interop.PerformanceData.cs" />
<Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeLocalAllocHandle.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ namespace System.Diagnostics
/// </summary>
public static class CounterSampleCalculator
{
private static volatile bool s_perfCounterDllLoaded;

/// <summary>
/// Converts 100NS elapsed time to fractional seconds
/// </summary>
Expand Down Expand Up @@ -89,11 +87,9 @@ public static float ComputeCounterValue(CounterSample oldSample, CounterSample n

FillInValues(oldSample, newSample, ref oldPdhValue, ref newPdhValue);

LoadPerfCounterDll();

Interop.Kernel32.PerformanceCounterOptions.PDH_FMT_COUNTERVALUE pdhFormattedValue = default;
long timeBase = newSample.SystemFrequency;
int result = Interop.PerfCounter.FormatFromRawValue((uint)newCounterType, Interop.Kernel32.PerformanceCounterOptions.PDH_FMT_DOUBLE | Interop.Kernel32.PerformanceCounterOptions.PDH_FMT_NOSCALE | Interop.Kernel32.PerformanceCounterOptions.PDH_FMT_NOCAP100,
int result = Interop.Pdh.PdhFormatFromRawValue((uint)newCounterType, Interop.Kernel32.PerformanceCounterOptions.PDH_FMT_DOUBLE | Interop.Kernel32.PerformanceCounterOptions.PDH_FMT_NOSCALE | Interop.Kernel32.PerformanceCounterOptions.PDH_FMT_NOCAP100,
ref timeBase, ref newPdhValue, ref oldPdhValue, ref pdhFormattedValue);

if (result != Interop.Errors.ERROR_SUCCESS)
Expand Down Expand Up @@ -227,21 +223,5 @@ private static void FillInValues(CounterSample oldSample, CounterSample newSampl
break;
}
}

private static void LoadPerfCounterDll()
{
if (s_perfCounterDllLoaded)
return;

string installPath = NetFrameworkUtils.GetLatestBuildDllDirectory(".");

string perfcounterPath = Path.Combine(installPath, "perfcounter.dll");
if (Interop.Kernel32.LoadLibrary(perfcounterPath) == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}

s_perfCounterDllLoaded = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ namespace System.Diagnostics.Tests
{
public static class CounterCreationDataCollectionTests
{
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationDataCollection_CreateCounterCreationDataCollection_Empty()
{
CounterCreationDataCollection ccdc = new CounterCreationDataCollection();
Assert.Equal(0, ccdc.Count);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationDataCollection_CreateCounterCreationDataCollection_CCDC()
{
CounterCreationData[] ccds = { new CounterCreationData("Simple1", "Simple Help", PerformanceCounterType.RawBase), new CounterCreationData("Simple2", "Simple Help", PerformanceCounterType.RawBase) };
Expand All @@ -27,7 +27,7 @@ public static void CounterCreationDataCollection_CreateCounterCreationDataCollec
Assert.Equal(2, ccdc2.Count);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationDataCollection_CreateCounterCreationDataCollection_Array()
{
CounterCreationData[] ccds = { new CounterCreationData("Simple1", "Simple Help", PerformanceCounterType.RawBase), new CounterCreationData("Simple2", "Simple Help", PerformanceCounterType.RawBase) };
Expand All @@ -37,7 +37,7 @@ public static void CounterCreationDataCollection_CreateCounterCreationDataCollec
Assert.Equal(0, ccdc.IndexOf(ccds[0]));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationDataCollection_CreateCounterCreationDataCollection_Invalid()
{
CounterCreationData[] ccds = null;
Expand All @@ -46,7 +46,7 @@ public static void CounterCreationDataCollection_CreateCounterCreationDataCollec
Assert.Throws<ArgumentNullException>(() => new CounterCreationDataCollection(ccdc));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationDataCollection_SetIndex2()
{
CounterCreationData[] ccds = { new CounterCreationData("Simple1", "Simple Help", PerformanceCounterType.RawBase), new CounterCreationData("Simple2", "Simple Help", PerformanceCounterType.RawBase) };
Expand All @@ -59,7 +59,7 @@ public static void CounterCreationDataCollection_SetIndex2()
Assert.Equal(ccd, ccdc[1]);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationDataCollection_Remove()
{
CounterCreationData[] ccds = { new CounterCreationData("Simple1", "Simple Help", PerformanceCounterType.RawBase), new CounterCreationData("Simple2", "Simple Help", PerformanceCounterType.RawBase) };
Expand All @@ -69,7 +69,7 @@ public static void CounterCreationDataCollection_Remove()
Assert.False(ccdc.Contains(ccds[0]));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationDataCollection_Insert()
{
CounterCreationData[] ccds = { new CounterCreationData("Simple1", "Simple Help", PerformanceCounterType.RawBase), new CounterCreationData("Simple2", "Simple Help", PerformanceCounterType.RawBase) };
Expand All @@ -82,7 +82,7 @@ public static void CounterCreationDataCollection_Insert()
Assert.Equal(1, ccdc.IndexOf(ccd));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationDataCollection_CopyTo()
{
CounterCreationData[] ccds = { new CounterCreationData("Simple1", "Simple Help", PerformanceCounterType.RawBase), new CounterCreationData("Simple2", "Simple Help", PerformanceCounterType.RawBase) };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace System.Diagnostics.Tests
{
public static class CounterCreationDataTests
{
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationData_CreateCounterCreationData_SimpleSimpleHelpRawBase()
{
CounterCreationData ccd = new CounterCreationData("Simple", "Simple Help", PerformanceCounterType.RawBase);
Expand All @@ -21,7 +21,7 @@ public static void CounterCreationData_CreateCounterCreationData_SimpleSimpleHel
Assert.Equal(PerformanceCounterType.RawBase, ccd.CounterType);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterCreationData_SetCounterType_Invalud()
{
CounterCreationData ccd = new CounterCreationData("Simple", "Simple Help", PerformanceCounterType.RawBase);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace System.Diagnostics.Tests
{
public static class CounterSampleCalculatorTests
{
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void CounterSampleCalculator_ElapsedTime()
{
var name = nameof(CounterSampleCalculator_ElapsedTime) + "_Counter";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace System.Diagnostics.Tests
{
public static class CounterSampleTests
{
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterSample_Constructor_EmptyCounterSample()
{
CounterSample counterSample = new CounterSample();
Expand All @@ -24,7 +24,7 @@ public static void CounterSample_Constructor_EmptyCounterSample()
Assert.Equal(0, counterSample.TimeStamp100nSec);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterSample_Constructor_CounterSample()
{
long timeStamp = DateTime.Now.ToFileTime();
Expand All @@ -39,17 +39,15 @@ public static void CounterSample_Constructor_CounterSample()
Assert.Equal(timeStamp, counterSample.TimeStamp100nSec);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34409", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
[Fact]
public static void CounterSample_Calculate_CalculateCounterSample()
{
CounterSample counterSample = new CounterSample(5, 0, 0, 0, 0, 0, PerformanceCounterType.NumberOfItems32);

Assert.Equal(5, CounterSample.Calculate(counterSample));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34409", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
[Fact]
public static void CounterSample_Calculate_CalculateCounterSampleCounterSample()
{
CounterSample counterSample1 = new CounterSample(5, 0, 0, 1, 0, 0, PerformanceCounterType.CounterDelta32);
Expand All @@ -58,7 +56,7 @@ public static void CounterSample_Calculate_CalculateCounterSampleCounterSample()
Assert.Equal(10, CounterSample.Calculate(counterSample1, counterSample2));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterSample_Equal()
{
CounterSample counterSample1 = new CounterSample(5, 0, 0, 1, 0, 0, PerformanceCounterType.CounterDelta32);
Expand All @@ -67,7 +65,7 @@ public static void CounterSample_Equal()
Assert.Equal(counterSample1, counterSample2);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterSample_opInequality()
{
CounterSample counterSample1 = new CounterSample(5, 0, 0, 1, 0, 0, PerformanceCounterType.CounterDelta32);
Expand All @@ -76,7 +74,7 @@ public static void CounterSample_opInequality()
Assert.True(counterSample1 != counterSample2);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterSample_opEquality()
{
CounterSample counterSample1 = new CounterSample(5, 0, 0, 1, 0, 0, PerformanceCounterType.CounterDelta32);
Expand All @@ -85,7 +83,7 @@ public static void CounterSample_opEquality()
Assert.True(counterSample1 == counterSample2);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void CounterSample_GetHashCode()
{
CounterSample counterSample1 = new CounterSample(5, 0, 0, 1, 0, 0, PerformanceCounterType.CounterDelta32);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.IO;
using System.Threading;
using Xunit;

Expand All @@ -12,7 +13,9 @@ namespace System.Diagnostics.Tests
internal class Helpers
{
public static bool IsElevatedAndCanWriteToPerfCounters { get => AdminHelpers.IsProcessElevated() && CanWriteToPerfCounters; }
public static bool CanWriteToPerfCounters { get => PlatformDetection.IsNotWindowsNanoServer && PlatformDetection.IsNotArmNorArm64Process; }
public static bool IsElevatedAndCanWriteAndReadNetPerfCounters { get => AdminHelpers.IsProcessElevated() && CanWriteToPerfCounters && CanReadNetPerfCounters; }
public static bool CanWriteToPerfCounters { get => PlatformDetection.IsNotWindowsNanoServer; }
public static bool CanReadNetPerfCounters { get => File.Exists(Environment.SystemDirectory + Path.DirectorySeparatorChar + "netfxperf.dll"); }

public static string CreateCategory(string name, PerformanceCounterCategoryType categoryType)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace System.Diagnostics.Tests
{
public static class InstanceDataTests
{
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceData_CreateInstanceData_FromCounterSample()
{
long timestamp = DateTime.Now.ToFileTime();
Expand All @@ -22,7 +22,7 @@ public static void InstanceData_CreateInstanceData_FromCounterSample()
Assert.Equal(1, id.RawValue);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollection_GetItem_ExistingCounter()
{
InstanceDataCollection idc = GetInstanceDataCollection();
Expand All @@ -41,7 +41,7 @@ public static void InstanceDataCollection_GetItem_ExistingCounter()
}
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollection_NullTest()
{
InstanceDataCollection idc = GetInstanceDataCollection();
Expand All @@ -50,7 +50,7 @@ public static void InstanceDataCollection_NullTest()
Assert.Throws<ArgumentNullException>(() => idc.Contains(null));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollection_GetKeys()
{
InstanceDataCollection idc = GetInstanceDataCollection();
Expand All @@ -61,7 +61,7 @@ public static void InstanceDataCollection_GetKeys()
Assert.True(keys.Length > 0);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollection_GetValues()
{
InstanceDataCollection idc = GetInstanceDataCollection();
Expand All @@ -72,47 +72,47 @@ public static void InstanceDataCollection_GetValues()
Assert.True(values.Length > 0);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollectionCollection_GetItem_Invalid()
{
InstanceDataCollectionCollection idcc = GetInstanceDataCollectionCollection();

Assert.Throws<ArgumentNullException>(() => idcc[null]);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollectionCollection_GetKeys()
{
InstanceDataCollectionCollection idcc = GetInstanceDataCollectionCollection();

Assert.True(idcc.Keys.Count > 0);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollectionCollection_GetValues()
{
InstanceDataCollectionCollection idcc = GetInstanceDataCollectionCollection();

Assert.True(idcc.Values.Count > 0);
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollectionCollection_Contains_Valid()
{
InstanceDataCollectionCollection idcc = GetInstanceDataCollectionCollection();

Assert.False(idcc.Contains("Not a real instance"));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollectionCollection_Contains_inValid()
{
InstanceDataCollectionCollection idcc = GetInstanceDataCollectionCollection();

Assert.Throws<ArgumentNullException>(() => idcc.Contains(null));
}

[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
[Fact]
public static void InstanceDataCollectionCollection_CopyTo()
{
InstanceDataCollectionCollection idcc = GetInstanceDataCollectionCollection();
Expand Down
Loading