From 47da7c7f3785a8cdb6dac865f83fa5e9fbbadb9d Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 8 Feb 2024 15:14:22 +0100 Subject: [PATCH 01/10] Dump select counters after running functional tests. --- .../Net/Quic/Interop/msquic_generated.cs | 1 + .../MsQuicCipherSuitesPolicyTests.cs | 1 + .../MsQuicRemoteExecutorTests.cs | 1 + .../tests/FunctionalTests/MsQuicTests.cs | 1 + .../FunctionalTests/QuicConnectionTests.cs | 1 + .../FunctionalTests/QuicCountersFixture.cs | 66 +++++++++++++++++++ .../FunctionalTests/QuicListenerTests.cs | 1 + ...icStreamConnectedStreamConformanceTests.cs | 1 + .../tests/FunctionalTests/QuicStreamTests.cs | 13 ++-- 9 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs index b8c0b092df1df7..ad781e6ddd7c7e 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs @@ -929,6 +929,7 @@ internal enum QUIC_PERFORMANCE_COUNTERS PATH_FAILURE, SEND_STATELESS_RESET, SEND_STATELESS_RETRY, + CONN_LOAD_REJECT, MAX, } diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs index 459b9bce810dca..ec9fe8366e5e70 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs @@ -9,6 +9,7 @@ namespace System.Net.Quic.Tests { [Collection(nameof(DisableParallelization))] + [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] [SkipOnPlatform(TestPlatforms.Windows, "CipherSuitesPolicy is not supported on Windows")] public class MsQuicCipherSuitesPolicyTests : QuicTestBase diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs index 051ead9b3bb2ec..fedab2baf7e677 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs @@ -13,6 +13,7 @@ namespace System.Net.Quic.Tests { [Collection(nameof(DisableParallelization))] + [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public class MsQuicRemoteExecutorTests : QuicTestBase { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs index 4a11909d30bfef..3e17de3a503056 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs @@ -47,6 +47,7 @@ public void Dispose() } [Collection(nameof(DisableParallelization))] + [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public class MsQuicTests : QuicTestBase, IClassFixture { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs index 98d72124f0048c..0c3c0788cb3e73 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs @@ -14,6 +14,7 @@ namespace System.Net.Quic.Tests using Configuration = System.Net.Test.Common.Configuration; [Collection(nameof(DisableParallelization))] + [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicConnectionTests : QuicTestBase { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs new file mode 100644 index 00000000000000..b3ad95990b2392 --- /dev/null +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.DotNet.XUnitExtensions; +using System; +using System.Net.Quic; +using System.Reflection; +using System.Text; +using System.Linq; +using Xunit; +using Xunit.Abstractions; + +using Microsoft.Quic; +using static Microsoft.Quic.MsQuic; + +public class QuicCountersListener : IDisposable +{ + public unsafe void Dispose() + { + Type msQuicApiType = Type.GetType("System.Net.Quic.MsQuicApi, System.Net.Quic"); + object msQuicApiInstance = msQuicApiType.GetProperty("Api", BindingFlags.NonPublic | BindingFlags.Static).GetGetMethod(true).Invoke(null, Array.Empty()); + QUIC_API_TABLE* apiTable = (QUIC_API_TABLE*)(Pointer.Unbox(msQuicApiType.GetProperty("ApiTable").GetGetMethod().Invoke(msQuicApiInstance, Array.Empty()))); + + long[] counters = new long[(int)QUIC_PERFORMANCE_COUNTERS.MAX]; + int countersAvailable; + + int status; + fixed (long* pCounters = counters) + { + uint size = (uint)counters.Length * sizeof(long); + status = apiTable->GetParam(null, QUIC_PARAM_GLOBAL_PERF_COUNTERS, &size, (byte*)pCounters); + countersAvailable = (int)size / sizeof(long); + } + + if (StatusFailed(status)) + { + System.Console.WriteLine($"Failed to read MsQuic counters: {status}"); + return; + } + + + StringBuilder sb = new StringBuilder(); + sb.AppendLine("MsQuic Counters:"); + + int maxlen = Enum.GetNames(typeof(QUIC_PERFORMANCE_COUNTERS)).Max(s => s.Length); + void DumpCounter(QUIC_PERFORMANCE_COUNTERS counter) + { + var name = $"{counter}:".PadRight(maxlen + 1); + var index = (int)counter; + var value = index < countersAvailable ? counters[(int)counter].ToString() : "N/A"; + sb.AppendLine($" {counter} {value}"); + } + + DumpCounter(QUIC_PERFORMANCE_COUNTERS.CONN_CREATED); + DumpCounter(QUIC_PERFORMANCE_COUNTERS.CONN_HANDSHAKE_FAIL); + DumpCounter(QUIC_PERFORMANCE_COUNTERS.CONN_APP_REJECT); + DumpCounter(QUIC_PERFORMANCE_COUNTERS.CONN_LOAD_REJECT); + + System.Console.WriteLine(sb.ToString()); + } +} + +[CollectionDefinition(nameof(QuicCountersListener))] +public class QuicCountersCollection : ICollectionFixture +{ +} \ No newline at end of file diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs index d9e27a9e394c4c..102316065ef60b 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs @@ -14,6 +14,7 @@ namespace System.Net.Quic.Tests { [Collection(nameof(DisableParallelization))] + [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicListenerTests : QuicTestBase { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs index e224bf75c55312..24df417fa3eb22 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs @@ -15,6 +15,7 @@ namespace System.Net.Quic.Tests { [Collection(nameof(DisableParallelization))] + [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicStreamConformanceTests : ConnectedStreamConformanceTests { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs index 72d0995823edc3..33d49d89bdf743 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs @@ -13,6 +13,7 @@ namespace System.Net.Quic.Tests { [Collection(nameof(DisableParallelization))] + [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicStreamTests : QuicTestBase { @@ -1211,16 +1212,16 @@ async ValueTask ReleaseOnReadsClosedAsync() private const int SmallestPayload = 1; private const int SmallPayload = 1024; - private const int BufferPayload = 64*1024; - private const int BufferPlusPayload = 64*1024+1; - private const int BigPayload = 1024*1024*1024; + private const int BufferPayload = 64 * 1024; + private const int BufferPlusPayload = 64 * 1024 + 1; + private const int BigPayload = 1024 * 1024 * 1024; public static IEnumerable PayloadSizeAndTwoBools() { - var boolValues = new [] { true, false }; + var boolValues = new[] { true, false }; var payloadValues = !PlatformDetection.IsInHelix ? - new [] { SmallestPayload, SmallPayload, BufferPayload, BufferPlusPayload, BigPayload } : - new [] { SmallestPayload, SmallPayload, BufferPayload, BufferPlusPayload }; + new[] { SmallestPayload, SmallPayload, BufferPayload, BufferPlusPayload, BigPayload } : + new[] { SmallestPayload, SmallPayload, BufferPayload, BufferPlusPayload }; return from payload in payloadValues from bool1 in boolValues From 49142ad2f001f08d210dcabfed2732867134551b Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 8 Feb 2024 15:17:55 +0100 Subject: [PATCH 02/10] V1 of counter implementation --- .../Quic/Internal/MsQuicApi.NativeMethods.cs | 14 ++-- .../src/System/Net/Quic/Internal/MsQuicApi.cs | 1 + .../System/Net/Quic/Internal/MsQuicHelpers.cs | 2 +- .../Net/Quic/NetEventSource.Quic.Counters.cs | 77 +++++++++++++++++++ 4 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.NativeMethods.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.NativeMethods.cs index 206eac76ac7878..eaac29a02240c1 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.NativeMethods.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.NativeMethods.cs @@ -63,31 +63,31 @@ public int SetParam(MsQuicSafeHandle handle, uint param, uint bufferLength, void bool success = false; try { - handle.DangerousAddRef(ref success); - return ApiTable->SetParam(handle.QuicHandle, param, bufferLength, buffer); + handle?.DangerousAddRef(ref success); + return ApiTable->SetParam(handle != null ? handle.QuicHandle : null, param, bufferLength, buffer); } finally { if (success) { - handle.DangerousRelease(); + handle!.DangerousRelease(); } } } - public int GetParam(MsQuicSafeHandle handle, uint param, uint* bufferLength, void* buffer) + public int GetParam(MsQuicSafeHandle? handle, uint param, uint* bufferLength, void* buffer) { bool success = false; try { - handle.DangerousAddRef(ref success); - return ApiTable->GetParam(handle.QuicHandle, param, bufferLength, buffer); + handle?.DangerousAddRef(ref success); + return ApiTable->GetParam(handle != null ? handle.QuicHandle : null, param, bufferLength, buffer); } finally { if (success) { - handle.DangerousRelease(); + handle!.DangerousRelease(); } } } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index e89119844c744c..d3db1cb36a0ef4 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -48,6 +48,7 @@ private MsQuicApi(QUIC_API_TABLE* apiTable) ThrowHelper.ThrowIfMsQuicError(ApiTable->RegistrationOpen(&cfg, &handle), "RegistrationOpen failed"); Registration = new MsQuicSafeHandle(handle, apiTable->RegistrationClose, SafeHandleType.Registration); + // QuicTelemetry.EnsureInitialized(); } } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicHelpers.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicHelpers.cs index fee4e1aade7dfb..83452b34f8ea3b 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicHelpers.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicHelpers.cs @@ -61,7 +61,7 @@ internal static unsafe T GetMsQuicParameter(MsQuicSafeHandle handle, uint par GetMsQuicParameter(handle, parameter, (uint)sizeof(T), (byte*)&value); return value; } - internal static unsafe void GetMsQuicParameter(MsQuicSafeHandle handle, uint parameter, uint length, byte* value) + internal static unsafe void GetMsQuicParameter(MsQuicSafeHandle? handle, uint parameter, uint length, byte* value) { int status = MsQuicApi.Api.GetParam( handle, diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs new file mode 100644 index 00000000000000..2070f8a7756b30 --- /dev/null +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.Tracing; +using System.Net.Quic; + +using Microsoft.Quic; +using static Microsoft.Quic.MsQuic; + +namespace System.Net +{ + internal sealed partial class NetEventSource + { + private static readonly long[] s_counters = new long[(int)QUIC_PERFORMANCE_COUNTERS.MAX]; + + private IncrementingPollingCounter? _connCreated; + private IncrementingPollingCounter? _connHandshakeFail; + private IncrementingPollingCounter? _connAppReject; + private IncrementingPollingCounter? _connLoadReject; + + protected override void OnEventCommand(EventCommandEventArgs command) + { + if (command.Command == EventCommand.Enable && MsQuicApi.IsQuicSupported) + { + _connCreated ??= new IncrementingPollingCounter("CONN_CREATED", this, () => GetCounter(QUIC_PERFORMANCE_COUNTERS.CONN_CREATED)) + { + DisplayName = "Connections Created", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _connHandshakeFail ??= new IncrementingPollingCounter("CONN_HANDSHAKE_FAIL", this, () => GetCounter(QUIC_PERFORMANCE_COUNTERS.CONN_HANDSHAKE_FAIL)) + { + DisplayName = "Connection Handshake Failures", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _connAppReject ??= new IncrementingPollingCounter("CONN_APP_REJECT", this, () => GetCounter(QUIC_PERFORMANCE_COUNTERS.CONN_APP_REJECT)) + { + DisplayName = "Connections Rejected on Application Layer", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _connLoadReject ??= new IncrementingPollingCounter("CONN_LOAD_REJECT", this, () => GetCounter(QUIC_PERFORMANCE_COUNTERS.CONN_LOAD_REJECT)) + { + DisplayName = "Connections Rejected due to worker load", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + } + } + + [NonEvent] + private void UpdateCounters() + { + // if (!MsQuicApi.IsQuicSupported) + // { + // // MsQuicApi static ctor also uses this event source for logging, so if this event source is enabled, logging can + // // actually transitively call this method. Since IsQuicSupported is set at the very end of that method, we just + // return; + // } + + unsafe + { + fixed (long* pCounters = s_counters) + { + MsQuicHelpers.GetMsQuicParameter(null, QUIC_PARAM_GLOBAL_PERF_COUNTERS, (uint)s_counters.Length * sizeof(long), (byte*)pCounters); + } + } + } + + [NonEvent] + private long GetCounter(QUIC_PERFORMANCE_COUNTERS counter) + { + UpdateCounters(); + return s_counters[(int)counter]; + } + } +} From 3c8489914dcf28894962959545fc2a05ada6382e Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 8 Feb 2024 15:55:45 +0100 Subject: [PATCH 03/10] Fix compilation --- .../tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs | 1 - .../tests/FunctionalTests/MsQuicRemoteExecutorTests.cs | 1 - .../System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs | 1 - .../tests/FunctionalTests/QuicConnectionTests.cs | 1 - .../tests/FunctionalTests/QuicCountersFixture.cs | 2 +- .../System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs | 1 - .../QuicStreamConnectedStreamConformanceTests.cs | 1 - .../System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs | 1 - 8 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs index ec9fe8366e5e70..367993c10e1623 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs @@ -8,7 +8,6 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(DisableParallelization))] [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] [SkipOnPlatform(TestPlatforms.Windows, "CipherSuitesPolicy is not supported on Windows")] diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs index fedab2baf7e677..b8df47509c660a 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs @@ -12,7 +12,6 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(DisableParallelization))] [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public class MsQuicRemoteExecutorTests : QuicTestBase diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs index 3e17de3a503056..63a1e44ea68ecc 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs @@ -46,7 +46,6 @@ public void Dispose() } } - [Collection(nameof(DisableParallelization))] [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public class MsQuicTests : QuicTestBase, IClassFixture diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs index 0c3c0788cb3e73..b21e162d4b4ffa 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs @@ -13,7 +13,6 @@ namespace System.Net.Quic.Tests { using Configuration = System.Net.Test.Common.Configuration; - [Collection(nameof(DisableParallelization))] [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicConnectionTests : QuicTestBase diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs index b3ad95990b2392..6d0a1a68b7c084 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs @@ -60,7 +60,7 @@ void DumpCounter(QUIC_PERFORMANCE_COUNTERS counter) } } -[CollectionDefinition(nameof(QuicCountersListener))] +[CollectionDefinition(nameof(QuicCountersListener), DisableParallelization = true)] public class QuicCountersCollection : ICollectionFixture { } \ No newline at end of file diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs index 102316065ef60b..f7c02a03f3dd74 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs @@ -13,7 +13,6 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(DisableParallelization))] [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicListenerTests : QuicTestBase diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs index 24df417fa3eb22..ec4323f0ae4605 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs @@ -14,7 +14,6 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(DisableParallelization))] [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicStreamConformanceTests : ConnectedStreamConformanceTests diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs index 33d49d89bdf743..55e3939292c5f0 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs @@ -12,7 +12,6 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(DisableParallelization))] [Collection(nameof(QuicCountersListener))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicStreamTests : QuicTestBase From 52269b108d15e6c7dea62528fc17f93ad4f03b31 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 14 Feb 2024 14:52:24 +0100 Subject: [PATCH 04/10] Switch to Metrics API --- .../src/System.Net.Quic.csproj | 1 + .../Net/Quic/NetEventSource.Quic.Counters.cs | 127 ++++++++++++------ 2 files changed, 86 insertions(+), 42 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj b/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj index 40351864618018..7351b0a3a4555d 100644 --- a/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj +++ b/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj @@ -131,6 +131,7 @@ + diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs index 2070f8a7756b30..897821ce36095d 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Diagnostics.Tracing; +using System.Diagnostics.Metrics; using System.Net.Quic; using Microsoft.Quic; @@ -11,67 +13,108 @@ namespace System.Net { internal sealed partial class NetEventSource { + private static Meter s_meter = new Meter("Private.InternalDiagnostics.System.Net.Quic"); private static readonly long[] s_counters = new long[(int)QUIC_PERFORMANCE_COUNTERS.MAX]; - private IncrementingPollingCounter? _connCreated; - private IncrementingPollingCounter? _connHandshakeFail; - private IncrementingPollingCounter? _connAppReject; - private IncrementingPollingCounter? _connLoadReject; + public static readonly ObservableGauge MsQuicCountersGauge = s_meter.CreateObservableGauge( + name: "MsQuic", + observeValues: GetGauges, + unit: null, + description: "MsQuic performance counters"); - protected override void OnEventCommand(EventCommandEventArgs command) + public static readonly ObservableCounter MsQuicCountersCounter = s_meter.CreateObservableCounter( + name: "MsQuic", + observeValues: GetCounters, + unit: null, + description: "MsQuic performance counters"); + + [NonEvent] + private static void UpdateCounters() { - if (command.Command == EventCommand.Enable && MsQuicApi.IsQuicSupported) + unsafe { - _connCreated ??= new IncrementingPollingCounter("CONN_CREATED", this, () => GetCounter(QUIC_PERFORMANCE_COUNTERS.CONN_CREATED)) - { - DisplayName = "Connections Created", - DisplayRateTimeScale = TimeSpan.FromSeconds(1) - }; - - _connHandshakeFail ??= new IncrementingPollingCounter("CONN_HANDSHAKE_FAIL", this, () => GetCounter(QUIC_PERFORMANCE_COUNTERS.CONN_HANDSHAKE_FAIL)) - { - DisplayName = "Connection Handshake Failures", - DisplayRateTimeScale = TimeSpan.FromSeconds(1) - }; - - _connAppReject ??= new IncrementingPollingCounter("CONN_APP_REJECT", this, () => GetCounter(QUIC_PERFORMANCE_COUNTERS.CONN_APP_REJECT)) - { - DisplayName = "Connections Rejected on Application Layer", - DisplayRateTimeScale = TimeSpan.FromSeconds(1) - }; - - _connLoadReject ??= new IncrementingPollingCounter("CONN_LOAD_REJECT", this, () => GetCounter(QUIC_PERFORMANCE_COUNTERS.CONN_LOAD_REJECT)) + fixed (long* pCounters = s_counters) { - DisplayName = "Connections Rejected due to worker load", - DisplayRateTimeScale = TimeSpan.FromSeconds(1) - }; + MsQuicHelpers.GetMsQuicParameter(null, QUIC_PARAM_GLOBAL_PERF_COUNTERS, (uint)s_counters.Length * sizeof(long), (byte*)pCounters); + } } } [NonEvent] - private void UpdateCounters() + private static IEnumerable> GetGauges() { - // if (!MsQuicApi.IsQuicSupported) - // { - // // MsQuicApi static ctor also uses this event source for logging, so if this event source is enabled, logging can - // // actually transitively call this method. Since IsQuicSupported is set at the very end of that method, we just - // return; - // } + if (!MsQuicApi.IsQuicSupported) + { + // Avoid calling into MsQuic if not supported (or not initialized yet) + return Array.Empty>(); + } - unsafe + UpdateCounters(); + + var measurements = new List>(); + + static void AddMeasurement(List> measurements, QUIC_PERFORMANCE_COUNTERS counter) { - fixed (long* pCounters = s_counters) - { - MsQuicHelpers.GetMsQuicParameter(null, QUIC_PARAM_GLOBAL_PERF_COUNTERS, (uint)s_counters.Length * sizeof(long), (byte*)pCounters); - } + measurements.Add(new Measurement(s_counters[(int)counter], new KeyValuePair("Name", counter))); } + + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_ACTIVE); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_CONNECTED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.STRM_ACTIVE); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_QUEUE_DEPTH); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_OPER_QUEUE_DEPTH); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.WORK_OPER_QUEUE_DEPTH); + + return measurements; } + [NonEvent] - private long GetCounter(QUIC_PERFORMANCE_COUNTERS counter) + private static IEnumerable> GetCounters() { + if (!MsQuicApi.IsQuicSupported) + { + // Avoid calling into MsQuic if not supported (or not initialized yet) + return Array.Empty>(); + } + UpdateCounters(); - return s_counters[(int)counter]; + + var measurements = new List>(); + + static void AddMeasurement(List> measurements, QUIC_PERFORMANCE_COUNTERS counter) + { + measurements.Add(new Measurement(s_counters[(int)counter], new KeyValuePair("Name", counter))); + } + + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_CREATED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_HANDSHAKE_FAIL); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_APP_REJECT); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_RESUMED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_PROTOCOL_ERRORS); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_NO_ALPN); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PKTS_SUSPECTED_LOST); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PKTS_DROPPED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PKTS_DECRYPTION_FAIL); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_RECV); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_SEND); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_RECV_BYTES); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_SEND_BYTES); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_RECV_EVENTS); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_SEND_CALLS); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.APP_SEND_BYTES); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.APP_RECV_BYTES); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_OPER_QUEUED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_OPER_COMPLETED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.WORK_OPER_QUEUED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.WORK_OPER_COMPLETED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PATH_VALIDATED); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PATH_FAILURE); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.SEND_STATELESS_RESET); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.SEND_STATELESS_RETRY); + AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_LOAD_REJECT); + + return measurements; } } } From f23ecd4c4f4d9523a716c5ecde5099dc8deca3a6 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 15 Feb 2024 12:54:50 +0100 Subject: [PATCH 05/10] Code review feedback --- .../Net/Quic/Internal/MsQuicApi.NativeMethods.cs | 14 +++++++------- .../src/System/Net/Quic/Internal/MsQuicApi.cs | 1 - .../src/System/Net/Quic/Internal/MsQuicHelpers.cs | 2 +- .../Net/Quic/NetEventSource.Quic.Counters.cs | 3 ++- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.NativeMethods.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.NativeMethods.cs index eaac29a02240c1..206eac76ac7878 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.NativeMethods.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.NativeMethods.cs @@ -63,31 +63,31 @@ public int SetParam(MsQuicSafeHandle handle, uint param, uint bufferLength, void bool success = false; try { - handle?.DangerousAddRef(ref success); - return ApiTable->SetParam(handle != null ? handle.QuicHandle : null, param, bufferLength, buffer); + handle.DangerousAddRef(ref success); + return ApiTable->SetParam(handle.QuicHandle, param, bufferLength, buffer); } finally { if (success) { - handle!.DangerousRelease(); + handle.DangerousRelease(); } } } - public int GetParam(MsQuicSafeHandle? handle, uint param, uint* bufferLength, void* buffer) + public int GetParam(MsQuicSafeHandle handle, uint param, uint* bufferLength, void* buffer) { bool success = false; try { - handle?.DangerousAddRef(ref success); - return ApiTable->GetParam(handle != null ? handle.QuicHandle : null, param, bufferLength, buffer); + handle.DangerousAddRef(ref success); + return ApiTable->GetParam(handle.QuicHandle, param, bufferLength, buffer); } finally { if (success) { - handle!.DangerousRelease(); + handle.DangerousRelease(); } } } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index d3db1cb36a0ef4..e89119844c744c 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -48,7 +48,6 @@ private MsQuicApi(QUIC_API_TABLE* apiTable) ThrowHelper.ThrowIfMsQuicError(ApiTable->RegistrationOpen(&cfg, &handle), "RegistrationOpen failed"); Registration = new MsQuicSafeHandle(handle, apiTable->RegistrationClose, SafeHandleType.Registration); - // QuicTelemetry.EnsureInitialized(); } } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicHelpers.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicHelpers.cs index 83452b34f8ea3b..fee4e1aade7dfb 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicHelpers.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicHelpers.cs @@ -61,7 +61,7 @@ internal static unsafe T GetMsQuicParameter(MsQuicSafeHandle handle, uint par GetMsQuicParameter(handle, parameter, (uint)sizeof(T), (byte*)&value); return value; } - internal static unsafe void GetMsQuicParameter(MsQuicSafeHandle? handle, uint parameter, uint length, byte* value) + internal static unsafe void GetMsQuicParameter(MsQuicSafeHandle handle, uint parameter, uint length, byte* value) { int status = MsQuicApi.Api.GetParam( handle, diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs index 897821ce36095d..b51c2009772c34 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs @@ -35,7 +35,8 @@ private static void UpdateCounters() { fixed (long* pCounters = s_counters) { - MsQuicHelpers.GetMsQuicParameter(null, QUIC_PARAM_GLOBAL_PERF_COUNTERS, (uint)s_counters.Length * sizeof(long), (byte*)pCounters); + uint size = (uint)s_counters.Length * sizeof(long); + MsQuicApi.Api.ApiTable->GetParam(null, QUIC_PARAM_GLOBAL_PERF_COUNTERS, &size, (byte*)pCounters); } } } From 49be6e4ea98a5db8bda9aef0b06f6e90a3f5b89f Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Mon, 19 Feb 2024 12:30:54 +0100 Subject: [PATCH 06/10] Rename to QuicTestCollection --- .../MsQuicCipherSuitesPolicyTests.cs | 4 +- .../MsQuicPlatformDetectionTests.cs | 1 + .../MsQuicRemoteExecutorTests.cs | 2 +- .../tests/FunctionalTests/MsQuicTests.cs | 2 +- .../FunctionalTests/QuicConnectionTests.cs | 2 +- .../FunctionalTests/QuicCountersFixture.cs | 52 +++++++++++++++---- .../FunctionalTests/QuicListenerTests.cs | 2 +- ...icStreamConnectedStreamConformanceTests.cs | 2 +- .../tests/FunctionalTests/QuicStreamTests.cs | 2 +- .../tests/FunctionalTests/QuicTestBase.cs | 24 +-------- 10 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs index 367993c10e1623..2d95e08c743923 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs @@ -8,7 +8,7 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(QuicCountersListener))] + [Collection(nameof(QuicTestCollection))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] [SkipOnPlatform(TestPlatforms.Windows, "CipherSuitesPolicy is not supported on Windows")] public class MsQuicCipherSuitesPolicyTests : QuicTestBase @@ -77,4 +77,4 @@ await Assert.ThrowsAsync(() => TestConnection( )); } } -} \ No newline at end of file +} diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicPlatformDetectionTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicPlatformDetectionTests.cs index 16f267fc719535..891e6c7350218b 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicPlatformDetectionTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicPlatformDetectionTests.cs @@ -8,6 +8,7 @@ namespace System.Net.Quic.Tests { + [Collection(nameof(QuicTestCollection))] public class MsQuicPlatformDetectionTests : QuicTestBase { public MsQuicPlatformDetectionTests(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs index b8df47509c660a..90cec1a5237ae8 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicRemoteExecutorTests.cs @@ -12,7 +12,7 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(QuicCountersListener))] + [Collection(nameof(QuicTestCollection))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public class MsQuicRemoteExecutorTests : QuicTestBase { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs index 63a1e44ea68ecc..31177d6c15e046 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs @@ -46,7 +46,7 @@ public void Dispose() } } - [Collection(nameof(QuicCountersListener))] + [Collection(nameof(QuicTestCollection))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public class MsQuicTests : QuicTestBase, IClassFixture { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs index b21e162d4b4ffa..f7c70196e6d15e 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs @@ -13,7 +13,7 @@ namespace System.Net.Quic.Tests { using Configuration = System.Net.Test.Common.Configuration; - [Collection(nameof(QuicCountersListener))] + [Collection(nameof(QuicTestCollection))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicConnectionTests : QuicTestBase { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs index 6d0a1a68b7c084..25845b42085750 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs @@ -13,13 +13,35 @@ using Microsoft.Quic; using static Microsoft.Quic.MsQuic; -public class QuicCountersListener : IDisposable +[CollectionDefinition(nameof(QuicTestCollection))] +public unsafe class QuicTestCollection : ICollectionFixture, IDisposable { + public static bool IsSupported => QuicListener.IsSupported && QuicConnection.IsSupported; + + public QuicTestCollection() + { + string msQuicLibraryVersion = GetMsQuicLibraryVersion(); + // If any of the reflection bellow breaks due to changes in "System.Net.Quic.MsQuicApi", also check and fix HttpStress project as it uses the same hack. + Console.WriteLine($"MsQuic {(IsSupported ? "supported" : "not supported")} and using '{msQuicLibraryVersion}'."); + + if (IsSupported) + { + QUIC_SETTINGS settings = default(QUIC_SETTINGS); + settings.IsSet.MaxWorkerQueueDelayUs = 1; + settings.MaxWorkerQueueDelayUs = 2_500_000u; // 2.5s, 10x the default + if (MsQuic.StatusFailed(GetApiTable()->SetParam(null, MsQuic.QUIC_PARAM_GLOBAL_SETTINGS, (uint)sizeof(QUIC_SETTINGS), (byte*)&settings))) + { + Console.WriteLine($"Unable to set MsQuic MaxWorkerQueueDelayUs."); + } + } + } + public unsafe void Dispose() { - Type msQuicApiType = Type.GetType("System.Net.Quic.MsQuicApi, System.Net.Quic"); - object msQuicApiInstance = msQuicApiType.GetProperty("Api", BindingFlags.NonPublic | BindingFlags.Static).GetGetMethod(true).Invoke(null, Array.Empty()); - QUIC_API_TABLE* apiTable = (QUIC_API_TABLE*)(Pointer.Unbox(msQuicApiType.GetProperty("ApiTable").GetGetMethod().Invoke(msQuicApiInstance, Array.Empty()))); + if (!IsSupported) + { + return; + } long[] counters = new long[(int)QUIC_PERFORMANCE_COUNTERS.MAX]; int countersAvailable; @@ -28,7 +50,7 @@ public unsafe void Dispose() fixed (long* pCounters = counters) { uint size = (uint)counters.Length * sizeof(long); - status = apiTable->GetParam(null, QUIC_PARAM_GLOBAL_PERF_COUNTERS, &size, (byte*)pCounters); + status = GetApiTable()->GetParam(null, QUIC_PARAM_GLOBAL_PERF_COUNTERS, &size, (byte*)pCounters); countersAvailable = (int)size / sizeof(long); } @@ -38,7 +60,6 @@ public unsafe void Dispose() return; } - StringBuilder sb = new StringBuilder(); sb.AppendLine("MsQuic Counters:"); @@ -58,9 +79,18 @@ void DumpCounter(QUIC_PERFORMANCE_COUNTERS counter) System.Console.WriteLine(sb.ToString()); } -} -[CollectionDefinition(nameof(QuicCountersListener), DisableParallelization = true)] -public class QuicCountersCollection : ICollectionFixture -{ -} \ No newline at end of file + private static string? GetMsQuicLibraryVersion() + { + Type msQuicApiType = Type.GetType("System.Net.Quic.MsQuicApi, System.Net.Quic"); + + return (string)msQuicApiType.GetProperty("MsQuicLibraryVersion", BindingFlags.NonPublic | BindingFlags.Static).GetGetMethod(true).Invoke(null, Array.Empty()); + } + + private static QUIC_API_TABLE* GetApiTable() + { + Type msQuicApiType = Type.GetType("System.Net.Quic.MsQuicApi, System.Net.Quic"); + object msQuicApiInstance = msQuicApiType.GetProperty("Api", BindingFlags.NonPublic | BindingFlags.Static).GetGetMethod(true).Invoke(null, Array.Empty()); + return (QUIC_API_TABLE*)(Pointer.Unbox(msQuicApiType.GetProperty("ApiTable").GetGetMethod().Invoke(msQuicApiInstance, Array.Empty()))); + } +} diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs index f7c02a03f3dd74..0de2863f902f24 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs @@ -13,7 +13,7 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(QuicCountersListener))] + [Collection(nameof(QuicTestCollection))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicListenerTests : QuicTestBase { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs index ec4323f0ae4605..2f8b7a66ff6c8d 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs @@ -14,7 +14,7 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(QuicCountersListener))] + [Collection(nameof(QuicTestCollection))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicStreamConformanceTests : ConnectedStreamConformanceTests { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs index 55e3939292c5f0..e82bd1ea9e8c94 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs @@ -12,7 +12,7 @@ namespace System.Net.Quic.Tests { - [Collection(nameof(QuicCountersListener))] + [Collection(nameof(QuicTestCollection))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported), nameof(QuicTestBase.IsNotArm32CoreClrStressTest))] public sealed class QuicStreamTests : QuicTestBase { diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs index 79992aef5f16c7..d85cf0e5ed3d9b 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs @@ -43,29 +43,7 @@ public abstract class QuicTestBase : IDisposable public const int PassingTestTimeoutMilliseconds = 4 * 60 * 1000; public static TimeSpan PassingTestTimeout => TimeSpan.FromMilliseconds(PassingTestTimeoutMilliseconds); - static unsafe QuicTestBase() - { - // If any of the reflection bellow breaks due to changes in "System.Net.Quic.MsQuicApi", also check and fix HttpStress project as it uses the same hack. - Type msQuicApiType = Type.GetType("System.Net.Quic.MsQuicApi, System.Net.Quic"); - - string msQuicLibraryVersion = (string)msQuicApiType.GetProperty("MsQuicLibraryVersion", BindingFlags.NonPublic | BindingFlags.Static).GetGetMethod(true).Invoke(null, Array.Empty()); - Console.WriteLine($"MsQuic {(IsSupported ? "supported" : "not supported")} and using '{msQuicLibraryVersion}'."); - - if (IsSupported) - { - object msQuicApiInstance = msQuicApiType.GetProperty("Api", BindingFlags.NonPublic | BindingFlags.Static).GetGetMethod(true).Invoke(null, Array.Empty()); - QUIC_API_TABLE* apiTable = (QUIC_API_TABLE*)(Pointer.Unbox(msQuicApiType.GetProperty("ApiTable").GetGetMethod().Invoke(msQuicApiInstance, Array.Empty()))); - QUIC_SETTINGS settings = default(QUIC_SETTINGS); - settings.IsSet.MaxWorkerQueueDelayUs = 1; - settings.MaxWorkerQueueDelayUs = 2_500_000u; // 2.5s, 10x the default - if (MsQuic.StatusFailed(apiTable->SetParam(null, MsQuic.QUIC_PARAM_GLOBAL_SETTINGS, (uint)sizeof(QUIC_SETTINGS), (byte*)&settings))) - { - Console.WriteLine($"Unable to set MsQuic MaxWorkerQueueDelayUs."); - } - } - } - - public unsafe QuicTestBase(ITestOutputHelper output) + public QuicTestBase(ITestOutputHelper output) { _output = output; } From 7c59cd44747f797bbcf5fe7486ea853c9da76928 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Mon, 19 Feb 2024 14:35:35 +0100 Subject: [PATCH 07/10] Move to instrument per metric --- .../Net/Quic/NetEventSource.Quic.Counters.cs | 295 +++++++++++++----- 1 file changed, 212 insertions(+), 83 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs index b51c2009772c34..0ede6141fafc0f 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.Tracing; using System.Diagnostics.Metrics; using System.Net.Quic; @@ -13,24 +14,210 @@ namespace System.Net { internal sealed partial class NetEventSource { - private static Meter s_meter = new Meter("Private.InternalDiagnostics.System.Net.Quic"); + private static Meter s_meter = new Meter("Private.InternalDiagnostics.System.Net.Quic.MsQuic"); + private static long s_countersLastFetched; private static readonly long[] s_counters = new long[(int)QUIC_PERFORMANCE_COUNTERS.MAX]; - - public static readonly ObservableGauge MsQuicCountersGauge = s_meter.CreateObservableGauge( - name: "MsQuic", - observeValues: GetGauges, - unit: null, - description: "MsQuic performance counters"); - - public static readonly ObservableCounter MsQuicCountersCounter = s_meter.CreateObservableCounter( - name: "MsQuic", - observeValues: GetCounters, - unit: null, - description: "MsQuic performance counters"); + public static readonly ObservableCounter s_CONN_CREATED = s_meter.CreateObservableCounter( + name: "msquic.connection.created", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_CREATED), + unit: "{connection}", + description: "New connections allocated"); + + public static readonly ObservableCounter s_CONN_HANDSHAKE_FAIL = s_meter.CreateObservableCounter( + name: "msquic.connection.handshake_failures", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_HANDSHAKE_FAIL), + unit: "{connection}", + description: "Connections that failed during handshake"); + + public static readonly ObservableCounter s_CONN_APP_REJECT = s_meter.CreateObservableCounter( + name: "msquic.connection.app_rejected", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_APP_REJECT), + unit: "{connection}", + description: "Connections rejected by the application"); + + public static readonly ObservableCounter s_CONN_LOAD_REJECT = s_meter.CreateObservableCounter( + name: "msquic.connection.load_rejected", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_LOAD_REJECT), + unit: "{connection}", + description: "Connections rejected due to worker load."); + + public static readonly ObservableCounter s_CONN_RESUMED = s_meter.CreateObservableCounter( + name: "msquic.connection.resumed", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_RESUMED), + unit: "{connection}", + description: "Connections resumed"); + + public static readonly ObservableGauge s_CONN_ACTIVE = s_meter.CreateObservableGauge( + name: "msquic.connection.allocated", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_ACTIVE), + unit: "{connection}", + description: "Connections currently allocated"); + + public static readonly ObservableGauge s_CONN_CONNECTED = s_meter.CreateObservableGauge( + name: "msquic.connection.connected", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_CONNECTED), + unit: "{connection}", + description: "Connections currently in the connected state"); + + public static readonly ObservableCounter s_CONN_PROTOCOL_ERRORS = s_meter.CreateObservableCounter( + name: "msquic.connection.protocol_errors", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_PROTOCOL_ERRORS), + unit: "{connection}", + description: "Connections shutdown with a protocol error"); + + public static readonly ObservableCounter s_CONN_NO_ALPN = s_meter.CreateObservableCounter( + name: "msquic.connection.no_alpn", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_NO_ALPN), + unit: "{connection}", + description: "Connection attempts with no matching ALPN"); + + public static readonly ObservableGauge s_STRM_ACTIVE = s_meter.CreateObservableGauge( + name: "msquic.stream.allocated", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.STRM_ACTIVE), + unit: "{stream}", + description: "Current streams allocated"); + + public static readonly ObservableCounter s_PKTS_SUSPECTED_LOST = s_meter.CreateObservableCounter( + name: "msquic.packet.suspected_lost", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.PKTS_SUSPECTED_LOST), + unit: "{packet}", + description: "Packets suspected lost"); + + public static readonly ObservableCounter s_PKTS_DROPPED = s_meter.CreateObservableCounter( + name: "msquic.packet.dropped", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.PKTS_DROPPED), + unit: "{packet}", + description: "Packets dropped for any reason"); + + public static readonly ObservableCounter s_PKTS_DECRYPTION_FAIL = s_meter.CreateObservableCounter( + name: "msquic.packet.decryption_failures", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.PKTS_DECRYPTION_FAIL), + unit: "{packet}", + description: "Packets with decryption failures"); + + public static readonly ObservableCounter s_UDP_RECV = s_meter.CreateObservableCounter( + name: "msquic.udp.recv_datagrams", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.UDP_RECV), + unit: "{datagram}", + description: "UDP datagrams received"); + + public static readonly ObservableCounter s_UDP_SEND = s_meter.CreateObservableCounter( + name: "msquic.udp.send_datagrams", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.UDP_SEND), + unit: "{datagram}", + description: "UDP datagrams sent"); + + public static readonly ObservableCounter s_UDP_RECV_BYTES = s_meter.CreateObservableCounter( + name: "msquic.udp.recv_bytes", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.UDP_RECV_BYTES), + unit: "By", + description: "UDP payload bytes received"); + + public static readonly ObservableCounter s_UDP_SEND_BYTES = s_meter.CreateObservableCounter( + name: "msquic.udp.send_bytes", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.UDP_SEND_BYTES), + unit: "By", + description: "UDP payload bytes sent"); + + public static readonly ObservableCounter s_UDP_RECV_EVENTS = s_meter.CreateObservableCounter( + name: "msquic.udp.recv_events", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.UDP_RECV_EVENTS), + unit: "{event}", + description: "UDP receive events"); + + public static readonly ObservableCounter s_UDP_SEND_CALLS = s_meter.CreateObservableCounter( + name: "msquic.udp.send_calls", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.UDP_SEND_CALLS), + unit: "{call}", + description: "UDP send API calls"); + + public static readonly ObservableCounter s_APP_SEND_BYTES = s_meter.CreateObservableCounter( + name: "msquic.app.send_bytes", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.APP_SEND_BYTES), + unit: "By", + description: "Bytes sent by applications"); + + public static readonly ObservableCounter s_APP_RECV_BYTES = s_meter.CreateObservableCounter( + name: "msquic.app.recv_bytes", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.APP_RECV_BYTES), + unit: "By", + description: "Bytes received by applications"); + + public static readonly ObservableGauge s_CONN_QUEUE_DEPTH = s_meter.CreateObservableGauge( + name: "msquic.threadpool.conn_queue_depth", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_QUEUE_DEPTH), + unit: "{connection}", + description: "Current connections queued for processing"); + + public static readonly ObservableGauge s_CONN_OPER_QUEUE_DEPTH = s_meter.CreateObservableGauge( + name: "msquic.threadpool.conn_oper_queue_depth", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_OPER_QUEUE_DEPTH), + unit: "{operation}", + description: "Current connection operations queued"); + + public static readonly ObservableCounter s_CONN_OPER_QUEUED = s_meter.CreateObservableCounter( + name: "msquic.threadpool.conn_oper_queued", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_OPER_QUEUED), + unit: "{operation}", + description: "New connection operations queued"); + + public static readonly ObservableCounter s_CONN_OPER_COMPLETED = s_meter.CreateObservableCounter( + name: "msquic.threadpool.conn_oper_completed", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.CONN_OPER_COMPLETED), + unit: "{operation}", + description: "Connection operations processed"); + + public static readonly ObservableGauge s_WORK_OPER_QUEUE_DEPTH = s_meter.CreateObservableGauge( + name: "msquic.threadpool.work_oper_queue_depth", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.WORK_OPER_QUEUE_DEPTH), + unit: "{operation}", + description: "Current worker operations queued"); + + public static readonly ObservableCounter s_WORK_OPER_QUEUED = s_meter.CreateObservableCounter( + name: "msquic.threadpool.work_oper_queued", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.WORK_OPER_QUEUED), + unit: "{operation}", + description: "New worker operations queued"); + + public static readonly ObservableCounter s_WORK_OPER_COMPLETED = s_meter.CreateObservableCounter( + name: "msquic.threadpool.work_oper_completed", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.WORK_OPER_COMPLETED), + unit: "{operation}", + description: "Worker operations processed"); + + public static readonly ObservableCounter s_PATH_VALIDATED = s_meter.CreateObservableCounter( + name: "msquic.datapath.path_validated", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.PATH_VALIDATED), + unit: "{challenge}", + description: "Successful path challenges"); + + public static readonly ObservableCounter s_PATH_FAILURE = s_meter.CreateObservableCounter( + name: "msquic.datapath.path_failure", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.PATH_FAILURE), + unit: "{challenge}", + description: "Unsuccessful path challenges"); + + public static readonly ObservableCounter s_SEND_STATELESS_RESET = s_meter.CreateObservableCounter( + name: "msquic.datapath.send_stateless_reset", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.SEND_STATELESS_RESET), + unit: "{packet}", + description: "Stateless reset packets sent ever"); + + public static readonly ObservableCounter s_SEND_STATELESS_RETRY = s_meter.CreateObservableCounter( + name: "msquic.datapath.send_stateless_retry", + observeValue: () => GetCounterValue(QUIC_PERFORMANCE_COUNTERS.SEND_STATELESS_RETRY), + unit: "{packet}", + description: "Stateless retry packets sent"); [NonEvent] private static void UpdateCounters() { + if (!MsQuicApi.IsQuicSupported) + { + // Avoid calling into MsQuic if not supported (or not initialized yet) + return; + } + unsafe { fixed (long* pCounters = s_counters) @@ -42,80 +229,22 @@ private static void UpdateCounters() } [NonEvent] - private static IEnumerable> GetGauges() - { - if (!MsQuicApi.IsQuicSupported) - { - // Avoid calling into MsQuic if not supported (or not initialized yet) - return Array.Empty>(); - } - - UpdateCounters(); - - var measurements = new List>(); - - static void AddMeasurement(List> measurements, QUIC_PERFORMANCE_COUNTERS counter) - { - measurements.Add(new Measurement(s_counters[(int)counter], new KeyValuePair("Name", counter))); - } - - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_ACTIVE); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_CONNECTED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.STRM_ACTIVE); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_QUEUE_DEPTH); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_OPER_QUEUE_DEPTH); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.WORK_OPER_QUEUE_DEPTH); - - return measurements; - } - - - [NonEvent] - private static IEnumerable> GetCounters() + private static long GetCounterValue(QUIC_PERFORMANCE_COUNTERS counter) { - if (!MsQuicApi.IsQuicSupported) - { - // Avoid calling into MsQuic if not supported (or not initialized yet) - return Array.Empty>(); - } - - UpdateCounters(); - - var measurements = new List>(); - - static void AddMeasurement(List> measurements, QUIC_PERFORMANCE_COUNTERS counter) + // + // We wan't to avoid refreshing the counter values array for each counter callback, + // so we refresh the counters array only once every 50ms. This should be enough time + // for all the counters to be queried and at the same time but still low enough to not + // confuse any monitoring tool as their polling rate is usually in seconds. + // + if (s_countersLastFetched == 0 || Stopwatch.GetElapsedTime(s_countersLastFetched).TotalMilliseconds > 50) { - measurements.Add(new Measurement(s_counters[(int)counter], new KeyValuePair("Name", counter))); + UpdateCounters(); + System.Console.WriteLine($"Fetched MsQuic after {Stopwatch.GetElapsedTime(s_countersLastFetched).TotalMilliseconds}ms"); + s_countersLastFetched = Stopwatch.GetTimestamp(); } - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_CREATED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_HANDSHAKE_FAIL); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_APP_REJECT); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_RESUMED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_PROTOCOL_ERRORS); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_NO_ALPN); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PKTS_SUSPECTED_LOST); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PKTS_DROPPED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PKTS_DECRYPTION_FAIL); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_RECV); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_SEND); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_RECV_BYTES); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_SEND_BYTES); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_RECV_EVENTS); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.UDP_SEND_CALLS); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.APP_SEND_BYTES); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.APP_RECV_BYTES); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_OPER_QUEUED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_OPER_COMPLETED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.WORK_OPER_QUEUED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.WORK_OPER_COMPLETED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PATH_VALIDATED); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.PATH_FAILURE); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.SEND_STATELESS_RESET); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.SEND_STATELESS_RETRY); - AddMeasurement(measurements, QUIC_PERFORMANCE_COUNTERS.CONN_LOAD_REJECT); - - return measurements; + return s_counters[(int)counter]; } } } From 976715ce205370809108737a8d88c208497003b4 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Mon, 19 Feb 2024 14:41:36 +0100 Subject: [PATCH 08/10] Remove unwanted code --- .../src/System/Net/Quic/NetEventSource.Quic.Counters.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs index 0ede6141fafc0f..93ec7e7532c7f3 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/NetEventSource.Quic.Counters.cs @@ -240,7 +240,6 @@ private static long GetCounterValue(QUIC_PERFORMANCE_COUNTERS counter) if (s_countersLastFetched == 0 || Stopwatch.GetElapsedTime(s_countersLastFetched).TotalMilliseconds > 50) { UpdateCounters(); - System.Console.WriteLine($"Fetched MsQuic after {Stopwatch.GetElapsedTime(s_countersLastFetched).TotalMilliseconds}ms"); s_countersLastFetched = Stopwatch.GetTimestamp(); } From 1589227df2f7eff01aff437f2fb478f7b2efa00f Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Tue, 20 Feb 2024 18:08:06 +0100 Subject: [PATCH 09/10] Rename file --- .../{QuicCountersFixture.cs => QuicTestCollection.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/libraries/System.Net.Quic/tests/FunctionalTests/{QuicCountersFixture.cs => QuicTestCollection.cs} (100%) diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs similarity index 100% rename from src/libraries/System.Net.Quic/tests/FunctionalTests/QuicCountersFixture.cs rename to src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs From 1a33acfaa28a6338b15c28e77cb6cf8b853e7990 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Tue, 20 Feb 2024 18:09:13 +0100 Subject: [PATCH 10/10] Redisable paralellization --- .../System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs index 25845b42085750..aac056df7cc16d 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs @@ -13,7 +13,7 @@ using Microsoft.Quic; using static Microsoft.Quic.MsQuic; -[CollectionDefinition(nameof(QuicTestCollection))] +[CollectionDefinition(nameof(QuicTestCollection), DisableParallelization = true)] public unsafe class QuicTestCollection : ICollectionFixture, IDisposable { public static bool IsSupported => QuicListener.IsSupported && QuicConnection.IsSupported;