From 40fe48ef701d633bb60837c6446162f1e9d8286b Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Fri, 14 Mar 2025 11:10:48 +0100
Subject: [PATCH 01/28] Implementation

- split AggregationManager.Threads.cs and AggregationManager.Wasm.cs - make it timer based for WASM
- split CounterGroup.Threads.cs and CounterGroup.Wasm.cs - make it timer based for WASM
- split EventPipeEventDispatcher.Threads.cs and EventPipeEventDispatcher.Wasm.cs - make it Task based
- add switch System.Net.Http.EnableMetrics and use it in HTTP client to make MetricsHandler optional
-

Api
- remove UnsupportedOSPlatform("browser")] on diagnostic API

Tests
- enable WasmPerfTracing, EventSourceSupport, MetricsSupport for unit tests which need it
- fix ActiveIssue https://github.com/dotnet/runtime/issues/93754
- enable TestSubscriptionManagerDisposal
- fix nullable argument in BeginInstrumentReporting, EndInstrumentReporting and InstrumentPublished
- enable MetricEventSourceTests, RuntimeMetricsTests, ActivityTracking
---
 .../tests/DefaultMetricsFactoryTests.cs       |   1 -
 .../tests/MetricsSubscriptionManagerTests.cs  |   2 +-
 ...rosoft.Extensions.Diagnostics.Tests.csproj |   6 +
 ...System.Diagnostics.DiagnosticSource.csproj |   4 +-
 .../Metrics/AggregationManager.Threads.cs     |  86 ++++++++++++++
 .../Metrics/AggregationManager.Wasm.cs        |  70 +++++++++++
 .../Diagnostics/Metrics/AggregationManager.cs | 109 ++++--------------
 .../Diagnostics/Metrics/MetricsEventSource.cs |  19 ++-
 .../tests/MetricEventSourceTests.cs           |  66 +++++------
 .../tests/RuntimeMetricsTests.cs              |   6 +-
 ....Diagnostics.DiagnosticSource.Tests.csproj |   6 +
 .../System.Diagnostics.Tracing.Counters.cs    |   5 -
 .../BasicEventSourceTest/ActivityTracking.cs  |  36 ++++--
 .../System.Diagnostics.Tracing.Tests.csproj   |   5 +
 .../src/System/Net/Http/GlobalHttpSettings.cs |   8 ++
 .../Net/Http/HttpClientHandler.AnyMobile.cs   |   5 +-
 .../src/System/Net/Http/HttpClientHandler.cs  |   5 +-
 .../System/Net/Http/Metrics/MetricsHandler.cs |   3 +
 .../SocketsHttpHandler/SocketsHttpHandler.cs  |   7 +-
 .../tests/FunctionalTests/DiagnosticsTests.cs |   1 -
 .../tests/FunctionalTests/MetricsTest.cs      |   7 +-
 .../System.Net.Http.Functional.Tests.csproj   |   6 +
 .../System.Private.CoreLib.Shared.projitems   |   4 +
 .../Tracing/CounterGroup.Threads.cs           |  54 +++++++++
 .../Diagnostics/Tracing/CounterGroup.Wasm.cs  |  34 ++++++
 .../Diagnostics/Tracing/CounterGroup.cs       |  41 +------
 .../Diagnostics/Tracing/DiagnosticCounter.cs  |   3 -
 .../Diagnostics/Tracing/EventCounter.cs       |   3 -
 .../EventPipeEventDispatcher.Threads.cs       |  56 +++++++++
 .../Tracing/EventPipeEventDispatcher.Wasm.cs  |  50 ++++++++
 .../Tracing/EventPipeEventDispatcher.cs       |  51 +-------
 .../System/Diagnostics/Tracing/EventSource.cs |   4 +-
 .../Tracing/IncrementingEventCounter.cs       |   3 -
 .../Tracing/IncrementingPollingCounter.cs     |   3 -
 .../Diagnostics/Tracing/PollingCounter.cs     |   3 -
 ...iCompatBaseline.NetCoreAppLatestStable.xml |  60 ++++++++++
 .../System.Private.CoreLib.csproj             |   3 -
 37 files changed, 577 insertions(+), 258 deletions(-)
 create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
 create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs
 create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
 create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs
 create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Threads.cs
 create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs

diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/DefaultMetricsFactoryTests.cs b/src/libraries/Microsoft.Extensions.Diagnostics/tests/DefaultMetricsFactoryTests.cs
index 41277ced0c7fa0..f73b197136bd7e 100644
--- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/DefaultMetricsFactoryTests.cs
+++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/DefaultMetricsFactoryTests.cs
@@ -104,7 +104,6 @@ public void NegativeTest()
         }
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/runtime/issues/93754", TestPlatforms.Browser)]
         public void MeterDisposeTest()
         {
             ServiceCollection services = new ServiceCollection();
diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs b/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs
index b64df712fae45f..0833a60198a59a 100644
--- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs
+++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs
@@ -42,7 +42,7 @@ private class FakeListener : IMetricsListener
             public void MeasurementsCompleted(Instrument instrument, object? userState) => throw new NotImplementedException();
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         public void TestSubscriptionManagerDisposal()
         {
             var meter = new Meter("TestMeter");
diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
index cf79a3f5dca619..791f708d20a23c 100644
--- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
+++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
@@ -6,6 +6,12 @@
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
   </PropertyGroup>
 
+  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
+    <WasmPerfTracing>true</WasmPerfTracing>
+    <MetricsSupport>true</MetricsSupport>
+    <EventSourceSupport>true</EventSourceSupport>
+  </PropertyGroup>
+
   <ItemGroup>
     <Compile Include="..\src\Metrics\Configuration\MetricsConfigureOptions.cs" />
     <Compile Include="..\src\Metrics\DebugConsoleMetricListener.cs" />
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
index 8be83c2ccbd180..74eee967868132 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
@@ -17,7 +17,7 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
   <PropertyGroup>
     <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(DefineConstants);ENABLE_HTTP_HANDLER</DefineConstants>
-    <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISBROWSER_SUPPORT</DefineConstants>
+    <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT</DefineConstants>
     <IncludePlatformAttributes>true</IncludePlatformAttributes>
     <!-- TODO: Add package README file: https://github.com/dotnet/runtime/issues/99358 -->
     <EnableDefaultPackageReadmeFile>false</EnableDefaultPackageReadmeFile>
@@ -57,6 +57,8 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
     <Compile Include="System\Diagnostics\PassThroughPropagator.cs" />
     <Compile Include="System\Diagnostics\RandomNumberGenerator.cs" />
     <Compile Include="System\Diagnostics\Metrics\AggregationManager.cs" />
+    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Threads.cs" Condition="'$(TargetOS)' != 'browser'" />
+    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Wasm.cs" Condition="'$(TargetOS)' == 'browser'"/>
     <Compile Include="System\Diagnostics\Metrics\Aggregator.cs" />
     <Compile Include="System\Diagnostics\Metrics\AggregatorStore.cs" />
     <Compile Include="System\Diagnostics\Metrics\Counter.cs" />
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
new file mode 100644
index 00000000000000..9f3a1411ba5924
--- /dev/null
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
@@ -0,0 +1,86 @@
+﻿// 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.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Versioning;
+using System.Security;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Diagnostics.Metrics
+{
+    internal sealed partial class AggregationManager
+    {
+        private Thread? _collectThread;
+
+        public void Start()
+        {
+            // if already started or already stopped we can't be started again
+            Debug.Assert(_collectThread == null && !_cts.IsCancellationRequested);
+            Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs);
+
+            // This explicitly uses a Thread and not a Task so that metrics still work
+            // even when an app is experiencing thread-pool starvation. Although we
+            // can't make in-proc metrics robust to everything, this is a common enough
+            // problem in .NET apps that it feels worthwhile to take the precaution.
+            _collectThread = new Thread(() => CollectWorker(_cts.Token));
+            _collectThread.IsBackground = true;
+            _collectThread.Name = "MetricsEventSource CollectWorker";
+            _collectThread.Start();
+
+            _listener.Start();
+            _initialInstrumentEnumerationComplete();
+        }
+
+        private void CollectWorker(CancellationToken cancelToken)
+        {
+            try
+            {
+                double collectionIntervalSecs = -1;
+                lock (this)
+                {
+                    collectionIntervalSecs = CollectionPeriod.TotalSeconds;
+                }
+                Debug.Assert(collectionIntervalSecs >= MinCollectionTimeSecs);
+
+                DateTime startTime = DateTime.UtcNow;
+                DateTime intervalStartTime = startTime;
+                while (!cancelToken.IsCancellationRequested)
+                {
+                    // pause until the interval is complete
+                    DateTime now = DateTime.UtcNow;
+                    DateTime nextIntervalStartTime = CalculateDelayTime(now, startTime, intervalStartTime, collectionIntervalSecs);
+                    TimeSpan delayTime = nextIntervalStartTime - now;
+                    if (cancelToken.WaitHandle.WaitOne(delayTime))
+                    {
+                        // don't do collection if timer may not have run to completion
+                        break;
+                    }
+
+                    // collect statistics for the completed interval
+                    _beginCollection(intervalStartTime, nextIntervalStartTime);
+                    Collect();
+                    _endCollection(intervalStartTime, nextIntervalStartTime);
+                    intervalStartTime = nextIntervalStartTime;
+                }
+            }
+            catch (Exception e)
+            {
+                _collectionError(e);
+            }
+        }
+
+        public void Dispose()
+        {
+            _cts.Cancel();
+            if (_collectThread != null)
+            {
+                _collectThread.Join();
+                _collectThread = null;
+            }
+            _listener.Dispose();
+        }
+    }
+}
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs
new file mode 100644
index 00000000000000..1344c381f79391
--- /dev/null
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs
@@ -0,0 +1,70 @@
+﻿// 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.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Versioning;
+using System.Security;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Diagnostics.Metrics
+{
+    internal sealed partial class AggregationManager
+    {
+        private Timer? _pollingTimer;
+        private DateTime _startTime;
+        private DateTime _intervalStartTime;
+        private DateTime _nextIntervalStartTime;
+
+        public void Start()
+        {
+            // if already started or already stopped we can't be started again
+            Debug.Assert(_pollingTimer == null && !_cts.IsCancellationRequested);
+            Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs);
+
+            DateTime now = _startTime = _intervalStartTime  = DateTime.UtcNow;
+            _nextIntervalStartTime = CalculateDelayTime(now, _startTime, _intervalStartTime, CollectionPeriod.TotalSeconds);
+            TimeSpan delayTime = _nextIntervalStartTime - now;
+            _pollingTimer = new Timer(CollectOnce, null, (int)delayTime.TotalMilliseconds, 0);
+
+            _listener.Start();
+            _initialInstrumentEnumerationComplete();
+        }
+
+        private void CollectOnce(object? state)
+        {
+            try
+            {
+                if (_cts.Token.IsCancellationRequested)
+                {
+                    return;
+                }
+
+                // collect statistics for the completed interval
+                _beginCollection(_intervalStartTime, _nextIntervalStartTime);
+                Collect();
+                _endCollection(_intervalStartTime, _nextIntervalStartTime);
+
+                DateTime now = DateTime.UtcNow;
+                _nextIntervalStartTime = CalculateDelayTime(now, _startTime, _intervalStartTime, CollectionPeriod.TotalSeconds);
+                TimeSpan delayTime = _nextIntervalStartTime - now;
+                _intervalStartTime = _nextIntervalStartTime;
+                // schedule the next collection
+                _pollingTimer!.Change((int)delayTime.TotalMilliseconds, 0);
+            }
+            catch (Exception e)
+            {
+                _collectionError(e);
+            }
+        }
+
+        public void Dispose()
+        {
+            _cts.Cancel();
+            _pollingTimer?.Dispose();
+            _listener.Dispose();
+        }
+    }
+}
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
index 2dd9450c6eae50..34678b5c68b62b 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
@@ -11,9 +11,8 @@
 
 namespace System.Diagnostics.Metrics
 {
-    [UnsupportedOSPlatform("browser")]
     [SecuritySafeCritical]
-    internal sealed class AggregationManager
+    internal sealed partial class AggregationManager
     {
         public const double MinCollectionTimeSecs = 0.1;
         private static readonly QuantileAggregation s_defaultHistogramConfig = new QuantileAggregation(new double[] { 0.50, 0.95, 0.99 });
@@ -28,7 +27,6 @@ internal sealed class AggregationManager
         private Dictionary<Instrument, bool> _instruments = new();
         private readonly ConcurrentDictionary<Instrument, InstrumentState> _instrumentStates = new();
         private readonly CancellationTokenSource _cts = new();
-        private Thread? _collectThread;
         private readonly MeterListener _listener;
         private int _currentTimeSeries;
         private int _currentHistograms;
@@ -154,25 +152,6 @@ private void PublishedInstrument(Instrument instrument, MeterListener _)
             }
         }
 
-        public void Start()
-        {
-            // if already started or already stopped we can't be started again
-            Debug.Assert(_collectThread == null && !_cts.IsCancellationRequested);
-            Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs);
-
-            // This explicitly uses a Thread and not a Task so that metrics still work
-            // even when an app is experiencing thread-pool starvation. Although we
-            // can't make in-proc metrics robust to everything, this is a common enough
-            // problem in .NET apps that it feels worthwhile to take the precaution.
-            _collectThread = new Thread(() => CollectWorker(_cts.Token));
-            _collectThread.IsBackground = true;
-            _collectThread.Name = "MetricsEventSource CollectWorker";
-            _collectThread.Start();
-
-            _listener.Start();
-            _initialInstrumentEnumerationComplete();
-        }
-
         public void Update()
         {
             // Creating (and destroying) a MeterListener to leverage the existing
@@ -186,76 +165,32 @@ public void Update()
 
             _initialInstrumentEnumerationComplete();
         }
-
-        private void CollectWorker(CancellationToken cancelToken)
+        private static DateTime CalculateDelayTime(DateTime now, DateTime startTime, DateTime intervalStartTime, double collectionIntervalSecs)
         {
-            try
+            // intervals end at startTime + X*collectionIntervalSecs. Under normal
+            // circumstance X increases by 1 each interval, but if the time it
+            // takes to do collection is very large then we might need to skip
+            // ahead multiple intervals to catch back up.
+            //
+            double secsSinceStart = (now - startTime).TotalSeconds;
+            double alignUpSecsSinceStart = Math.Ceiling(secsSinceStart / collectionIntervalSecs) *
+                collectionIntervalSecs;
+            DateTime nextIntervalStartTime = startTime.AddSeconds(alignUpSecsSinceStart);
+
+            // The delay timer precision isn't exact. We might have a situation
+            // where in the previous loop iterations intervalStartTime=20.00,
+            // nextIntervalStartTime=21.00, the timer was supposed to delay for 1s but
+            // it exited early so we looped around and DateTime.Now=20.99.
+            // Aligning up from DateTime.Now would give us 21.00 again so we also need to skip
+            // forward one time interval
+            DateTime minNextInterval = intervalStartTime.AddSeconds(collectionIntervalSecs);
+            if (nextIntervalStartTime <= minNextInterval)
             {
-                double collectionIntervalSecs = -1;
-                lock (this)
-                {
-                    collectionIntervalSecs = CollectionPeriod.TotalSeconds;
-                }
-                Debug.Assert(collectionIntervalSecs >= MinCollectionTimeSecs);
-
-                DateTime startTime = DateTime.UtcNow;
-                DateTime intervalStartTime = startTime;
-                while (!cancelToken.IsCancellationRequested)
-                {
-                    // intervals end at startTime + X*collectionIntervalSecs. Under normal
-                    // circumstance X increases by 1 each interval, but if the time it
-                    // takes to do collection is very large then we might need to skip
-                    // ahead multiple intervals to catch back up.
-                    //
-                    DateTime now = DateTime.UtcNow;
-                    double secsSinceStart = (now - startTime).TotalSeconds;
-                    double alignUpSecsSinceStart = Math.Ceiling(secsSinceStart / collectionIntervalSecs) *
-                        collectionIntervalSecs;
-                    DateTime nextIntervalStartTime = startTime.AddSeconds(alignUpSecsSinceStart);
-
-                    // The delay timer precision isn't exact. We might have a situation
-                    // where in the previous loop iterations intervalStartTime=20.00,
-                    // nextIntervalStartTime=21.00, the timer was supposed to delay for 1s but
-                    // it exited early so we looped around and DateTime.Now=20.99.
-                    // Aligning up from DateTime.Now would give us 21.00 again so we also need to skip
-                    // forward one time interval
-                    DateTime minNextInterval = intervalStartTime.AddSeconds(collectionIntervalSecs);
-                    if (nextIntervalStartTime <= minNextInterval)
-                    {
-                        nextIntervalStartTime = minNextInterval;
-                    }
-
-                    // pause until the interval is complete
-                    TimeSpan delayTime = nextIntervalStartTime - now;
-                    if (cancelToken.WaitHandle.WaitOne(delayTime))
-                    {
-                        // don't do collection if timer may not have run to completion
-                        break;
-                    }
-
-                    // collect statistics for the completed interval
-                    _beginCollection(intervalStartTime, nextIntervalStartTime);
-                    Collect();
-                    _endCollection(intervalStartTime, nextIntervalStartTime);
-                    intervalStartTime = nextIntervalStartTime;
-                }
-            }
-            catch (Exception e)
-            {
-                _collectionError(e);
+                nextIntervalStartTime = minNextInterval;
             }
+            return nextIntervalStartTime;
         }
 
-        public void Dispose()
-        {
-            _cts.Cancel();
-            if (_collectThread != null)
-            {
-                _collectThread.Join();
-                _collectThread = null;
-            }
-            _listener.Dispose();
-        }
 
         private void RemoveInstrumentState(Instrument instrument)
         {
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
index 0768d8b456119e..71b8af288fd89d 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
@@ -173,7 +173,7 @@ public void BeginInstrumentReporting(
                         string? meterTelemetrySchemaUrl)
         {
             WriteEvent(7, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
-                    instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl);
+                    instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl ?? "");
         }
 
         // Sent when we stop monitoring the value of a instrument, either because new session filter arguments changed subscriptions
@@ -198,7 +198,7 @@ public void EndInstrumentReporting(
                         string? meterTelemetrySchemaUrl)
         {
             WriteEvent(8, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
-                    instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl);
+                    instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl ?? "");
         }
 
         [Event(9, Keywords = Keywords.TimeSeriesValues | Keywords.Messages | Keywords.InstrumentPublishing)]
@@ -233,7 +233,7 @@ public void InstrumentPublished(
                         string? meterTelemetrySchemaUrl)
         {
             WriteEvent(11, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
-                    instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl);
+                    instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl ?? "");
         }
 
         [Event(12, Keywords = Keywords.TimeSeriesValues)]
@@ -338,16 +338,16 @@ public void OnEventCommand(EventCommandEventArgs command)
             {
                 try
                 {
-#if OS_ISBROWSER_SUPPORT
-                    if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi())
+#if OS_ISWASI_SUPPORT
+                    if (OperatingSystem.IsWasi())
                     {
                         // AggregationManager uses a dedicated thread to avoid losing data for apps experiencing threadpool starvation
-                        // and browser doesn't support Thread.Start()
+                        // and wasi doesn't support Thread.Start()
                         //
-                        // This limitation shouldn't really matter because browser also doesn't support out-of-proc EventSource communication
+                        // This limitation shouldn't really matter because wasi also doesn't support out-of-proc EventSource communication
                         // which is the intended scenario for this EventSource. If it matters in the future AggregationManager can be
-                        // modified to have some other fallback path that works for browser.
-                        Parent.Error("", "System.Diagnostics.Metrics EventSource not supported on browser and wasi");
+                        // modified to have some other fallback path that works for wasi.
+                        Parent.Error("", "System.Diagnostics.Metrics EventSource not supported on wasi");
                         return;
                     }
 #endif
@@ -661,7 +661,6 @@ private bool LogError(Exception e)
 
             private static readonly char[] s_instrumentSeparators = new char[] { '\r', '\n', ',', ';' };
 
-            [UnsupportedOSPlatform("browser")]
             private void ParseSpecs(string? metricsSpecs)
             {
                 if (metricsSpecs == null)
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
index dbf25f79032aea..4ad1aba0d107a3 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
@@ -75,7 +75,7 @@ public void TestVersion()
             }).Dispose();
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_DifferentCounters()
         {
@@ -123,7 +123,7 @@ public void MultipleListeners_DifferentCounters()
             AssertCollectStartStopEventsPresent(events2, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_ReuseCounter()
         {
@@ -174,7 +174,7 @@ public void MultipleListeners_ReuseCounter()
             AssertCollectStartStopEventsPresent(events2, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_CollectAfterDisableListener()
         {
@@ -228,7 +228,7 @@ public void MultipleListeners_CollectAfterDisableListener()
             AssertCollectStartStopEventsPresent(events2, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_ThreeCounters()
         {
@@ -288,7 +288,7 @@ public void MultipleListeners_ThreeCounters()
             AssertCollectStartStopEventsPresent(events3, IntervalSecs, 2);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void SingleListener_Wildcard()
         {
@@ -331,7 +331,7 @@ public void SingleListener_Wildcard()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 2);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void SingleListener_Prefix()
         {
@@ -368,7 +368,7 @@ public void SingleListener_Prefix()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 2);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_OverlappingListeners()
         {
@@ -413,7 +413,7 @@ public void MultipleListeners_OverlappingListeners()
             AssertCollectStartStopEventsPresent(events2, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_UnsharedSessionRejectsUnsharedListener()
         {
@@ -467,7 +467,7 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_UnsharedSessionRejectsSharedListener()
         {
@@ -524,7 +524,7 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_SharedSessionRejectsUnsharedListener()
         {
@@ -580,7 +580,7 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs()
         {
@@ -619,7 +619,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 4);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         [ActiveIssue("This test appears to interfere with the others due to the session not being shut down.")]
         public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerWithDifferentArgsAfterListenerDisposed()
@@ -658,7 +658,7 @@ public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerW
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 4);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval()
         {
@@ -717,7 +717,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval(
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_DisposeMeterBeforeSecondListener()
         {
@@ -783,7 +783,7 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener()
             AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc, g);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener()
         {
@@ -854,7 +854,7 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener()
             AssertEndInstrumentReportingEventsPresent(events2, c, oc, og, udc, oudc, g);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void MultipleListeners_PublishingInstruments()
         {
@@ -895,9 +895,7 @@ public void MultipleListeners_PublishingInstruments()
             AssertInitialEnumerationCompleteEventPresent(events2);
         }
 
-        public static bool IsNotBrowserAndRemoteExecuteSupported => PlatformDetection.IsNotBrowser && RemoteExecutor.IsSupported;
-
-        [ConditionalFact(typeof(MetricEventSourceTests), nameof(IsNotBrowserAndRemoteExecuteSupported))]
+        [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesTimeSeriesWithEmptyMetadata()
         {
@@ -960,7 +958,7 @@ public void WriteLine(string message) { }
             public void WriteLine(string format, params object[] args) { }
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesTimeSeriesWithMetadata()
         {
@@ -1005,7 +1003,7 @@ public void EventSourcePublishesTimeSeriesWithMetadata()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesTimeSeriesForLateMeter()
         {
@@ -1071,7 +1069,7 @@ public void EventSourcePublishesTimeSeriesForLateMeter()
             }
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesTimeSeriesForLateInstruments()
         {
@@ -1127,7 +1125,7 @@ public void EventSourcePublishesTimeSeriesForLateInstruments()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesTimeSeriesWithTags()
         {
@@ -1214,7 +1212,7 @@ public void EventSourcePublishesTimeSeriesWithTags()
         }
 
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         [ActiveIssue("https://github.com/dotnet/runtime/issues/79749", TargetFrameworkMonikers.NetFramework)]
         public void EventSourceFiltersInstruments()
@@ -1283,7 +1281,7 @@ public void EventSourceFiltersInstruments()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesMissingDataPoints()
         {
@@ -1375,7 +1373,7 @@ public void EventSourcePublishesMissingDataPoints()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 5);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesEndEventsOnMeterDispose()
         {
@@ -1435,7 +1433,7 @@ public void EventSourcePublishesEndEventsOnMeterDispose()
             AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc, g);
         }
 
-        [ConditionalFact(typeof(MetricEventSourceTests), nameof(IsNotBrowserAndRemoteExecuteSupported))]
+        [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesInstruments()
         {
@@ -1477,7 +1475,7 @@ public void EventSourcePublishesInstruments()
             }).Dispose();
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesAllDataTypes()
         {
@@ -1543,7 +1541,7 @@ public void EventSourcePublishesAllDataTypes()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourceEnforcesTimeSeriesLimit()
         {
@@ -1579,7 +1577,7 @@ public void EventSourceEnforcesTimeSeriesLimit()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourceEnforcesHistogramLimit()
         {
@@ -1616,7 +1614,7 @@ public void EventSourceEnforcesHistogramLimit()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourceHandlesObservableCallbackException()
         {
@@ -1643,7 +1641,7 @@ public void EventSourceHandlesObservableCallbackException()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourceWorksWithSequentialListeners()
         {
@@ -1718,7 +1716,7 @@ public void EventSourceWorksWithSequentialListeners()
             AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries()
         {
@@ -1786,7 +1784,7 @@ public static IEnumerable<object[]> DifferentMetersAndInstrumentsData()
             yield return new object[] { meter.CreateCounter<int>("C8", "u1", "d1", new TagList { { "k2", "v2" } } ), meter.CreateCounter<int>("C9", "u1", "d1", new TagList { { "k2", "v2" } } ), false };
         }
 
-        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Theory]
         [OuterLoop("Slow and has lots of console spew")]
         [MemberData(nameof(DifferentMetersAndInstrumentsData))]
         public void TestDifferentMetersAndInstruments(Counter<int> counter1, Counter<int> counter2, bool isSameCounters)
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/RuntimeMetricsTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/RuntimeMetricsTests.cs
index 2963533ac7cdc0..662d8d68fc0c68 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/RuntimeMetricsTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/RuntimeMetricsTests.cs
@@ -49,7 +49,7 @@ public class RuntimeMetricsTests(ITestOutputHelper output)
 
         private readonly ITestOutputHelper _output = output;
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         public void GcCollectionsCount()
         {
             using InstrumentRecorder<long> instrumentRecorder = new("dotnet.gc.collections");
@@ -158,7 +158,7 @@ public void CpuTime()
            }
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         public void ExceptionsCount()
         {
             // We inject an exception into the MeterListener callback here, so we can test that we don't recursively record exceptions.
@@ -271,7 +271,7 @@ private static void ValidateSingleMeasurement<T>(string metricName, Func<T, (boo
             }
         }
 
-        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Theory]
         [InlineData("dotnet.gc.last_collection.heap.size")]
         [InlineData("dotnet.gc.last_collection.heap.fragmentation.size")]
         public void HeapTags(string metricName) => EnsureAllHeapTags(metricName);
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
index fe68c58eef9155..e16da53e29a732 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
@@ -5,6 +5,12 @@
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
   </PropertyGroup>
 
+  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
+    <WasmPerfTracing>true</WasmPerfTracing>
+    <MetricsSupport>true</MetricsSupport>
+    <EventSourceSupport>true</EventSourceSupport>
+  </PropertyGroup>
+
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
   <PropertyGroup>
     <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);MEMORYMARSHAL_SUPPORT</DefineConstants>
diff --git a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs
index 56c748f026e3e2..2e1cce9f780a48 100644
--- a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs
+++ b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs
@@ -3,7 +3,6 @@
 
 namespace System.Diagnostics.Tracing
 {
-    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public abstract partial class DiagnosticCounter : System.IDisposable
     {
         internal DiagnosticCounter() { }
@@ -14,13 +13,11 @@ internal DiagnosticCounter() { }
         public void AddMetadata(string key, string? value) { }
         public void Dispose() { }
     }
-    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public partial class PollingCounter : System.Diagnostics.Tracing.DiagnosticCounter
     {
         public PollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func<double> metricProvider) { }
         public override string ToString() { throw null; }
     }
-    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public partial class IncrementingEventCounter : System.Diagnostics.Tracing.DiagnosticCounter
     {
         public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { }
@@ -28,14 +25,12 @@ public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSou
         public void Increment(double increment = 1) { }
         public override string ToString() { throw null; }
     }
-    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public partial class IncrementingPollingCounter : System.Diagnostics.Tracing.DiagnosticCounter
     {
         public IncrementingPollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func<double> totalValueProvider) { }
         public System.TimeSpan DisplayRateTimeScale { get { throw null; } set { } }
         public override string ToString() { throw null; }
     }
-    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public partial class EventCounter : System.Diagnostics.Tracing.DiagnosticCounter
     {
         public EventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { }
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
index 1330901b00bff7..ceab3fd7466c95 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
@@ -8,25 +8,47 @@
 using System.Text;
 using System.Threading.Tasks;
 using Xunit;
+using System.Runtime.CompilerServices;
 
 namespace BasicEventSourceTests
 {
-    public class ActivityTracking
+    public class ActivityTracking : IDisposable
     {
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        public ActivityTracking()
+        {
+            EventSource.SetCurrentThreadActivityId(Guid.Empty);
+        }
+
+        public void Dispose()
+        {
+            EventSource.SetCurrentThreadActivityId(Guid.Empty);
+        }
+
+        [Fact]
+        public void IsSupported()
+        {
+            Assert.True(IsSupported((EventSource)null));
+
+            [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "get_IsSupported")]
+            static extern bool IsSupported(EventSource eventSource);
+        }
+
+        [Fact]
         public void StartStopCreatesActivity()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
 
+            Assert.True(es.IsEnabled());
+
             Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId);
             es.ExampleStart();
-            Assert.NotEqual(Guid.Empty, EventSource.CurrentThreadActivityId);
+            //Assert.NotEqual(Guid.Empty, EventSource.CurrentThreadActivityId);
             es.ExampleStop();
             Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         public async Task ActivityFlowsAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
@@ -41,7 +63,7 @@ public async Task ActivityFlowsAsync()
             Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId);
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
         public async Task ActivityIdIsZeroedOnThreadSwitchOut()
         {
             using ActivityEventListener l = new ActivityEventListener();
@@ -74,7 +96,7 @@ private async Task YieldTwoActivitiesDeep(ActivityEventSource es)
         // I am attempting to preserve it to lower back compat risk, but in
         // the future we might decide it wasn't even desirable to begin with.
         // Compare with SetCurrentActivityIdAfterEventDoesNotFlowAsync below.
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         public async Task SetCurrentActivityIdBeforeEventFlowsAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
@@ -99,7 +121,7 @@ public async Task SetCurrentActivityIdBeforeEventFlowsAsync()
         // I am attempting to preserve it to lower back compat risk, but in
         // the future we might decide it wasn't even desirable to begin with.
         // Compare with SetCurrentActivityIdBeforeEventFlowsAsync above.
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+        [Fact]
         public async Task SetCurrentActivityIdAfterEventDoesNotFlowAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
index af231d14fa72a1..6862b424abcd3e 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
+++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
@@ -6,6 +6,11 @@
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
     <TestDisableParallelization>true</TestDisableParallelization>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
+    <WasmPerfTracing>true</WasmPerfTracing>
+    <MetricsSupport>true</MetricsSupport>
+    <EventSourceSupport>true</EventSourceSupport>
+  </PropertyGroup>
   <ItemGroup Condition="'$(TargetsAppleMobile)' == 'true' or '$(TargetOS)' == 'android'">
     <RuntimeComponents Include="diagnostics_tracing" />
     <RuntimeComponents Include="marshal-ilgen" />
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs
index e314957414b6b0..ab6878db43df48 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs
@@ -21,6 +21,14 @@ internal static class DiagnosticsHandler
                 false);
         }
 
+        internal static class MetricsHandler
+        {
+            public static bool EnableMetrics { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch(
+                "System.Net.Http.EnableMetrics",
+                "DOTNET_SYSTEM_NET_HTTP_ENABLEMETRICS",
+                true);
+        }
+
         internal static class SocketsHttpHandler
         {
 #if !TARGET_BROWSER && !TARGET_WASI
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
index 6037df88bef807..90b55ad0e47428 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
@@ -45,7 +45,10 @@ private HttpMessageHandler Handler
 
                         // MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
                         // metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
-                        handler = new MetricsHandler(handler, _nativeMeterFactory, out _);
+                        if (MetricsHandler.IsGloballyEnabled())
+                        {
+                            handler = new MetricsHandler(handler, _nativeMeterFactory, out _);
+                        }
                         if (DiagnosticsHandler.IsGloballyEnabled())
                         {
                             handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current);
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
index afba32455bc2fe..9c5c728ddb0658 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
@@ -45,7 +45,10 @@ private HttpMessageHandler Handler
 
                 // MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
                 // metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
-                handler = new MetricsHandler(handler, _meterFactory, out _);
+                if (MetricsHandler.IsGloballyEnabled())
+                {
+                    handler = new MetricsHandler(handler, _meterFactory, out _);
+                }
                 if (DiagnosticsHandler.IsGloballyEnabled())
                 {
                     handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current);
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs
index 79a544816ccb09..9ee40930e3de4b 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs
@@ -17,6 +17,7 @@ internal sealed class MetricsHandler : HttpMessageHandlerStage
 
         public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFactory, out Meter meter)
         {
+            Debug.Assert(IsGloballyEnabled());
             _innerHandler = innerHandler;
 
             meter = meterFactory?.Create("System.Net.Http") ?? SharedMeter.Instance;
@@ -33,6 +34,8 @@ public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFacto
                 advice: DiagnosticsHelper.ShortHistogramAdvice);
         }
 
+        internal static bool IsGloballyEnabled() => GlobalHttpSettings.MetricsHandler.EnableMetrics;
+
         internal override ValueTask<HttpResponseMessage> SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
         {
             if (_activeRequests.Enabled || _requestsDuration.Enabled)
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs
index 6c0a8208508bdb..1af8e6abd53a12 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs
@@ -531,8 +531,11 @@ private HttpMessageHandlerStage SetupHandlerChain()
 
             // MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
             // metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
-            handler = new MetricsHandler(handler, settings._meterFactory, out Meter meter);
-            settings._metrics = new SocketsHttpHandlerMetrics(meter);
+            if (MetricsHandler.IsGloballyEnabled())
+            {
+                handler = new MetricsHandler(handler, settings._meterFactory, out Meter meter);
+                settings._metrics = new SocketsHttpHandlerMetrics(meter);
+            }
 
             // DiagnosticsHandler is inserted before RedirectHandler so that trace propagation is done on redirects as well
             if (DiagnosticsHandler.IsGloballyEnabled() && settings._activityHeadersPropagator is DistributedContextPropagator propagator)
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
index 29a03a52d1ab30..804ec138105618 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
@@ -31,7 +31,6 @@ public abstract class DiagnosticsTest : DiagnosticsTestBase
         public DiagnosticsTest(ITestOutputHelper output) : base(output) { }
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/runtime/issues/71877", TestPlatforms.Browser)]
         public void EventSource_ExistsWithCorrectId()
         {
             Type esType = typeof(HttpClient).Assembly.GetType("System.Net.NetEventSource", throwOnError: true, ignoreCase: false);
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
index 1715dbf8c676df..8a2e1fde4e4f75 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
@@ -1046,10 +1046,12 @@ public Task DurationHistograms_HaveBucketSizeHints()
                 using HttpRequestMessage request = new(HttpMethod.Get, uri) { Version = UseVersion };
                 using HttpResponseMessage response = await SendAsync(client, request);
 
+
                 Assert.Equal(1, requestDurationRecorder.MeasurementCount);
-                Assert.Equal(1, timeInQueueRecorder.MeasurementCount);
+                if (SocketsHttpHandler.IsSupported) Assert.Equal(1, timeInQueueRecorder.MeasurementCount);
                 client.Dispose(); // terminate the connection
-                Assert.Equal(1, connectionDurationRecorder.MeasurementCount);
+
+                if (SocketsHttpHandler.IsSupported) Assert.Equal(1, connectionDurationRecorder.MeasurementCount);
             }, async server =>
             {
                 await server.AcceptConnectionSendResponseAndCloseAsync();
@@ -1057,7 +1059,6 @@ public Task DurationHistograms_HaveBucketSizeHints()
         }
     }
 
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/93754", TestPlatforms.Browser)]
     public class HttpMetricsTest_Http11_Async : HttpMetricsTest_Http11
     {
         public HttpMetricsTest_Http11_Async(ITestOutputHelper output) : base(output)
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index 44e576ea14ae89..6675d52324c305 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -28,6 +28,9 @@
     <!-- This WASM test is slow on NodeJS. This sets the xharness timeout but there is also override in sendtohelix-browser.targets -->
     <WasmXHarnessTestsTimeout>01:15:00</WasmXHarnessTestsTimeout>
     <XunitShowProgress Condition="'$(FeatureWasmManagedThreads)' == 'true'">true</XunitShowProgress>
+    <WasmPerfTracing>true</WasmPerfTracing>
+    <EventSourceSupport>true</EventSourceSupport>
+    <MetricsSupport>true</MetricsSupport>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(TargetOS)' == 'wasi'">
@@ -48,6 +51,9 @@
     <NodeNpmModule Include="node-fetch" />
     <NodeNpmModule Include="node-abort-controller" />
 
+    <RuntimeHostConfigurationOption Include="System.Net.Http.EnableActivityPropagation" Value="true" Trim="true" />
+    <RuntimeHostConfigurationOption Include="System.Net.Http.EnableMetrics" Value="true" Trim="true" />
+
   </ItemGroup>
 
   <ItemGroup>
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index a73d2783adf653..ae0325a504c31d 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -1548,6 +1548,8 @@
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\ActivityTracker.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\DiagnosticCounter.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\CounterGroup.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\CounterGroup.Threads.cs" Condition="('$(TargetsWasi)' != 'true' and '$(TargetsBrowser)' != 'true') or '$(FeatureWasmManagedThreads)' == 'true'" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\CounterGroup.Wasm.cs" Condition="('$(TargetsWasi)' == 'true' or '$(TargetsBrowser)' == 'true') and '$(FeatureWasmManagedThreads)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\CounterPayload.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventActivityOptions.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventCounter.cs" />
@@ -1555,6 +1557,8 @@
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipe.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipe.Internal.cs" Condition="'$(FeaturePerfTracing)' == 'true' and '$(FeatureMono)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipeEventDispatcher.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipeEventDispatcher.Threads.cs" Condition="'$(FeaturePerfTracing)' == 'true' and (('$(TargetsWasi)' != 'true' and '$(TargetsBrowser)' != 'true') or '$(FeatureWasmManagedThreads)' == 'true')" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipeEventDispatcher.Wasm.cs" Condition="'$(FeaturePerfTracing)' == 'true' and (('$(TargetsWasi)' == 'true' or '$(TargetsBrowser)' == 'true') and '$(FeatureWasmManagedThreads)' != 'true')" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipeEventProvider.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipeMetadataGenerator.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipePayloadDecoder.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
new file mode 100644
index 00000000000000..a719bd04af2c44
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
@@ -0,0 +1,54 @@
+// 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.Runtime.Versioning;
+using System.Threading;
+
+namespace System.Diagnostics.Tracing
+{
+    internal sealed partial class CounterGroup
+    {
+        private static Thread? s_pollingThread;
+        // Used for sleeping for a certain amount of time while allowing the thread to be woken up
+        private static AutoResetEvent? s_pollingThreadSleepEvent;
+
+        private static void CreatePollingTimer()
+        {
+            // Create the polling thread and init all the shared state if needed
+            if (s_pollingThread == null)
+            {
+                s_pollingThreadSleepEvent = new AutoResetEvent(false);
+                s_counterGroupEnabledList = new List<CounterGroup>();
+                // TODO
+                s_pollingThread = new Thread(PollForValues)
+                {
+                    IsBackground = true,
+                    Name = ".NET Counter Poller"
+                };
+                s_pollingThread.Start();
+            }
+            else
+            {
+                // notify the polling thread that the polling interval may have changed and the sleep should be recomputed
+                s_pollingThreadSleepEvent!.Set();
+            }
+        }
+
+        private static void PollForValues()
+        {
+            AutoResetEvent? sleepEvent = null;
+            lock (s_counterGroupLock)
+            {
+                sleepEvent = s_pollingThreadSleepEvent;
+            }
+
+            while (true)
+            {
+                var sleepDurationInMilliseconds = PollOnce();
+
+                sleepEvent?.WaitOne(sleepDurationInMilliseconds);
+            }
+        }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs
new file mode 100644
index 00000000000000..2f9a0acb6788e8
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs
@@ -0,0 +1,34 @@
+// 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.Runtime.Versioning;
+using System.Threading;
+
+namespace System.Diagnostics.Tracing
+{
+    internal sealed partial class CounterGroup
+    {
+        private static Timer? s_pollingTimer;
+
+        private static void CreatePollingTimer()
+        {
+            if (s_pollingTimer == null)
+            {
+                s_pollingTimer = new Timer(PollForValues, null, 0, 0);
+                s_counterGroupEnabledList = new List<CounterGroup>();
+            }
+            else
+            {
+                // notify the polling callback that the polling interval may have changed and the sleep should be recomputed
+                s_pollingTimer.Change(0, 0);
+            }
+        }
+
+        private static void PollForValues(object? state)
+        {
+            var sleepDurationInMilliseconds = PollOnce();
+            s_pollingTimer!.Change(sleepDurationInMilliseconds, 0);
+        }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
index d08c6949616c10..d5a73b3ee40e67 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
@@ -7,10 +7,7 @@
 
 namespace System.Diagnostics.Tracing
 {
-#if !ES_BUILD_STANDALONE
-    [UnsupportedOSPlatform("browser")]
-#endif
-    internal sealed class CounterGroup
+    internal sealed partial class CounterGroup
     {
         private readonly EventSource _eventSource;
         private readonly List<DiagnosticCounter> _counters;
@@ -159,27 +156,12 @@ private void EnableTimer(float pollingIntervalInSeconds)
                 _timeStampSinceCollectionStarted = DateTime.UtcNow;
                 _nextPollingTimeStamp = DateTime.UtcNow + new TimeSpan(0, 0, (int)pollingIntervalInSeconds);
 
-                // Create the polling thread and init all the shared state if needed
-                if (s_pollingThread == null)
-                {
-                    s_pollingThreadSleepEvent = new AutoResetEvent(false);
-                    s_counterGroupEnabledList = new List<CounterGroup>();
-                    s_pollingThread = new Thread(PollForValues)
-                    {
-                        IsBackground = true,
-                        Name = ".NET Counter Poller"
-                    };
-                    s_pollingThread.Start();
-                }
+                CreatePollingTimer();
 
                 if (!s_counterGroupEnabledList!.Contains(this))
                 {
                     s_counterGroupEnabledList.Add(this);
                 }
-
-                // notify the polling thread that the polling interval may have changed and the sleep should
-                // be recomputed
-                s_pollingThreadSleepEvent!.Set();
             }
         }
 
@@ -267,29 +249,21 @@ private void OnTimer()
             }
         }
 
-        private static Thread? s_pollingThread;
-        // Used for sleeping for a certain amount of time while allowing the thread to be woken up
-        private static AutoResetEvent? s_pollingThreadSleepEvent;
-
         private static List<CounterGroup>? s_counterGroupEnabledList;
         private static List<IncrementingPollingCounter> s_needsResetIncrementingPollingCounters = [];
 
-        private static void PollForValues()
+        private static int PollOnce()
         {
-            AutoResetEvent? sleepEvent = null;
-
             // Cache of onTimer callbacks for each CounterGroup.
             // We cache these outside of the scope of s_counterGroupLock because
             // calling into the callbacks can cause a re-entrancy into CounterGroup.Enable()
             // and result in a deadlock. (See https://github.com/dotnet/runtime/issues/40190 for details)
             var onTimers = new List<CounterGroup>();
             List<IncrementingPollingCounter>? countersToReset = null;
-            while (true)
-            {
+
                 int sleepDurationInMilliseconds = int.MaxValue;
                 lock (s_counterGroupLock)
                 {
-                    sleepEvent = s_pollingThreadSleepEvent;
                     foreach (CounterGroup counterGroup in s_counterGroupEnabledList!)
                     {
                         DateTime now = DateTime.UtcNow;
@@ -316,8 +290,6 @@ private static void PollForValues()
                     {
                         counter.UpdateMetric();
                     }
-
-                    countersToReset = null;
                 }
 
                 foreach (CounterGroup onTimer in onTimers)
@@ -329,10 +301,9 @@ private static void PollForValues()
                 {
                     sleepDurationInMilliseconds = -1; // WaitOne uses -1 to mean infinite
                 }
-                sleepEvent?.WaitOne(sleepDurationInMilliseconds);
-            }
-        }
 
+            return sleepDurationInMilliseconds;
+        }
 #endregion // Timer Processing
 
     }
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
index 0095e93ba4ae4c..62ae4beef3b2c3 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
@@ -12,9 +12,6 @@ namespace System.Diagnostics.Tracing
     /// DiagnosticCounter is an abstract class that serves as the parent class for various Counter* classes,
     /// namely EventCounter, PollingCounter, IncrementingEventCounter, and IncrementingPollingCounter.
     /// </summary>
-#if !ES_BUILD_STANDALONE
-    [UnsupportedOSPlatform("browser")]
-#endif
     public abstract class DiagnosticCounter : IDisposable
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
index 473ce079a23e10..790fda3af318c1 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
@@ -16,9 +16,6 @@ namespace System.Diagnostics.Tracing
     /// See https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs
     /// which shows tests, which are also useful in seeing actual use.
     /// </summary>
-#if !ES_BUILD_STANDALONE
-    [UnsupportedOSPlatform("browser")]
-#endif
     public partial class EventCounter : DiagnosticCounter
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Threads.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Threads.cs
new file mode 100644
index 00000000000000..93c7f3473c8f5f
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Threads.cs
@@ -0,0 +1,56 @@
+// 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.Threading;
+using System.Threading.Tasks;
+
+namespace System.Diagnostics.Tracing
+{
+    internal sealed partial class EventPipeEventDispatcher
+    {
+        private void StartDispatchTask(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency)
+        {
+            Debug.Assert(Monitor.IsEntered(m_dispatchControlLock));
+            Debug.Assert(sessionID != 0);
+
+            m_dispatchTaskCancellationSource = new CancellationTokenSource();
+            Task? previousDispatchTask = m_dispatchTask;
+            m_dispatchTask = Task.Factory.StartNew(() => DispatchEventsToEventListeners(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, previousDispatchTask, m_dispatchTaskCancellationSource.Token), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+        }
+
+        private void DispatchEventsToEventListeners(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, Task? previousDispatchTask, CancellationToken token)
+        {
+            Debug.Assert(sessionID != 0);
+            previousDispatchTask?.Wait(CancellationToken.None);
+
+            // Struct to fill with the call to GetNextEvent.
+            while (!token.IsCancellationRequested)
+            {
+                bool eventsReceived = DispatchEventsToEventListenersOnce(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, token);
+
+                // Wait for more events.
+                if (!token.IsCancellationRequested)
+                {
+                    if (!eventsReceived)
+                    {
+                        EventPipeInternal.WaitForSessionSignal(sessionID, Timeout.Infinite);
+                    }
+
+                    Thread.Sleep(10);
+                }
+            }
+
+            // Wait for SignalSession() to be called before we call disable, otherwise
+            // the SignalSession() call could be on a disabled session.
+            SpinWait sw = default;
+            while (Volatile.Read(ref m_sessionID) == sessionID)
+            {
+                sw.SpinOnce();
+            }
+
+            // Disable the old session. This can happen asynchronously since we aren't using the old session
+            // anymore.
+            EventPipeInternal.Disable(sessionID);
+        }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
new file mode 100644
index 00000000000000..f74c4da375499f
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
@@ -0,0 +1,50 @@
+// 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.Threading;
+using System.Threading.Tasks;
+
+namespace System.Diagnostics.Tracing
+{
+    // this is single-threaded version of EventPipeEventDispatcher
+    internal sealed partial class EventPipeEventDispatcher
+    {
+        // this is trade-off between speed of dispatching events and CPU usage of the same thread which is running actual business logic
+        private const int DispatcherDelayMs = 100;
+
+        private void StartDispatchTask(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency)
+        {
+            Debug.Assert(Monitor.IsEntered(m_dispatchControlLock));
+            Debug.Assert(sessionID != 0);
+
+            m_dispatchTaskCancellationSource = new CancellationTokenSource();
+            Task? previousDispatchTask = m_dispatchTask;
+            if (previousDispatchTask != null)
+            {
+                m_dispatchTask = previousDispatchTask.ContinueWith(_ => DispatchEventsToEventListeners(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, m_dispatchTaskCancellationSource.Token),
+                    m_dispatchTaskCancellationSource.Token, TaskContinuationOptions.None, TaskScheduler.Default);
+            }
+            else
+            {
+                m_dispatchTask = DispatchEventsToEventListeners(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, m_dispatchTaskCancellationSource.Token);
+            }
+        }
+
+        private async Task DispatchEventsToEventListeners(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, CancellationToken token)
+        {
+            Debug.Assert(sessionID != 0);
+
+            while (!token.IsCancellationRequested)
+            {
+                DispatchEventsToEventListenersOnce(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, token);
+                await Task.Delay(DispatcherDelayMs, token).ConfigureAwait(false);
+            }
+
+            // Wait for SignalSession() to be called before we call disable, otherwise
+            // the SignalSession() call could be on a disabled session.
+            await Task.Delay(1, CancellationToken.None).ConfigureAwait(false);
+
+            EventPipeInternal.Disable(sessionID);
+        }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs
index ffa63f1c98db1c..83911a0a13a492 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs
@@ -6,7 +6,7 @@
 
 namespace System.Diagnostics.Tracing
 {
-    internal sealed class EventPipeEventDispatcher
+    internal sealed partial class EventPipeEventDispatcher
     {
         internal sealed class EventListenerSubscription
         {
@@ -129,21 +129,6 @@ private void CommitDispatchConfiguration()
             StartDispatchTask(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency);
         }
 
-        private void StartDispatchTask(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency)
-        {
-            if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi())
-            {
-                throw new PlatformNotSupportedException();
-            }
-
-            Debug.Assert(Monitor.IsEntered(m_dispatchControlLock));
-            Debug.Assert(sessionID != 0);
-
-            m_dispatchTaskCancellationSource = new CancellationTokenSource();
-            Task? previousDispatchTask = m_dispatchTask;
-            m_dispatchTask = Task.Factory.StartNew(() => DispatchEventsToEventListeners(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, previousDispatchTask, m_dispatchTaskCancellationSource.Token), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
-        }
-
         private void SetStopDispatchTask()
         {
             Debug.Assert(Monitor.IsEntered(m_dispatchControlLock));
@@ -160,16 +145,13 @@ private void SetStopDispatchTask()
             Volatile.Write(ref m_sessionID, 0);
         }
 
-        private unsafe void DispatchEventsToEventListeners(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, Task? previousDispatchTask, CancellationToken token)
+        private unsafe bool DispatchEventsToEventListenersOnce(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, CancellationToken token)
         {
-            Debug.Assert(sessionID != 0);
-            previousDispatchTask?.Wait(CancellationToken.None);
+            bool eventsReceived = false;
 
             // Struct to fill with the call to GetNextEvent.
             EventPipeEventInstanceData instanceData;
-            while (!token.IsCancellationRequested)
-            {
-                bool eventsReceived = false;
+
                 // Get the next event.
                 while (!token.IsCancellationRequested && EventPipeInternal.GetNextEvent(sessionID, &instanceData))
                 {
@@ -184,30 +166,7 @@ private unsafe void DispatchEventsToEventListeners(ulong sessionID, DateTime syn
                         NativeRuntimeEventSource.Log.ProcessEvent(instanceData.EventID, instanceData.ThreadID, dateTimeStamp, instanceData.ActivityId, instanceData.ChildActivityId, payload);
                     }
                 }
-
-                // Wait for more events.
-                if (!token.IsCancellationRequested)
-                {
-                    if (!eventsReceived)
-                    {
-                        EventPipeInternal.WaitForSessionSignal(sessionID, Timeout.Infinite);
-                    }
-
-                    Thread.Sleep(10);
-                }
-            }
-
-            // Wait for SignalSession() to be called before we call disable, otherwise
-            // the SignalSession() call could be on a disabled session.
-            SpinWait sw = default;
-            while (Volatile.Read(ref m_sessionID) == sessionID)
-            {
-                sw.SpinOnce();
-            }
-
-            // Disable the old session. This can happen asynchronously since we aren't using the old session
-            // anymore.
-            EventPipeInternal.Disable(sessionID);
+            return eventsReceived;
         }
 
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
index 24a3a4485b7ebd..f8f07adc304417 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
@@ -1426,12 +1426,12 @@ protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* rel
 
                     if (m_Dispatchers != null && metadata.EnabledForAnyListener)
                     {
-#if MONO && !TARGET_BROWSER && !TARGET_WASI
+#if MONO && !TARGET_WASI
                         // On Mono, managed events from NativeRuntimeEventSource are written using WriteEventCore which can be
                         // written doubly because EventPipe tries to pump it back up to EventListener via NativeRuntimeEventSource.ProcessEvents.
                         // So we need to prevent this from getting written directly to the Listeners.
                         if (this.GetType() != typeof(NativeRuntimeEventSource))
-#endif // MONO && !TARGET_BROWSER && !TARGET_WASI
+#endif // MONO && !TARGET_WASI
                         {
                             var eventCallbackArgs = new EventWrittenEventArgs(this, eventId, pActivityId, relatedActivityId);
                             WriteToAllListeners(eventCallbackArgs, eventDataCount, data);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs
index 0b001e17c663a0..426b7df495a7dd 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs
@@ -12,9 +12,6 @@ namespace System.Diagnostics.Tracing
     /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates
     /// the counter value.
     /// </summary>
-#if !ES_BUILD_STANDALONE
-    [UnsupportedOSPlatform("browser")]
-#endif
     public partial class IncrementingEventCounter : DiagnosticCounter
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs
index 6c5bcec8e28ded..927f6df5816ed2 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs
@@ -14,9 +14,6 @@ namespace System.Diagnostics.Tracing
     /// Unlike IncrementingEventCounter, this takes in a polling callback that it can call to update
     /// its own metric periodically.
     /// </summary>
-#if !ES_BUILD_STANDALONE
-    [UnsupportedOSPlatform("browser")]
-#endif
     public partial class IncrementingPollingCounter : DiagnosticCounter
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs
index 4e9453a3a4aa88..87554db84f3696 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs
@@ -13,9 +13,6 @@ namespace System.Diagnostics.Tracing
     /// function to collect metrics on its own rather than the user having to call WriteMetric()
     /// every time.
     /// </summary>
-#if !ES_BUILD_STANDALONE
-    [UnsupportedOSPlatform("browser")]
-#endif
     public partial class PollingCounter : DiagnosticCounter
     {
         /// <summary>
diff --git a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml
index 1f33b65aeebd3f..14f1bcb22eb092 100644
--- a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml
+++ b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml
@@ -331,4 +331,64 @@
     <Left>net9.0/System.Runtime.dll</Left>
     <Right>net10.0/System.Runtime.dll</Right>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.DiagnosticCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/netstandard.dll</Left>
+    <Right>net10.0/netstandard.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.EventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/netstandard.dll</Left>
+    <Right>net10.0/netstandard.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.IncrementingEventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/netstandard.dll</Left>
+    <Right>net10.0/netstandard.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.IncrementingPollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/netstandard.dll</Left>
+    <Right>net10.0/netstandard.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.PollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/netstandard.dll</Left>
+    <Right>net10.0/netstandard.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.DiagnosticCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
+    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.EventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
+    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.IncrementingEventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
+    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.IncrementingPollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
+    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0014</DiagnosticId>
+    <Target>T:System.Diagnostics.Tracing.PollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
+    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
+    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
+  </Suppression>
 </Suppressions>
\ No newline at end of file
diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
index c4f38e8b6d4d30..5167fbe87959f9 100644
--- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -107,9 +107,6 @@
   <PropertyGroup>
     <NoWarn>$(NoWarn),618,67</NoWarn>
 
-    <!-- Diagnostics API for browser need to be made public for browser in future PRs, see https://github.com/dotnet/runtime/pull/111910 -->
-    <NoWarn Condition="'$(TargetsBrowser)' == 'true'">$(NoWarn);CA1416</NoWarn>
-
     <DefineConstants>$(DefineConstants);MONO_FEATURE_SRE</DefineConstants>
 
     <FeatureMono>true</FeatureMono>

From 7cd04e207dcb8ab0353f7b08ef1d3fed803eaaf7 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Fri, 14 Mar 2025 12:44:19 +0100
Subject: [PATCH 02/28] fix

---
 .../tests/Microsoft.Extensions.Diagnostics.Tests.csproj  | 1 -
 .../src/System.Diagnostics.DiagnosticSource.csproj       | 9 +++++----
 .../System.Diagnostics.DiagnosticSource.Tests.csproj     | 1 -
 .../tests/System.Diagnostics.Tracing.Tests.csproj        | 1 -
 .../System.Net.Http.Functional.Tests.csproj              | 1 -
 5 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
index 791f708d20a23c..d3a087bbf639c4 100644
--- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
+++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
@@ -7,7 +7,6 @@
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
-    <WasmPerfTracing>true</WasmPerfTracing>
     <MetricsSupport>true</MetricsSupport>
     <EventSourceSupport>true</EventSourceSupport>
   </PropertyGroup>
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
index 74eee967868132..6efbfe049348f1 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
+    <TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum);$(NetCoreAppCurrent)-browser</TargetFrameworks>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <NoWarn>$(NoWarn);SA1205</NoWarn>
     <EnableTrimAnalyzer Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">false</EnableTrimAnalyzer>
@@ -16,6 +16,7 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
 
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
   <PropertyGroup>
+    <TargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
     <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(DefineConstants);ENABLE_HTTP_HANDLER</DefineConstants>
     <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT</DefineConstants>
     <IncludePlatformAttributes>true</IncludePlatformAttributes>
@@ -57,8 +58,8 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
     <Compile Include="System\Diagnostics\PassThroughPropagator.cs" />
     <Compile Include="System\Diagnostics\RandomNumberGenerator.cs" />
     <Compile Include="System\Diagnostics\Metrics\AggregationManager.cs" />
-    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Threads.cs" Condition="'$(TargetOS)' != 'browser'" />
-    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Wasm.cs" Condition="'$(TargetOS)' == 'browser'"/>
+    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Threads.cs" Condition="('$(TargetsWasi)' != 'true' and '$(TargetsBrowser)' != 'true') or '$(FeatureWasmManagedThreads)' == 'true'" />
+    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Wasm.cs" Condition="('$(TargetsWasi)' == 'true' or '$(TargetsBrowser)' == 'true') and '$(FeatureWasmManagedThreads)' != 'true'" />
     <Compile Include="System\Diagnostics\Metrics\Aggregator.cs" />
     <Compile Include="System\Diagnostics\Metrics\AggregatorStore.cs" />
     <Compile Include="System\Diagnostics\Metrics\Counter.cs" />
@@ -148,7 +149,7 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
     <Compile Include="System\Diagnostics\Metrics\RuntimeMetrics.cs" />
   </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'">
+  <ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
     <Reference Include="System.Collections" />
     <Reference Include="System.Collections.Concurrent" />
     <Reference Include="System.Diagnostics.Tracing" />
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
index e16da53e29a732..507ec6840ccb64 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
@@ -6,7 +6,6 @@
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
-    <WasmPerfTracing>true</WasmPerfTracing>
     <MetricsSupport>true</MetricsSupport>
     <EventSourceSupport>true</EventSourceSupport>
   </PropertyGroup>
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
index 6862b424abcd3e..cfa91a7db4eeaf 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
+++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
@@ -7,7 +7,6 @@
     <TestDisableParallelization>true</TestDisableParallelization>
   </PropertyGroup>
   <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
-    <WasmPerfTracing>true</WasmPerfTracing>
     <MetricsSupport>true</MetricsSupport>
     <EventSourceSupport>true</EventSourceSupport>
   </PropertyGroup>
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index 6675d52324c305..1902d0e022306d 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -28,7 +28,6 @@
     <!-- This WASM test is slow on NodeJS. This sets the xharness timeout but there is also override in sendtohelix-browser.targets -->
     <WasmXHarnessTestsTimeout>01:15:00</WasmXHarnessTestsTimeout>
     <XunitShowProgress Condition="'$(FeatureWasmManagedThreads)' == 'true'">true</XunitShowProgress>
-    <WasmPerfTracing>true</WasmPerfTracing>
     <EventSourceSupport>true</EventSourceSupport>
     <MetricsSupport>true</MetricsSupport>
   </PropertyGroup>

From ed040439f307bef9b1af06693670af60db1ac1f6 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Fri, 14 Mar 2025 13:55:19 +0100
Subject: [PATCH 03/28] move System.Net.Http.EnableMetrics to
 https://github.com/dotnet/runtime/pull/113528

---
 .../src/System/Net/Http/GlobalHttpSettings.cs             | 8 --------
 .../src/System/Net/Http/HttpClientHandler.AnyMobile.cs    | 5 +----
 .../src/System/Net/Http/HttpClientHandler.cs              | 5 +----
 .../src/System/Net/Http/Metrics/MetricsHandler.cs         | 3 ---
 .../Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs     | 7 ++-----
 5 files changed, 4 insertions(+), 24 deletions(-)

diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs
index ab6878db43df48..e314957414b6b0 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs
@@ -21,14 +21,6 @@ internal static class DiagnosticsHandler
                 false);
         }
 
-        internal static class MetricsHandler
-        {
-            public static bool EnableMetrics { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch(
-                "System.Net.Http.EnableMetrics",
-                "DOTNET_SYSTEM_NET_HTTP_ENABLEMETRICS",
-                true);
-        }
-
         internal static class SocketsHttpHandler
         {
 #if !TARGET_BROWSER && !TARGET_WASI
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
index 90b55ad0e47428..6037df88bef807 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
@@ -45,10 +45,7 @@ private HttpMessageHandler Handler
 
                         // MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
                         // metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
-                        if (MetricsHandler.IsGloballyEnabled())
-                        {
-                            handler = new MetricsHandler(handler, _nativeMeterFactory, out _);
-                        }
+                        handler = new MetricsHandler(handler, _nativeMeterFactory, out _);
                         if (DiagnosticsHandler.IsGloballyEnabled())
                         {
                             handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current);
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
index 9c5c728ddb0658..afba32455bc2fe 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
@@ -45,10 +45,7 @@ private HttpMessageHandler Handler
 
                 // MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
                 // metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
-                if (MetricsHandler.IsGloballyEnabled())
-                {
-                    handler = new MetricsHandler(handler, _meterFactory, out _);
-                }
+                handler = new MetricsHandler(handler, _meterFactory, out _);
                 if (DiagnosticsHandler.IsGloballyEnabled())
                 {
                     handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current);
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs
index 9ee40930e3de4b..79a544816ccb09 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs
@@ -17,7 +17,6 @@ internal sealed class MetricsHandler : HttpMessageHandlerStage
 
         public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFactory, out Meter meter)
         {
-            Debug.Assert(IsGloballyEnabled());
             _innerHandler = innerHandler;
 
             meter = meterFactory?.Create("System.Net.Http") ?? SharedMeter.Instance;
@@ -34,8 +33,6 @@ public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFacto
                 advice: DiagnosticsHelper.ShortHistogramAdvice);
         }
 
-        internal static bool IsGloballyEnabled() => GlobalHttpSettings.MetricsHandler.EnableMetrics;
-
         internal override ValueTask<HttpResponseMessage> SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
         {
             if (_activeRequests.Enabled || _requestsDuration.Enabled)
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs
index 1af8e6abd53a12..6c0a8208508bdb 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs
@@ -531,11 +531,8 @@ private HttpMessageHandlerStage SetupHandlerChain()
 
             // MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
             // metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
-            if (MetricsHandler.IsGloballyEnabled())
-            {
-                handler = new MetricsHandler(handler, settings._meterFactory, out Meter meter);
-                settings._metrics = new SocketsHttpHandlerMetrics(meter);
-            }
+            handler = new MetricsHandler(handler, settings._meterFactory, out Meter meter);
+            settings._metrics = new SocketsHttpHandlerMetrics(meter);
 
             // DiagnosticsHandler is inserted before RedirectHandler so that trace propagation is done on redirects as well
             if (DiagnosticsHandler.IsGloballyEnabled() && settings._activityHeadersPropagator is DistributedContextPropagator propagator)

From 88e5ba524819c9fc96cfc8afa6416b33f2a182c9 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Fri, 14 Mar 2025 14:12:17 +0100
Subject: [PATCH 04/28] fix

---
 .../src/System.Diagnostics.DiagnosticSource.csproj              | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
index 6efbfe049348f1..56cda9e26166a6 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
@@ -149,7 +149,7 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
     <Compile Include="System\Diagnostics\Metrics\RuntimeMetrics.cs" />
   </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
+  <ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)' or '$(TargetsBrowser)' == 'true'">
     <Reference Include="System.Collections" />
     <Reference Include="System.Collections.Concurrent" />
     <Reference Include="System.Diagnostics.Tracing" />

From 0a22b098e295510b4aadf52fba0268a0655058fa Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Fri, 14 Mar 2025 14:44:16 +0100
Subject: [PATCH 05/28] fix

---
 .../System/Diagnostics/Metrics/AggregationManager.Threads.cs    | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
index 9f3a1411ba5924..ff6ac1b8774a33 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
@@ -28,7 +28,9 @@ public void Start()
             _collectThread = new Thread(() => CollectWorker(_cts.Token));
             _collectThread.IsBackground = true;
             _collectThread.Name = "MetricsEventSource CollectWorker";
+#pragma warning disable CA1416 // 'Thread.Start' is unsupported on: 'browser', there the actual implementation is in AggregationManager.Wasm.cs
             _collectThread.Start();
+#pragma warning restore CA1416
 
             _listener.Start();
             _initialInstrumentEnumerationComplete();

From 5d287d3e1b2d600057acd76e059751051da7d864 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Fri, 14 Mar 2025 18:01:54 +0100
Subject: [PATCH 06/28] fix

---
 .../src/System.Diagnostics.DiagnosticSource.csproj     |  6 +++---
 .../tests/BasicEventSourceTest/ActivityTracking.cs     | 10 +++++-----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
index 56cda9e26166a6..ff20bc31095ca0 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
@@ -58,8 +58,8 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
     <Compile Include="System\Diagnostics\PassThroughPropagator.cs" />
     <Compile Include="System\Diagnostics\RandomNumberGenerator.cs" />
     <Compile Include="System\Diagnostics\Metrics\AggregationManager.cs" />
-    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Threads.cs" Condition="('$(TargetsWasi)' != 'true' and '$(TargetsBrowser)' != 'true') or '$(FeatureWasmManagedThreads)' == 'true'" />
-    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Wasm.cs" Condition="('$(TargetsWasi)' == 'true' or '$(TargetsBrowser)' == 'true') and '$(FeatureWasmManagedThreads)' != 'true'" />
+    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Threads.cs" Condition="('$(TargetPlatformIdentifier)' != 'wasi' and '$(TargetPlatformIdentifier)' != 'browser') or '$(FeatureWasmManagedThreads)' == 'true'" />
+    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Wasm.cs" Condition="('$(TargetPlatformIdentifier)' == 'wasi' or '$(TargetPlatformIdentifier)' == 'browser') and '$(FeatureWasmManagedThreads)' != 'true'" />
     <Compile Include="System\Diagnostics\Metrics\Aggregator.cs" />
     <Compile Include="System\Diagnostics\Metrics\AggregatorStore.cs" />
     <Compile Include="System\Diagnostics\Metrics\Counter.cs" />
@@ -149,7 +149,7 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
     <Compile Include="System\Diagnostics\Metrics\RuntimeMetrics.cs" />
   </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)' or '$(TargetsBrowser)' == 'true'">
+  <ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)' or '$(TargetPlatformIdentifier)' == 'browser' or '$(TargetPlatformIdentifier)' == 'wasi'">
     <Reference Include="System.Collections" />
     <Reference Include="System.Collections.Concurrent" />
     <Reference Include="System.Diagnostics.Tracing" />
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
index ceab3fd7466c95..3d414df18ecbd5 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
@@ -14,11 +14,6 @@ namespace BasicEventSourceTests
 {
     public class ActivityTracking : IDisposable
     {
-        public ActivityTracking()
-        {
-            EventSource.SetCurrentThreadActivityId(Guid.Empty);
-        }
-
         public void Dispose()
         {
             EventSource.SetCurrentThreadActivityId(Guid.Empty);
@@ -40,6 +35,7 @@ public void StartStopCreatesActivity()
             using ActivityEventSource es = new ActivityEventSource();
 
             Assert.True(es.IsEnabled());
+            EventSource.SetCurrentThreadActivityId(Guid.Empty);
 
             Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId);
             es.ExampleStart();
@@ -53,6 +49,7 @@ public async Task ActivityFlowsAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
+            EventSource.SetCurrentThreadActivityId(Guid.Empty);
 
             Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId);
             es.ExampleStart();
@@ -68,6 +65,7 @@ public async Task ActivityIdIsZeroedOnThreadSwitchOut()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
+            EventSource.SetCurrentThreadActivityId(Guid.Empty);
 
             // Run tasks on many threads. If an activity id leaks it is likely
             // that the thread will be sheduled to run one of our other tasks
@@ -101,6 +99,7 @@ public async Task SetCurrentActivityIdBeforeEventFlowsAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
+            EventSource.SetCurrentThreadActivityId(Guid.Empty);
             try
             {
                 Guid g = Guid.NewGuid();
@@ -126,6 +125,7 @@ public async Task SetCurrentActivityIdAfterEventDoesNotFlowAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
+            EventSource.SetCurrentThreadActivityId(Guid.Empty);
             try
             {
                 es.ExampleStart();

From bfdbda8313626e6c58c1643ff2e15dd4101b89cc Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Sat, 15 Mar 2025 11:03:31 +0100
Subject: [PATCH 07/28] ActivityTracker_Instance_Enable

---
 .../BasicEventSourceTest/ActivityTracking.cs  | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
index 3d414df18ecbd5..ee42a0852b9127 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
@@ -5,6 +5,7 @@
 using System.Collections.Generic;
 using System.Diagnostics.Tracing;
 using System.Linq;
+using System.Reflection;
 using System.Text;
 using System.Threading.Tasks;
 using Xunit;
@@ -14,8 +15,30 @@ namespace BasicEventSourceTests
 {
     public class ActivityTracking : IDisposable
     {
+        public ActivityTracking()
+        {
+            // make sure ActivityTracker is enabled
+            // On CoreCLR, it's enabled via
+            //    FireAssemblyLoadStart -> ActivityTracker::Start -> AssemblyLoadContext.StartAssemblyLoad -> ActivityTracker.Instance.Enable()
+            // on Mono it could be enabled via
+            //    System.Threading.Tasks.TplEventSource followed by EventSource.SetCurrentThreadActivityId
+            // but it's too complex to do it in a portable way, so we just call it explicitly
+            ActivityTracker_Instance_Enable();
+        }
+
+        // ActivityTracker.Instance.Enable(); via reflection
+        private static bool ActivityTracker_Instance_Enable()
+        {
+            var type = typeof(EventSource).Assembly.GetType("System.Diagnostics.Tracing.ActivityTracker");
+            var prop = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
+            var m = type.GetMethod("Enable");
+            var instance = prop.GetValue(null);
+            m.Invoke(instance, null);
+        }
+
         public void Dispose()
         {
+            // reset ActivityTracker state between tests
             EventSource.SetCurrentThreadActivityId(Guid.Empty);
         }
 

From 7a6f106a95334603723ea18f44f1bbf91b201ba8 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Sat, 15 Mar 2025 12:01:04 +0100
Subject: [PATCH 08/28] fix

---
 .../tests/BasicEventSourceTest/ActivityTracking.cs              | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
index ee42a0852b9127..b9d804816806b3 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
@@ -27,7 +27,7 @@ public ActivityTracking()
         }
 
         // ActivityTracker.Instance.Enable(); via reflection
-        private static bool ActivityTracker_Instance_Enable()
+        private static void ActivityTracker_Instance_Enable()
         {
             var type = typeof(EventSource).Assembly.GetType("System.Diagnostics.Tracing.ActivityTracker");
             var prop = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);

From 04df34bf9eacd8bc025eda7ca5c2bff4d85c7f9f Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Mon, 17 Mar 2025 17:29:52 +0100
Subject: [PATCH 09/28] fix

---
 .../BasicEventSourceTest/ActivityTracking.cs      |  9 ++-------
 .../tests/System.Diagnostics.Tracing.Tests.csproj |  2 ++
 src/mono/browser/runtime/diagnostics/index.ts     | 15 ++++++++++-----
 3 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
index b9d804816806b3..e975859721f929 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs
@@ -22,7 +22,7 @@ public ActivityTracking()
             //    FireAssemblyLoadStart -> ActivityTracker::Start -> AssemblyLoadContext.StartAssemblyLoad -> ActivityTracker.Instance.Enable()
             // on Mono it could be enabled via
             //    System.Threading.Tasks.TplEventSource followed by EventSource.SetCurrentThreadActivityId
-            // but it's too complex to do it in a portable way, so we just call it explicitly
+            // but it's too complex for the unit test, so we just call it explicitly
             ActivityTracker_Instance_Enable();
         }
 
@@ -58,11 +58,10 @@ public void StartStopCreatesActivity()
             using ActivityEventSource es = new ActivityEventSource();
 
             Assert.True(es.IsEnabled());
-            EventSource.SetCurrentThreadActivityId(Guid.Empty);
 
             Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId);
             es.ExampleStart();
-            //Assert.NotEqual(Guid.Empty, EventSource.CurrentThreadActivityId);
+            Assert.NotEqual(Guid.Empty, EventSource.CurrentThreadActivityId);
             es.ExampleStop();
             Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId);
         }
@@ -72,7 +71,6 @@ public async Task ActivityFlowsAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
-            EventSource.SetCurrentThreadActivityId(Guid.Empty);
 
             Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId);
             es.ExampleStart();
@@ -88,7 +86,6 @@ public async Task ActivityIdIsZeroedOnThreadSwitchOut()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
-            EventSource.SetCurrentThreadActivityId(Guid.Empty);
 
             // Run tasks on many threads. If an activity id leaks it is likely
             // that the thread will be sheduled to run one of our other tasks
@@ -122,7 +119,6 @@ public async Task SetCurrentActivityIdBeforeEventFlowsAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
-            EventSource.SetCurrentThreadActivityId(Guid.Empty);
             try
             {
                 Guid g = Guid.NewGuid();
@@ -148,7 +144,6 @@ public async Task SetCurrentActivityIdAfterEventDoesNotFlowAsync()
         {
             using ActivityEventListener l = new ActivityEventListener();
             using ActivityEventSource es = new ActivityEventSource();
-            EventSource.SetCurrentThreadActivityId(Guid.Empty);
             try
             {
                 es.ExampleStart();
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
index cfa91a7db4eeaf..181a855ebf9f21 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
+++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
@@ -9,6 +9,8 @@
   <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
     <MetricsSupport>true</MetricsSupport>
     <EventSourceSupport>true</EventSourceSupport>
+    <!-- this is necessary for libmono-component-diagnostics_tracing-static.a to be linked, which makes the EventPipeEventProvider.EventActivityIdControl to work in Mono -->
+    <WasmPerfTracing>true</WasmPerfTracing>
   </PropertyGroup>
   <ItemGroup Condition="'$(TargetsAppleMobile)' == 'true' or '$(TargetOS)' == 'android'">
     <RuntimeComponents Include="diagnostics_tracing" />
diff --git a/src/mono/browser/runtime/diagnostics/index.ts b/src/mono/browser/runtime/diagnostics/index.ts
index 8ee5274257e5f6..97ed81eb0263b9 100644
--- a/src/mono/browser/runtime/diagnostics/index.ts
+++ b/src/mono/browser/runtime/diagnostics/index.ts
@@ -11,22 +11,27 @@ export function setRuntimeGlobals (globalObjects: GlobalObjects): void {
     setRuntimeGlobalsImpl(globalObjects);
 
     diagnosticHelpers.ds_rt_websocket_create = (urlPtr :CharPtr):number => {
-        throw new Error("Not implemented");
+        // Not implemented
+        return 1;
     };
 
     diagnosticHelpers.ds_rt_websocket_send = (client_socket :number, buffer:VoidPtr, bytes_to_write:number):number => {
-        throw new Error("Not implemented");
+        // Not implemented
+        return bytes_to_write;
     };
 
     diagnosticHelpers.ds_rt_websocket_poll = (client_socket :number):number => {
-        throw new Error("Not implemented");
+        // Not implemented
+        return 0;
     };
 
     diagnosticHelpers.ds_rt_websocket_recv = (client_socket :number, buffer:VoidPtr, bytes_to_read:number):number => {
-        throw new Error("Not implemented");
+        // Not implemented
+        return 0;
     };
 
     diagnosticHelpers. ds_rt_websocket_close = (client_socket :number):number => {
-        throw new Error("Not implemented");
+        // Not implemented
+        return 0;
     };
 }

From d1a8712adc2d39330c47ef2c93c8b87e50edaf4c Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Tue, 18 Mar 2025 11:13:18 +0100
Subject: [PATCH 10/28] more tests

---
 .../tests/ActivityTests.cs                    |   6 +-
 .../tests/MetricEventSourceTests.cs           | 341 +++++++++---------
 2 files changed, 179 insertions(+), 168 deletions(-)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
index 0a56bbd6772e84..435fde8804035e 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
@@ -1416,7 +1416,7 @@ public void DiagnosticSourceStartStop()
         /// <summary>
         /// Tests that Activity.Current flows correctly within async methods
         /// </summary>
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
+        [Fact]
         public async Task ActivityCurrentFlowsWithAsyncSimple()
         {
             Activity activity = new Activity("activity").Start();
@@ -1433,7 +1433,7 @@ await Task.Run(() =>
         /// <summary>
         /// Tests that Activity.Current flows correctly within async methods
         /// </summary>
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
+        [Fact]
         public async Task ActivityCurrentFlowsWithAsyncComplex()
         {
             Activity originalActivity = Activity.Current;
@@ -1472,7 +1472,7 @@ public async Task ActivityCurrentFlowsWithAsyncComplex()
         /// <summary>
         /// Tests that Activity.Current could be set
         /// </summary>
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
+        [Fact]
         public async Task ActivityCurrentSet()
         {
             Activity activity = new Activity("activity");
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
index 4ad1aba0d107a3..b52992065f8c95 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
@@ -9,6 +9,7 @@
 using System.Runtime.CompilerServices;
 using System.Text;
 using System.Threading;
+using System.Threading.Tasks;
 using Microsoft.DotNet.RemoteExecutor;
 using Xunit;
 using Xunit.Abstractions;
@@ -77,7 +78,7 @@ public void TestVersion()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_DifferentCounters()
+        public async Task MultipleListeners_DifferentCounters()
         {
             using Meter meter = new Meter("TestMeter1");
             Counter<int> c = meter.CreateCounter<int>("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } });
@@ -94,20 +95,20 @@ public void MultipleListeners_DifferentCounters()
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter2"))
                 {
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 1);
                     c2.Add(5);
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 2);
                     c2.Add(12);
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 3);
                     events2 = listener2.Events.ToArray();
                 }
             }
@@ -125,7 +126,7 @@ public void MultipleListeners_DifferentCounters()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_ReuseCounter()
+        public async Task MultipleListeners_ReuseCounter()
         {
             using Meter meter = new Meter("TestMeter1");
             Counter<int> c = meter.CreateCounter<int>("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } });
@@ -142,22 +143,22 @@ public void MultipleListeners_ReuseCounter()
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1", "TestMeter2"))
                 {
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 1);
                     c.Add(6);
                     c2.Add(5);
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 2);
                     c.Add(13);
                     c2.Add(12);
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 3);
                     events2 = listener2.Events.ToArray();
                 }
             }
@@ -176,7 +177,7 @@ public void MultipleListeners_ReuseCounter()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_CollectAfterDisableListener()
+        public async Task MultipleListeners_CollectAfterDisableListener()
         {
             using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object());
             Counter<int> c = meter.CreateCounter<int>("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } });
@@ -193,27 +194,27 @@ public void MultipleListeners_CollectAfterDisableListener()
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter2"))
                 {
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 1);
                     c2.Add(5);
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 2);
                     c2.Add(12);
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 3);
                     events2 = listener2.Events.ToArray();
                 }
 
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 7);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 7);
                 c.Add(6);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 8);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 8);
                 c.Add(13);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 9);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 9);
                 events = listener.Events.ToArray();
             }
 
@@ -230,7 +231,7 @@ public void MultipleListeners_CollectAfterDisableListener()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_ThreeCounters()
+        public async Task MultipleListeners_ThreeCounters()
         {
             using Meter meter = new Meter("TestMeter1");
             Counter<int> c = meter.CreateCounter<int>("counter1");
@@ -250,23 +251,23 @@ public void MultipleListeners_ThreeCounters()
             EventWrittenEventArgs[] events, events2, events3;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 events = listener.Events.ToArray();
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter2"))
                 {
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 1);
                     c2.Add(6);
-                    listener2.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                    await listener2.WaitForCollectionStop(s_waitForEventTimeout, 2);
                     events2 = listener2.Events.ToArray();
 
                     using (MetricsEventListener listener3 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter3"))
                     {
-                        listener3.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                        await listener3.WaitForCollectionStop(s_waitForEventTimeout, 1);
                         c3.Add(7);
-                        listener3.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                        await listener3.WaitForCollectionStop(s_waitForEventTimeout, 2);
                         events3 = listener3.Events.ToArray();
                     }
                 }
@@ -290,7 +291,7 @@ public void MultipleListeners_ThreeCounters()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void SingleListener_Wildcard()
+        public async Task SingleListener_Wildcard()
         {
             using Meter meter = new Meter("Test.TestMeter1");
             Counter<int> c = meter.CreateCounter<int>("counter1");
@@ -310,11 +311,11 @@ public void SingleListener_Wildcard()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "*"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 c2.Add(10);
                 c3.Add(20);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 events = listener.Events.ToArray();
             }
 
@@ -333,7 +334,7 @@ public void SingleListener_Wildcard()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void SingleListener_Prefix()
+        public async Task SingleListener_Prefix()
         {
             using Meter meter = new Meter("Company1.TestMeter1");
             Counter<int> c = meter.CreateCounter<int>("counter1");
@@ -353,11 +354,11 @@ public void SingleListener_Prefix()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "Company1*"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 c2.Add(10);
                 c3.Add(20);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 events = listener.Events.ToArray();
             }
 
@@ -370,7 +371,7 @@ public void SingleListener_Prefix()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_OverlappingListeners()
+        public async Task MultipleListeners_OverlappingListeners()
         {
             using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" } }, new object());
             Counter<int> c = meter.CreateCounter<int>("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } });
@@ -389,13 +390,13 @@ public void MultipleListeners_OverlappingListeners()
             {
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter2"))
                 {
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                     c.Add(5);
                     c2.Add(6);
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                     c.Add(12);
                     c2.Add(13);
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                     events = listener.Events.ToArray();
                     events2 = listener2.Events.ToArray();
                 }
@@ -415,7 +416,7 @@ public void MultipleListeners_OverlappingListeners()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_UnsharedSessionRejectsUnsharedListener()
+        public async Task MultipleListeners_UnsharedSessionRejectsUnsharedListener()
         {
             using Meter meter = new Meter(new MeterOptions("TestMeter7")
                                             {
@@ -438,21 +439,21 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(-10);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
                 g.Record(9);
 
                 using MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7");
-                listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout);
+                await listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout);
 
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -469,7 +470,7 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_UnsharedSessionRejectsSharedListener()
+        public async Task MultipleListeners_UnsharedSessionRejectsSharedListener()
         {
             using Meter meter = new Meter(new MeterOptions("TestMeter7")
                                             {
@@ -493,12 +494,12 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(-1);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
@@ -506,10 +507,10 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener()
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7"))
                 {
-                    listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout);
+                    await listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout);
                 }
 
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -526,7 +527,7 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_SharedSessionRejectsUnsharedListener()
+        public async Task MultipleListeners_SharedSessionRejectsUnsharedListener()
         {
             using Meter meter = new Meter(new MeterOptions("TestMeter7")
                                             {
@@ -549,12 +550,12 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(100);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
@@ -562,10 +563,10 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener()
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7"))
                 {
-                    listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout);
+                    await listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout);
                 }
 
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -582,7 +583,7 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs()
+        public async Task MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs()
         {
             using Meter meter = new Meter(new MeterOptions("TestMeter7")
                                             {
@@ -596,21 +597,21 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs()
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, 10, 12, "TestMeter7"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, 11, 13, "TestMeter7"))
                 {
-                    listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout);
+                    await listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout);
                     events2 = listener2.Events.ToArray();
                     AssertMultipleSessionsConfiguredIncorrectlyErrorEventsPresent(events2, "12", "13", "10", "11", IntervalSecs.ToString(), IntervalSecs.ToString());
                 }
 
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 c.Add(19);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
                 events = listener.Events.ToArray();
             }
 
@@ -622,7 +623,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs()
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         [ActiveIssue("This test appears to interfere with the others due to the session not being shut down.")]
-        public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerWithDifferentArgsAfterListenerDisposed()
+        public async Task MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerWithDifferentArgsAfterListenerDisposed()
         {
             using Meter meter = new Meter(new MeterOptions("TestMeter7")
                                             {
@@ -636,19 +637,19 @@ public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerW
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, string.Empty, isShared: true, IntervalSecs, 10, 12, "TestMeter7"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 c.Add(19);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
                 events = listener.Events.ToArray();
             }
 
             using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, 11, 13, "TestMeter7"))
             {
-                listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout);
+                await listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout);
                 events2 = listener2.Events.ToArray();
                 AssertMultipleSessionsConfiguredIncorrectlyErrorEventsPresent(events2, "12", "13", "10", "11", IntervalSecs.ToString(), IntervalSecs.ToString());
             }
@@ -660,7 +661,7 @@ public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerW
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval()
+        public async Task MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval()
         {
             using Meter meter = new Meter(new MeterOptions("TestMeter7")
                                             {
@@ -683,12 +684,12 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval(
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(5);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
@@ -696,13 +697,13 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval(
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs + 1, "TestMeter7"))
                 {
-                    listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout);
+                    await listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout);
                     events2 = listener2.Events.ToArray();
                     AssertMultipleSessionsConfiguredIncorrectlyErrorEventsPresent(events2, MetricsEventListener.HistogramLimit.ToString(), MetricsEventListener.HistogramLimit.ToString(),
                         MetricsEventListener.TimeSeriesLimit.ToString(), MetricsEventListener.TimeSeriesLimit.ToString(), IntervalSecs.ToString(), (IntervalSecs + 1).ToString());
                 }
 
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -719,7 +720,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval(
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_DisposeMeterBeforeSecondListener()
+        public async Task MultipleListeners_DisposeMeterBeforeSecondListener()
         {
             using Meter meterA = new Meter("TestMeter8", null, null, new object());
             using Meter meterB = new Meter(new MeterOptions("TestMeter9")
@@ -743,20 +744,20 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener()
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8;TestMeter9"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(-100);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
                 g.Record(100);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
 
                 meterA.Dispose();
-                listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3);
+                await listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3);
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8"))
                 {
@@ -764,7 +765,7 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener()
                 }
 
                 h.Record(21);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
                 events = listener.Events.ToArray();
             }
 
@@ -785,7 +786,7 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener()
+        public async Task MultipleListeners_DisposeMetersDuringAndAfterSecondListener()
         {
             using Meter meterA = new Meter("TestMeter8", null, new TagList() { { "1Mk1", "1Mv1" }, { "1Mk2", "Mv2" } });
             using Meter meterB = new Meter(new MeterOptions("TestMeter9")
@@ -809,31 +810,31 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener()
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8;TestMeter9"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(-10);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
                 g.Record(9);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
 
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8;TestMeter9"))
                 {
                     meterA.Dispose();
-                    listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3);
+                    await listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3);
 
                     events2 = listener2.Events.ToArray();
                 }
 
                 h.Record(21);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
 
                 meterB.Dispose();
-                listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 5);
+                await listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 5);
 
                 events = listener.Events.ToArray();
             }
@@ -854,9 +855,9 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener()
             AssertEndInstrumentReportingEventsPresent(events2, c, oc, og, udc, oudc, g);
         }
 
-        [Fact]
+        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] // time sensitive test
         [OuterLoop("Slow and has lots of console spew")]
-        public void MultipleListeners_PublishingInstruments()
+        public async Task MultipleListeners_PublishingInstruments()
         {
             using Meter meterA = new Meter(new MeterOptions("TestMeter10")
                                             {
@@ -880,10 +881,10 @@ public void MultipleListeners_PublishingInstruments()
             EventWrittenEventArgs[] events, events2;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.InstrumentPublishing, isShared: true, null, ""))
             {
-                listener.WaitForEnumerationComplete(s_waitForEventTimeout);
+                await listener.WaitForEnumerationComplete(s_waitForEventTimeout);
                 using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.InstrumentPublishing, isShared: true, null, ""))
                 {
-                    listener2.WaitForEnumerationComplete(s_waitForEventTimeout);
+                    await listener2.WaitForEnumerationComplete(s_waitForEventTimeout);
                     events = listener.Events.ToArray();
                     events2 = listener2.Events.ToArray();
                 }
@@ -899,7 +900,7 @@ public void MultipleListeners_PublishingInstruments()
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesTimeSeriesWithEmptyMetadata()
         {
-            RemoteExecutor.Invoke(static () =>
+            RemoteExecutor.Invoke(async static () =>
             {
                 CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("fi-FI");
 
@@ -924,17 +925,17 @@ public void EventSourcePublishesTimeSeriesWithEmptyMetadata()
                 EventWrittenEventArgs[] events;
                 using (MetricsEventListener listener = new MetricsEventListener(NullTestOutputHelper.Instance, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter1"))
                 {
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                     c.Add(5);
                     h.Record(19);
                     udc.Add(-33);
                     g.Record(200);
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                     c.Add(12);
                     h.Record(26);
                     udc.Add(-40);
                     g.Record(-200);
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                     events = listener.Events.ToArray();
                 }
 
@@ -960,7 +961,7 @@ public void WriteLine(string format, params object[] args) { }
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourcePublishesTimeSeriesWithMetadata()
+        public async Task EventSourcePublishesTimeSeriesWithMetadata()
         {
             using Meter meter = new Meter("TestMeter2");
             Counter<int> c = meter.CreateCounter<int>("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } });
@@ -977,17 +978,17 @@ public void EventSourcePublishesTimeSeriesWithMetadata()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter2"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(77);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
                 g.Record(-177);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1005,7 +1006,7 @@ public void EventSourcePublishesTimeSeriesWithMetadata()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourcePublishesTimeSeriesForLateMeter()
+        public async Task EventSourcePublishesTimeSeriesForLateMeter()
         {
             // this ensures the MetricsEventSource exists when the listener tries to query
             using Meter dummy = new Meter("dummy");
@@ -1023,7 +1024,7 @@ public void EventSourcePublishesTimeSeriesForLateMeter()
                 EventWrittenEventArgs[] events;
                 using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter3"))
                 {
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
 
                     // the Meter is created after the EventSource was already monitoring
                     meter = new Meter("TestMeter3");
@@ -1043,12 +1044,12 @@ public void EventSourcePublishesTimeSeriesForLateMeter()
                     h.Record(19);
                     udc.Add(33);
                     g.Record(1);
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                     c.Add(12);
                     h.Record(26);
                     udc.Add(40);
                     g.Record(-1);
-                    listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                    await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                     events = listener.Events.ToArray();
                 }
 
@@ -1071,7 +1072,7 @@ public void EventSourcePublishesTimeSeriesForLateMeter()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourcePublishesTimeSeriesForLateInstruments()
+        public async Task EventSourcePublishesTimeSeriesForLateInstruments()
         {
             // this ensures the MetricsEventSource exists when the listener tries to query
             using Meter meter = new Meter("TestMeter4");
@@ -1086,7 +1087,7 @@ public void EventSourcePublishesTimeSeriesForLateInstruments()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter4"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
 
                 // Instruments are created after the EventSource was already monitoring
                 c = meter.CreateCounter<int>("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } });
@@ -1104,12 +1105,12 @@ public void EventSourcePublishesTimeSeriesForLateInstruments()
                 h.Record(19);
                 udc.Add(-33);
                 g.Record(-1000);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(-40);
                 g.Record(2000);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1127,7 +1128,7 @@ public void EventSourcePublishesTimeSeriesForLateInstruments()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourcePublishesTimeSeriesWithTags()
+        public async Task EventSourcePublishesTimeSeriesWithTags()
         {
             using Meter meter = new Meter("TestMeter5");
             Counter<int> c = meter.CreateCounter<int>("counter1");
@@ -1168,7 +1169,7 @@ public void EventSourcePublishesTimeSeriesWithTags()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter5"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
 
                 c.Add(5, new KeyValuePair<string,object?>("Color", "red"));
                 c.Add(6, new KeyValuePair<string, object?>("Color", "blue"));
@@ -1178,7 +1179,7 @@ public void EventSourcePublishesTimeSeriesWithTags()
                 udc.Add(-34, new KeyValuePair<string, object?>("Color", "blue"));
                 g.Record(1, new KeyValuePair<string, object?>("Color", "black"));
                 g.Record(2, new KeyValuePair<string, object?>("Color", "white"));
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
 
                 c.Add(12, new KeyValuePair<string, object?>("Color", "red"));
                 c.Add(13, new KeyValuePair<string, object?>("Color", "blue"));
@@ -1188,7 +1189,7 @@ public void EventSourcePublishesTimeSeriesWithTags()
                 udc.Add(41, new KeyValuePair<string, object?>("Color", "blue"));
                 g.Record(3, new KeyValuePair<string, object?>("Color", "black"));
                 g.Record(4, new KeyValuePair<string, object?>("Color", "white"));
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1215,7 +1216,7 @@ public void EventSourcePublishesTimeSeriesWithTags()
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
         [ActiveIssue("https://github.com/dotnet/runtime/issues/79749", TargetFrameworkMonikers.NetFramework)]
-        public void EventSourceFiltersInstruments()
+        public async Task EventSourceFiltersInstruments()
         {
             object scope = new object();
             using Meter meterA = new Meter("TestMeterA", null, new TagList() { { "1Mk1", null } }, scope);
@@ -1241,7 +1242,7 @@ public void EventSourceFiltersInstruments()
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs,
                 "TestMeterA\\counter3;TestMeterB\\counter1;TestMeterC\\counter2;TestMeterB;TestMeterC\\counter3"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
 
                 c1a.Add(1);
                 c2a.Add(1);
@@ -1252,7 +1253,7 @@ public void EventSourceFiltersInstruments()
                 c1c.Add(1);
                 c2c.Add(1);
                 c3c.Add(1);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
 
                 c1a.Add(2);
                 c2a.Add(2);
@@ -1263,7 +1264,7 @@ public void EventSourceFiltersInstruments()
                 c1c.Add(2);
                 c2c.Add(2);
                 c3c.Add(2);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1283,7 +1284,7 @@ public void EventSourceFiltersInstruments()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourcePublishesMissingDataPoints()
+        public async Task EventSourcePublishesMissingDataPoints()
         {
             using Meter meter = new Meter("TestMeter6", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object());
             Counter<int> c = meter.CreateCounter<int>("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } });
@@ -1343,21 +1344,21 @@ public void EventSourcePublishesMissingDataPoints()
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter6"))
             {
                 // no measurements in interval 1
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(-123);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 // no measurements in interval 3
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
                 g.Record(123);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
                 // no measurements in interval 5
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 5);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 5);
                 events = listener.Events.ToArray();
             }
 
@@ -1375,7 +1376,7 @@ public void EventSourcePublishesMissingDataPoints()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourcePublishesEndEventsOnMeterDispose()
+        public async Task EventSourcePublishesEndEventsOnMeterDispose()
         {
             object scope = new object();
             using Meter meterA = new Meter("TestMeter8", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", null } }, scope);
@@ -1400,23 +1401,23 @@ public void EventSourcePublishesEndEventsOnMeterDispose()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter8;TestMeter9"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(9);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
                 g.Record(90);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
 
                 meterA.Dispose();
-                listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3);
+                await listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3);
 
                 h.Record(21);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 4);
                 events = listener.Events.ToArray();
             }
 
@@ -1437,7 +1438,7 @@ public void EventSourcePublishesEndEventsOnMeterDispose()
         [OuterLoop("Slow and has lots of console spew")]
         public void EventSourcePublishesInstruments()
         {
-            RemoteExecutor.Invoke(static () =>
+            RemoteExecutor.Invoke(async static () =>
             {
 
                 object scope = new object();
@@ -1466,7 +1467,7 @@ public void EventSourcePublishesInstruments()
                 EventWrittenEventArgs[] events;
                 using (MetricsEventListener listener = new MetricsEventListener(NullTestOutputHelper.Instance, MetricsEventListener.InstrumentPublishing, null, ""))
                 {
-                    listener.WaitForEnumerationComplete(s_waitForEventTimeout);
+                    await listener.WaitForEnumerationComplete(s_waitForEventTimeout);
                     events = listener.Events.ToArray();
                 }
 
@@ -1477,7 +1478,7 @@ public void EventSourcePublishesInstruments()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourcePublishesAllDataTypes()
+        public async Task EventSourcePublishesAllDataTypes()
         {
             using Meter meter = new Meter("TestMeter12");
             Counter<int> i = meter.CreateCounter<int>("counterInt");
@@ -1491,7 +1492,7 @@ public void EventSourcePublishesAllDataTypes()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter12"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
 
                 i.Add(1_234_567);
                 s.Add(21_432);
@@ -1508,7 +1509,7 @@ public void EventSourcePublishesAllDataTypes()
                 dec.Add(1);
                 f.Add(1);
                 d.Add(1);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
 
                 i.Add(1_234_567);
                 s.Add(21_432);
@@ -1525,7 +1526,7 @@ public void EventSourcePublishesAllDataTypes()
                 dec.Add(1);
                 f.Add(1);
                 d.Add(1);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1543,7 +1544,7 @@ public void EventSourcePublishesAllDataTypes()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourceEnforcesTimeSeriesLimit()
+        public async Task EventSourceEnforcesTimeSeriesLimit()
         {
             using Meter meter = new Meter("TestMeter13");
             Counter<int> c = meter.CreateCounter<int>("counter1");
@@ -1551,19 +1552,19 @@ public void EventSourceEnforcesTimeSeriesLimit()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, 2, 50, "TestMeter13"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
 
                 c.Add(5, new KeyValuePair<string, object?>("Color", "red"));
                 c.Add(6, new KeyValuePair<string, object?>("Color", "blue"));
                 c.Add(7, new KeyValuePair<string, object?>("Color", "green"));
                 c.Add(8, new KeyValuePair<string, object?>("Color", "yellow"));
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
 
                 c.Add(12, new KeyValuePair<string, object?>("Color", "red"));
                 c.Add(13, new KeyValuePair<string, object?>("Color", "blue"));
                 c.Add(14, new KeyValuePair<string, object?>("Color", "green"));
                 c.Add(15, new KeyValuePair<string, object?>("Color", "yellow"));
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1579,7 +1580,7 @@ public void EventSourceEnforcesTimeSeriesLimit()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourceEnforcesHistogramLimit()
+        public async Task EventSourceEnforcesHistogramLimit()
         {
             using Meter meter = new Meter("TestMeter14");
             Histogram<int> h = meter.CreateHistogram<int>("histogram1");
@@ -1588,19 +1589,19 @@ public void EventSourceEnforcesHistogramLimit()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, 50, 2, "TestMeter14"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
 
                 h.Record(5, new KeyValuePair<string, object?>("Color", "red"));
                 h.Record(6, new KeyValuePair<string, object?>("Color", "blue"));
                 h.Record(7, new KeyValuePair<string, object?>("Color", "green"));
                 h.Record(8, new KeyValuePair<string, object?>("Color", "yellow"));
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
 
                 h.Record(12, new KeyValuePair<string, object?>("Color", "red"));
                 h.Record(13, new KeyValuePair<string, object?>("Color", "blue"));
                 h.Record(14, new KeyValuePair<string, object?>("Color", "green"));
                 h.Record(15, new KeyValuePair<string, object?>("Color", "yellow"));
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1616,7 +1617,7 @@ public void EventSourceEnforcesHistogramLimit()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourceHandlesObservableCallbackException()
+        public async Task EventSourceHandlesObservableCallbackException()
         {
             using Meter meter = new Meter("TestMeter15");
             Counter<int> c = meter.CreateCounter<int>("counter1");
@@ -1626,11 +1627,11 @@ public void EventSourceHandlesObservableCallbackException()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter15"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1643,7 +1644,7 @@ public void EventSourceHandlesObservableCallbackException()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourceWorksWithSequentialListeners()
+        public async Task EventSourceWorksWithSequentialListeners()
         {
             using Meter meter = new Meter("TestMeter16");
             Counter<int> c = meter.CreateCounter<int>("counter1");
@@ -1660,17 +1661,17 @@ public void EventSourceWorksWithSequentialListeners()
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter16"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(-10);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
                 g.Record(10);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1690,17 +1691,17 @@ public void EventSourceWorksWithSequentialListeners()
             events = null;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter16"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 c.Add(5);
                 h.Record(19);
                 udc.Add(33);
                 g.Record(-10);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 c.Add(12);
                 h.Record(26);
                 udc.Add(40);
                 g.Record(10);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1718,7 +1719,7 @@ public void EventSourceWorksWithSequentialListeners()
 
         [Fact]
         [OuterLoop("Slow and has lots of console spew")]
-        public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries()
+        public async Task EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries()
         {
             using Meter meter = new Meter(new MeterOptions("TestMeter17")
                                             {
@@ -1734,19 +1735,19 @@ public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries()
             // HistogramLimitReached should be raised when Record(tags: "Color=green"), but TimeSeriesLimitReached should not be raised
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, 3, 2, "TestMeter17"))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
 
                 h.Record(5, new KeyValuePair<string, object?>("Color", "red"));
                 h.Record(6, new KeyValuePair<string, object?>("Color", "blue"));
                 h.Record(7, new KeyValuePair<string, object?>("Color", "green"));
                 h.Record(8, new KeyValuePair<string, object?>("Color", "yellow"));
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
 
                 h.Record(12, new KeyValuePair<string, object?>("Color", "red"));
                 h.Record(13, new KeyValuePair<string, object?>("Color", "blue"));
                 h.Record(14, new KeyValuePair<string, object?>("Color", "green"));
                 h.Record(15, new KeyValuePair<string, object?>("Color", "yellow"));
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
                 events = listener.Events.ToArray();
             }
 
@@ -1787,17 +1788,17 @@ public static IEnumerable<object[]> DifferentMetersAndInstrumentsData()
         [Theory]
         [OuterLoop("Slow and has lots of console spew")]
         [MemberData(nameof(DifferentMetersAndInstrumentsData))]
-        public void TestDifferentMetersAndInstruments(Counter<int> counter1, Counter<int> counter2, bool isSameCounters)
+        public async Task TestDifferentMetersAndInstruments(Counter<int> counter1, Counter<int> counter2, bool isSameCounters)
         {
             Assert.Equal(object.ReferenceEquals(counter1, counter2), isSameCounters);
 
             EventWrittenEventArgs[] events;
             using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, counter1.Meter.Name, counter2.Meter.Name))
             {
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
                 counter1.Add(1);
                 counter2.Add(1);
-                listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+                await listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
                 events = listener.Events.ToArray();
             }
 
@@ -2289,17 +2290,17 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData)
             _autoResetEvent.Set();
         }
 
-        public void WaitForCollectionStop(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "CollectionStop");
+        public Task WaitForCollectionStop(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "CollectionStop");
 
-        public void WaitForEndInstrumentReporting(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "EndInstrumentReporting");
+        public Task WaitForEndInstrumentReporting(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "EndInstrumentReporting");
 
-        public void WaitForEnumerationComplete(TimeSpan timeout) => WaitForEvent(timeout, 1, "InitialInstrumentEnumerationComplete");
+        public Task WaitForEnumerationComplete(TimeSpan timeout) => WaitForEvent(timeout, 1, "InitialInstrumentEnumerationComplete");
 
-        public void WaitForMultipleSessionsNotSupportedError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsNotSupportedError");
+        public Task WaitForMultipleSessionsNotSupportedError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsNotSupportedError");
 
-        public void WaitForMultipleSessionsConfiguredIncorrectlyError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsConfiguredIncorrectlyError");
+        public Task WaitForMultipleSessionsConfiguredIncorrectlyError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsConfiguredIncorrectlyError");
 
-        void WaitForEvent(TimeSpan timeout, int numEvents, string eventName)
+        async Task WaitForEvent(TimeSpan timeout, int numEvents, string eventName)
         {
             DateTime startTime = DateTime.Now;
             DateTime stopTime = startTime + timeout;
@@ -2311,12 +2312,22 @@ void WaitForEvent(TimeSpan timeout, int numEvents, string eventName)
                     return;
                 }
                 TimeSpan remainingTime = stopTime - DateTime.Now;
-                if (remainingTime.TotalMilliseconds < 0 || !_autoResetEvent.WaitOne(remainingTime))
+                if (remainingTime.TotalMilliseconds < 0)
                 {
                     int currentEventCount = GetCountEvents(eventName);
                     throw new TimeoutException($"Timed out waiting for a {eventName} event. " +
                         $"StartTime={startTime} stopTime={stopTime} initialEventCount={initialEventCount} currentEventCount={currentEventCount} targetEventCount={numEvents}");
                 }
+                if (OperatingSystem.IsBrowser())
+                {
+                    // in the single-threaded browser environment, we need to yield to the browser to allow the event to be processed
+                    // we also can't block with WaitOne
+                    await Task.Delay(10);
+                }
+                else
+                {
+                    _autoResetEvent.WaitOne(remainingTime);
+                }
             }
         }
 

From be60fbe942c66107a8dcd7f945363684cc8e0cbf Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Tue, 18 Mar 2025 11:48:48 +0100
Subject: [PATCH 11/28] fix

---
 .../tests/MetricEventSourceTests.cs                             | 2 ++
 .../tests/System.Diagnostics.DiagnosticSource.Tests.csproj      | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
index b52992065f8c95..3ec21cb3ef2fcf 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
@@ -2318,6 +2318,7 @@ async Task WaitForEvent(TimeSpan timeout, int numEvents, string eventName)
                     throw new TimeoutException($"Timed out waiting for a {eventName} event. " +
                         $"StartTime={startTime} stopTime={stopTime} initialEventCount={initialEventCount} currentEventCount={currentEventCount} targetEventCount={numEvents}");
                 }
+#if OS_ISBROWSER_SUPPORT
                 if (OperatingSystem.IsBrowser())
                 {
                     // in the single-threaded browser environment, we need to yield to the browser to allow the event to be processed
@@ -2325,6 +2326,7 @@ async Task WaitForEvent(TimeSpan timeout, int numEvents, string eventName)
                     await Task.Delay(10);
                 }
                 else
+#endif
                 {
                     _autoResetEvent.WaitOne(remainingTime);
                 }
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
index 507ec6840ccb64..7d5ba5cda7afce 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
@@ -12,7 +12,7 @@
 
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
   <PropertyGroup>
-    <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);MEMORYMARSHAL_SUPPORT</DefineConstants>
+    <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);MEMORYMARSHAL_SUPPORT;OS_ISBROWSER_SUPPORT</DefineConstants>
   </PropertyGroup>
 
   <ItemGroup>

From 963f14c81ed0bb80b84da5d282da4a67e581af7e Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Tue, 18 Mar 2025 12:25:28 +0100
Subject: [PATCH 12/28] fix

---
 .../tests/MetricEventSourceTests.cs                             | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
index 3ec21cb3ef2fcf..5bd05f39ec370e 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
@@ -2300,7 +2300,9 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData)
 
         public Task WaitForMultipleSessionsConfiguredIncorrectlyError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsConfiguredIncorrectlyError");
 
+#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
         async Task WaitForEvent(TimeSpan timeout, int numEvents, string eventName)
+#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
         {
             DateTime startTime = DateTime.Now;
             DateTime stopTime = startTime + timeout;

From 948f7f63d9b6da14003257670d82fc6fea925456 Mon Sep 17 00:00:00 2001
From: Pavel Savara <pavelsavara@microsoft.com>
Date: Tue, 18 Mar 2025 14:09:55 +0100
Subject: [PATCH 13/28] Update
 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs

Co-authored-by: Javier Calvarro Nelson <jacalvar@microsoft.com>
---
 .../System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
index f74c4da375499f..4f3c4bc2d57c63 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
@@ -42,7 +42,7 @@ private async Task DispatchEventsToEventListeners(ulong sessionID, DateTime sync
 
             // Wait for SignalSession() to be called before we call disable, otherwise
             // the SignalSession() call could be on a disabled session.
-            await Task.Delay(1, CancellationToken.None).ConfigureAwait(false);
+            await Task.Yield(CancellationToken.None).ConfigureAwait(false);
 
             EventPipeInternal.Disable(sessionID);
         }

From 84ec7ffc50cbc3f424952bbf25bfedf77907e1ed Mon Sep 17 00:00:00 2001
From: Pavel Savara <pavelsavara@microsoft.com>
Date: Tue, 18 Mar 2025 14:59:08 +0100
Subject: [PATCH 14/28] fix

---
 .../FunctionalTests/System.Net.Http.Functional.Tests.csproj     | 1 -
 .../System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index 1902d0e022306d..98c12eb362594b 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -51,7 +51,6 @@
     <NodeNpmModule Include="node-abort-controller" />
 
     <RuntimeHostConfigurationOption Include="System.Net.Http.EnableActivityPropagation" Value="true" Trim="true" />
-    <RuntimeHostConfigurationOption Include="System.Net.Http.EnableMetrics" Value="true" Trim="true" />
 
   </ItemGroup>
 
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
index 4f3c4bc2d57c63..d8f5fcbd2ce66e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
@@ -42,7 +42,7 @@ private async Task DispatchEventsToEventListeners(ulong sessionID, DateTime sync
 
             // Wait for SignalSession() to be called before we call disable, otherwise
             // the SignalSession() call could be on a disabled session.
-            await Task.Yield(CancellationToken.None).ConfigureAwait(false);
+            await Task.Yield().ConfigureAwait(false);
 
             EventPipeInternal.Disable(sessionID);
         }

From ff65c1f29bdcce053fa9035c8cb2f4d2651fb189 Mon Sep 17 00:00:00 2001
From: Pavel Savara <pavelsavara@microsoft.com>
Date: Tue, 18 Mar 2025 16:17:59 +0100
Subject: [PATCH 15/28] fix

---
 .../System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
index d8f5fcbd2ce66e..b9d9acb6db8b51 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs
@@ -42,7 +42,7 @@ private async Task DispatchEventsToEventListeners(ulong sessionID, DateTime sync
 
             // Wait for SignalSession() to be called before we call disable, otherwise
             // the SignalSession() call could be on a disabled session.
-            await Task.Yield().ConfigureAwait(false);
+            await Task.Yield();
 
             EventPipeInternal.Disable(sessionID);
         }

From 5003ac50c56bae49b0da442ded35613acdb20e8d Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Wed, 19 Mar 2025 12:12:00 +0100
Subject: [PATCH 16/28] feedback

- don't split System.Diagnostics.DiagnosticSource into separate platform DLL
- add comments for MetricsSupport and EventSourceSupport features in tests, make them global
---
 ...rosoft.Extensions.Diagnostics.Tests.csproj |   6 +-
 ...System.Diagnostics.DiagnosticSource.csproj |   7 +-
 .../Metrics/AggregationManager.Threads.cs     |  88 ------------
 .../Metrics/AggregationManager.Wasm.cs        |  70 ---------
 .../Diagnostics/Metrics/AggregationManager.cs | 135 ++++++++++++++++--
 ....Diagnostics.DiagnosticSource.Tests.csproj |   6 +-
 .../System.Diagnostics.Tracing.Tests.csproj   |   9 +-
 .../System.Net.Http.Functional.Tests.csproj   |  14 +-
 .../Tracing/CounterGroup.Threads.cs           |   1 -
 src/mono/browser/build/BrowserWasmApp.targets |   1 -
 src/mono/browser/runtime/diagnostics/index.ts |  10 +-
 11 files changed, 158 insertions(+), 189 deletions(-)
 delete mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
 delete mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs

diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
index d3a087bbf639c4..e1143d2ac6c85a 100644
--- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
+++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
@@ -5,8 +5,10 @@
     <EnableDefaultItems>true</EnableDefaultItems>
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
   </PropertyGroup>
-
-  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
+  <PropertyGroup>
+    <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
+    https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
+    -->
     <MetricsSupport>true</MetricsSupport>
     <EventSourceSupport>true</EventSourceSupport>
   </PropertyGroup>
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
index ff20bc31095ca0..177f33efb1ee3f 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum);$(NetCoreAppCurrent)-browser</TargetFrameworks>
+    <TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <NoWarn>$(NoWarn);SA1205</NoWarn>
     <EnableTrimAnalyzer Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">false</EnableTrimAnalyzer>
@@ -16,7 +16,6 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
 
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
   <PropertyGroup>
-    <TargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
     <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(DefineConstants);ENABLE_HTTP_HANDLER</DefineConstants>
     <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT</DefineConstants>
     <IncludePlatformAttributes>true</IncludePlatformAttributes>
@@ -58,8 +57,6 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
     <Compile Include="System\Diagnostics\PassThroughPropagator.cs" />
     <Compile Include="System\Diagnostics\RandomNumberGenerator.cs" />
     <Compile Include="System\Diagnostics\Metrics\AggregationManager.cs" />
-    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Threads.cs" Condition="('$(TargetPlatformIdentifier)' != 'wasi' and '$(TargetPlatformIdentifier)' != 'browser') or '$(FeatureWasmManagedThreads)' == 'true'" />
-    <Compile Include="System\Diagnostics\Metrics\AggregationManager.Wasm.cs" Condition="('$(TargetPlatformIdentifier)' == 'wasi' or '$(TargetPlatformIdentifier)' == 'browser') and '$(FeatureWasmManagedThreads)' != 'true'" />
     <Compile Include="System\Diagnostics\Metrics\Aggregator.cs" />
     <Compile Include="System\Diagnostics\Metrics\AggregatorStore.cs" />
     <Compile Include="System\Diagnostics\Metrics\Counter.cs" />
@@ -149,7 +146,7 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
     <Compile Include="System\Diagnostics\Metrics\RuntimeMetrics.cs" />
   </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)' or '$(TargetPlatformIdentifier)' == 'browser' or '$(TargetPlatformIdentifier)' == 'wasi'">
+  <ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'">
     <Reference Include="System.Collections" />
     <Reference Include="System.Collections.Concurrent" />
     <Reference Include="System.Diagnostics.Tracing" />
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
deleted file mode 100644
index ff6ac1b8774a33..00000000000000
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-﻿// 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.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.Versioning;
-using System.Security;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Diagnostics.Metrics
-{
-    internal sealed partial class AggregationManager
-    {
-        private Thread? _collectThread;
-
-        public void Start()
-        {
-            // if already started or already stopped we can't be started again
-            Debug.Assert(_collectThread == null && !_cts.IsCancellationRequested);
-            Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs);
-
-            // This explicitly uses a Thread and not a Task so that metrics still work
-            // even when an app is experiencing thread-pool starvation. Although we
-            // can't make in-proc metrics robust to everything, this is a common enough
-            // problem in .NET apps that it feels worthwhile to take the precaution.
-            _collectThread = new Thread(() => CollectWorker(_cts.Token));
-            _collectThread.IsBackground = true;
-            _collectThread.Name = "MetricsEventSource CollectWorker";
-#pragma warning disable CA1416 // 'Thread.Start' is unsupported on: 'browser', there the actual implementation is in AggregationManager.Wasm.cs
-            _collectThread.Start();
-#pragma warning restore CA1416
-
-            _listener.Start();
-            _initialInstrumentEnumerationComplete();
-        }
-
-        private void CollectWorker(CancellationToken cancelToken)
-        {
-            try
-            {
-                double collectionIntervalSecs = -1;
-                lock (this)
-                {
-                    collectionIntervalSecs = CollectionPeriod.TotalSeconds;
-                }
-                Debug.Assert(collectionIntervalSecs >= MinCollectionTimeSecs);
-
-                DateTime startTime = DateTime.UtcNow;
-                DateTime intervalStartTime = startTime;
-                while (!cancelToken.IsCancellationRequested)
-                {
-                    // pause until the interval is complete
-                    DateTime now = DateTime.UtcNow;
-                    DateTime nextIntervalStartTime = CalculateDelayTime(now, startTime, intervalStartTime, collectionIntervalSecs);
-                    TimeSpan delayTime = nextIntervalStartTime - now;
-                    if (cancelToken.WaitHandle.WaitOne(delayTime))
-                    {
-                        // don't do collection if timer may not have run to completion
-                        break;
-                    }
-
-                    // collect statistics for the completed interval
-                    _beginCollection(intervalStartTime, nextIntervalStartTime);
-                    Collect();
-                    _endCollection(intervalStartTime, nextIntervalStartTime);
-                    intervalStartTime = nextIntervalStartTime;
-                }
-            }
-            catch (Exception e)
-            {
-                _collectionError(e);
-            }
-        }
-
-        public void Dispose()
-        {
-            _cts.Cancel();
-            if (_collectThread != null)
-            {
-                _collectThread.Join();
-                _collectThread = null;
-            }
-            _listener.Dispose();
-        }
-    }
-}
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs
deleted file mode 100644
index 1344c381f79391..00000000000000
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-﻿// 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.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.Versioning;
-using System.Security;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Diagnostics.Metrics
-{
-    internal sealed partial class AggregationManager
-    {
-        private Timer? _pollingTimer;
-        private DateTime _startTime;
-        private DateTime _intervalStartTime;
-        private DateTime _nextIntervalStartTime;
-
-        public void Start()
-        {
-            // if already started or already stopped we can't be started again
-            Debug.Assert(_pollingTimer == null && !_cts.IsCancellationRequested);
-            Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs);
-
-            DateTime now = _startTime = _intervalStartTime  = DateTime.UtcNow;
-            _nextIntervalStartTime = CalculateDelayTime(now, _startTime, _intervalStartTime, CollectionPeriod.TotalSeconds);
-            TimeSpan delayTime = _nextIntervalStartTime - now;
-            _pollingTimer = new Timer(CollectOnce, null, (int)delayTime.TotalMilliseconds, 0);
-
-            _listener.Start();
-            _initialInstrumentEnumerationComplete();
-        }
-
-        private void CollectOnce(object? state)
-        {
-            try
-            {
-                if (_cts.Token.IsCancellationRequested)
-                {
-                    return;
-                }
-
-                // collect statistics for the completed interval
-                _beginCollection(_intervalStartTime, _nextIntervalStartTime);
-                Collect();
-                _endCollection(_intervalStartTime, _nextIntervalStartTime);
-
-                DateTime now = DateTime.UtcNow;
-                _nextIntervalStartTime = CalculateDelayTime(now, _startTime, _intervalStartTime, CollectionPeriod.TotalSeconds);
-                TimeSpan delayTime = _nextIntervalStartTime - now;
-                _intervalStartTime = _nextIntervalStartTime;
-                // schedule the next collection
-                _pollingTimer!.Change((int)delayTime.TotalMilliseconds, 0);
-            }
-            catch (Exception e)
-            {
-                _collectionError(e);
-            }
-        }
-
-        public void Dispose()
-        {
-            _cts.Cancel();
-            _pollingTimer?.Dispose();
-            _listener.Dispose();
-        }
-    }
-}
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
index 34678b5c68b62b..c66240c0809348 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
@@ -12,7 +12,7 @@
 namespace System.Diagnostics.Metrics
 {
     [SecuritySafeCritical]
-    internal sealed partial class AggregationManager
+    internal sealed class AggregationManager
     {
         public const double MinCollectionTimeSecs = 0.1;
         private static readonly QuantileAggregation s_defaultHistogramConfig = new QuantileAggregation(new double[] { 0.50, 0.95, 0.99 });
@@ -27,6 +27,8 @@ internal sealed partial class AggregationManager
         private Dictionary<Instrument, bool> _instruments = new();
         private readonly ConcurrentDictionary<Instrument, InstrumentState> _instrumentStates = new();
         private readonly CancellationTokenSource _cts = new();
+        private Thread? _collectThread;
+        private Timer? _pollingTimer;
         private readonly MeterListener _listener;
         private int _currentTimeSeries;
         private int _currentHistograms;
@@ -41,6 +43,9 @@ internal sealed partial class AggregationManager
         private readonly Action _timeSeriesLimitReached;
         private readonly Action _histogramLimitReached;
         private readonly Action<Exception> _observableInstrumentCallbackError;
+        private DateTime _startTime;
+        private DateTime _intervalStartTime;
+        private DateTime _nextIntervalStartTime;
 
         public AggregationManager(
             int maxTimeSeries,
@@ -152,6 +157,36 @@ private void PublishedInstrument(Instrument instrument, MeterListener _)
             }
         }
 
+        public void Start()
+        {
+            // if already started or already stopped we can't be started again
+            Debug.Assert(_collectThread == null && !_cts.IsCancellationRequested);
+            Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs);
+
+            _intervalStartTime = _nextIntervalStartTime = _startTime = DateTime.UtcNow;
+            if (OperatingSystem.IsBrowser())
+            {
+                TimeSpan delayTime = CalculateDelayTime(CollectionPeriod.TotalSeconds);
+                _pollingTimer = new Timer(CollectOnTimer, null, (int)delayTime.TotalMilliseconds, 0);
+            }
+            else
+            {
+                // This explicitly uses a Thread and not a Task so that metrics still work
+                // even when an app is experiencing thread-pool starvation. Although we
+                // can't make in-proc metrics robust to everything, this is a common enough
+                // problem in .NET apps that it feels worthwhile to take the precaution.
+                _collectThread = new Thread(CollectWorker);
+                _collectThread.IsBackground = true;
+                _collectThread.Name = "MetricsEventSource CollectWorker";
+    #pragma warning disable CA1416 // 'Thread.Start' is unsupported on: 'browser', there the actual implementation is in AggregationManager.Wasm.cs
+                _collectThread.Start();
+    #pragma warning restore CA1416
+
+            }
+            _listener.Start();
+            _initialInstrumentEnumerationComplete();
+        }
+
         public void Update()
         {
             // Creating (and destroying) a MeterListener to leverage the existing
@@ -165,17 +200,21 @@ public void Update()
 
             _initialInstrumentEnumerationComplete();
         }
-        private static DateTime CalculateDelayTime(DateTime now, DateTime startTime, DateTime intervalStartTime, double collectionIntervalSecs)
+
+        private TimeSpan CalculateDelayTime(double collectionIntervalSecs)
         {
+            _intervalStartTime = _nextIntervalStartTime;
+
             // intervals end at startTime + X*collectionIntervalSecs. Under normal
             // circumstance X increases by 1 each interval, but if the time it
             // takes to do collection is very large then we might need to skip
             // ahead multiple intervals to catch back up.
             //
-            double secsSinceStart = (now - startTime).TotalSeconds;
+            DateTime now = DateTime.UtcNow;
+            double secsSinceStart = (now - _startTime).TotalSeconds;
             double alignUpSecsSinceStart = Math.Ceiling(secsSinceStart / collectionIntervalSecs) *
                 collectionIntervalSecs;
-            DateTime nextIntervalStartTime = startTime.AddSeconds(alignUpSecsSinceStart);
+            _nextIntervalStartTime = _startTime.AddSeconds(alignUpSecsSinceStart);
 
             // The delay timer precision isn't exact. We might have a situation
             // where in the previous loop iterations intervalStartTime=20.00,
@@ -183,14 +222,94 @@ private static DateTime CalculateDelayTime(DateTime now, DateTime startTime, Dat
             // it exited early so we looped around and DateTime.Now=20.99.
             // Aligning up from DateTime.Now would give us 21.00 again so we also need to skip
             // forward one time interval
-            DateTime minNextInterval = intervalStartTime.AddSeconds(collectionIntervalSecs);
-            if (nextIntervalStartTime <= minNextInterval)
+            DateTime minNextInterval = _intervalStartTime.AddSeconds(collectionIntervalSecs);
+            if (_nextIntervalStartTime <= minNextInterval)
             {
-                nextIntervalStartTime = minNextInterval;
+                _nextIntervalStartTime = minNextInterval;
             }
-            return nextIntervalStartTime;
+            return _nextIntervalStartTime - now;
         }
 
+        private void CollectWorker()
+        {
+            try
+            {
+                double collectionIntervalSecs = -1;
+                CancellationToken cancelToken;
+                lock (this)
+                {
+                    collectionIntervalSecs = CollectionPeriod.TotalSeconds;
+                    cancelToken = _cts.Token;
+                }
+                Debug.Assert(collectionIntervalSecs >= MinCollectionTimeSecs);
+
+                DateTime startTime = DateTime.UtcNow;
+                DateTime intervalStartTime = startTime;
+                while (!_cts.Token.IsCancellationRequested)
+                {
+                    // pause until the interval is complete
+                    TimeSpan delayTime = CalculateDelayTime(collectionIntervalSecs);
+                    if (cancelToken.WaitHandle.WaitOne(delayTime))
+                    {
+                        // don't do collection if timer may not have run to completion
+                        break;
+                    }
+
+                    // collect statistics for the completed interval
+                    _beginCollection(_intervalStartTime, _nextIntervalStartTime);
+                    Collect();
+                    _endCollection(_intervalStartTime, _nextIntervalStartTime);
+                }
+            }
+            catch (Exception e)
+            {
+                _collectionError(e);
+            }
+        }
+
+        private void CollectOnTimer(object? _)
+        {
+            try
+            {
+                // this is single-threaded so we don't need to lock
+                CancellationToken cancelToken = _cts.Token;
+                double collectionIntervalSecs = CollectionPeriod.TotalSeconds;
+
+                if (cancelToken.IsCancellationRequested)
+                {
+                    return;
+                }
+
+                // collect statistics for the completed interval
+                _beginCollection(_intervalStartTime, _nextIntervalStartTime);
+                Collect();
+                _endCollection(_intervalStartTime, _nextIntervalStartTime);
+
+                TimeSpan delayTime = CalculateDelayTime(collectionIntervalSecs);
+                // schedule the next collection
+                _pollingTimer!.Change((int)delayTime.TotalMilliseconds, 0);
+            }
+            catch (Exception e)
+            {
+                _collectionError(e);
+            }
+        }
+
+        public void Dispose()
+        {
+            _cts.Cancel();
+            if (OperatingSystem.IsBrowser())
+            {
+                _pollingTimer?.Dispose();
+                _pollingTimer = null;
+            }
+            else
+            {
+                _collectThread?.Join();
+                _collectThread = null;
+            }
+            _listener.Dispose();
+        }
 
         private void RemoveInstrumentState(Instrument instrument)
         {
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
index 7d5ba5cda7afce..0f7ef438977ef6 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
@@ -4,8 +4,10 @@
     <TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkCurrent)</TargetFrameworks>
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
   </PropertyGroup>
-
-  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
+  <PropertyGroup>
+    <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
+    https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
+    -->
     <MetricsSupport>true</MetricsSupport>
     <EventSourceSupport>true</EventSourceSupport>
   </PropertyGroup>
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
index 181a855ebf9f21..e3dc180bd310f7 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
+++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
@@ -1,14 +1,19 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)</TargetFrameworks>
+    <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)</TargetFrameworks>
     <TestRuntime>true</TestRuntime>
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
     <TestDisableParallelization>true</TestDisableParallelization>
   </PropertyGroup>
-  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
+  <PropertyGroup>
+    <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
+    https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
+    -->
     <MetricsSupport>true</MetricsSupport>
     <EventSourceSupport>true</EventSourceSupport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
     <!-- this is necessary for libmono-component-diagnostics_tracing-static.a to be linked, which makes the EventPipeEventProvider.EventActivityIdControl to work in Mono -->
     <WasmPerfTracing>true</WasmPerfTracing>
   </PropertyGroup>
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index 98c12eb362594b..f3a6187970f5ee 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -9,7 +9,13 @@
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
     <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-osx</TargetFrameworks>
     <EnablePreviewFeatures>true</EnablePreviewFeatures>
-    <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
+  </PropertyGroup>
+  <PropertyGroup>
+    <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
+    https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
+    -->
+    <MetricsSupport>true</MetricsSupport>
+    <EventSourceSupport>true</EventSourceSupport>
   </PropertyGroup>
 
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
@@ -28,8 +34,6 @@
     <!-- This WASM test is slow on NodeJS. This sets the xharness timeout but there is also override in sendtohelix-browser.targets -->
     <WasmXHarnessTestsTimeout>01:15:00</WasmXHarnessTestsTimeout>
     <XunitShowProgress Condition="'$(FeatureWasmManagedThreads)' == 'true'">true</XunitShowProgress>
-    <EventSourceSupport>true</EventSourceSupport>
-    <MetricsSupport>true</MetricsSupport>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(TargetOS)' == 'wasi'">
@@ -50,12 +54,12 @@
     <NodeNpmModule Include="node-fetch" />
     <NodeNpmModule Include="node-abort-controller" />
 
-    <RuntimeHostConfigurationOption Include="System.Net.Http.EnableActivityPropagation" Value="true" Trim="true" />
-
   </ItemGroup>
 
   <ItemGroup>
     <TrimmerRootDescriptor Include="$(MSBuildThisFileDirectory)ILLink.Descriptor.xml" Condition="'$(TargetOS)' == 'browser' or '$(TargetOS)' == 'wasi'"/>
+
+    <RuntimeHostConfigurationOption Include="System.Net.Http.EnableActivityPropagation" Value="true" Trim="true" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
index a719bd04af2c44..618e1e6c3e353d 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
@@ -20,7 +20,6 @@ private static void CreatePollingTimer()
             {
                 s_pollingThreadSleepEvent = new AutoResetEvent(false);
                 s_counterGroupEnabledList = new List<CounterGroup>();
-                // TODO
                 s_pollingThread = new Thread(PollForValues)
                 {
                     IsBackground = true,
diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets
index ddd612cdbedbaf..20cb8cef23ec21 100644
--- a/src/mono/browser/build/BrowserWasmApp.targets
+++ b/src/mono/browser/build/BrowserWasmApp.targets
@@ -5,7 +5,6 @@
     <WasmEnableSIMD Condition="'$(WasmEnableSIMD)' == ''">$(WasmEnableExceptionHandling)</WasmEnableSIMD>
     <!-- we are not triggering WasmPerfTracing in Debug automatically, because it would trigger re-link, making dev-loop slow -->
     <WasmPerfTracing Condition="'$(WasmPerfTracing)' == ''">false</WasmPerfTracing>
-    <FeaturePerfTracing Condition="'$(FeaturePerfTracing)' == '' and '$(WasmPerfTracing)' == 'true'">true</FeaturePerfTracing>
   </PropertyGroup>
 
   <Import Project="$(WasmCommonTargetsPath)WasmApp.Common.targets" />
diff --git a/src/mono/browser/runtime/diagnostics/index.ts b/src/mono/browser/runtime/diagnostics/index.ts
index 97ed81eb0263b9..09c16da2d78959 100644
--- a/src/mono/browser/runtime/diagnostics/index.ts
+++ b/src/mono/browser/runtime/diagnostics/index.ts
@@ -11,27 +11,27 @@ export function setRuntimeGlobals (globalObjects: GlobalObjects): void {
     setRuntimeGlobalsImpl(globalObjects);
 
     diagnosticHelpers.ds_rt_websocket_create = (urlPtr :CharPtr):number => {
-        // Not implemented
+        // Not implemented yet
         return 1;
     };
 
     diagnosticHelpers.ds_rt_websocket_send = (client_socket :number, buffer:VoidPtr, bytes_to_write:number):number => {
-        // Not implemented
+        // Not implemented yet
         return bytes_to_write;
     };
 
     diagnosticHelpers.ds_rt_websocket_poll = (client_socket :number):number => {
-        // Not implemented
+        // Not implemented yet
         return 0;
     };
 
     diagnosticHelpers.ds_rt_websocket_recv = (client_socket :number, buffer:VoidPtr, bytes_to_read:number):number => {
-        // Not implemented
+        // Not implemented yet
         return 0;
     };
 
     diagnosticHelpers. ds_rt_websocket_close = (client_socket :number):number => {
-        // Not implemented
+        // Not implemented yet
         return 0;
     };
 }

From b059f30429f0a038366347e35d1d78d01226fec3 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Wed, 19 Mar 2025 12:48:48 +0100
Subject: [PATCH 17/28] feedbak - keep DiagnosticCounter not supported API

---
 .../System.Diagnostics.Tracing.Counters.cs    |  5 ++
 .../Diagnostics/Tracing/CounterGroup.cs       |  2 +
 .../Diagnostics/Tracing/DiagnosticCounter.cs  |  3 +
 .../Diagnostics/Tracing/EventCounter.cs       |  3 +
 .../Tracing/IncrementingEventCounter.cs       |  3 +
 .../Tracing/IncrementingPollingCounter.cs     |  3 +
 .../Diagnostics/Tracing/PollingCounter.cs     |  3 +
 .../Diagnostics/Tracing/RuntimeEventSource.cs |  2 +
 ...iCompatBaseline.NetCoreAppLatestStable.xml | 60 -------------------
 9 files changed, 24 insertions(+), 60 deletions(-)

diff --git a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs
index 2e1cce9f780a48..56c748f026e3e2 100644
--- a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs
+++ b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs
@@ -3,6 +3,7 @@
 
 namespace System.Diagnostics.Tracing
 {
+    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public abstract partial class DiagnosticCounter : System.IDisposable
     {
         internal DiagnosticCounter() { }
@@ -13,11 +14,13 @@ internal DiagnosticCounter() { }
         public void AddMetadata(string key, string? value) { }
         public void Dispose() { }
     }
+    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public partial class PollingCounter : System.Diagnostics.Tracing.DiagnosticCounter
     {
         public PollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func<double> metricProvider) { }
         public override string ToString() { throw null; }
     }
+    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public partial class IncrementingEventCounter : System.Diagnostics.Tracing.DiagnosticCounter
     {
         public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { }
@@ -25,12 +28,14 @@ public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSou
         public void Increment(double increment = 1) { }
         public override string ToString() { throw null; }
     }
+    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public partial class IncrementingPollingCounter : System.Diagnostics.Tracing.DiagnosticCounter
     {
         public IncrementingPollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func<double> totalValueProvider) { }
         public System.TimeSpan DisplayRateTimeScale { get { throw null; } set { } }
         public override string ToString() { throw null; }
     }
+    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
     public partial class EventCounter : System.Diagnostics.Tracing.DiagnosticCounter
     {
         public EventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { }
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
index d5a73b3ee40e67..a6541ee7ea5f46 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
@@ -5,6 +5,8 @@
 using System.Runtime.Versioning;
 using System.Threading;
 
+#pragma warning disable CA1416 // DiagnosticCounter is not supported public API on the browser OS
+
 namespace System.Diagnostics.Tracing
 {
     internal sealed partial class CounterGroup
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
index 62ae4beef3b2c3..0095e93ba4ae4c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
@@ -12,6 +12,9 @@ namespace System.Diagnostics.Tracing
     /// DiagnosticCounter is an abstract class that serves as the parent class for various Counter* classes,
     /// namely EventCounter, PollingCounter, IncrementingEventCounter, and IncrementingPollingCounter.
     /// </summary>
+#if !ES_BUILD_STANDALONE
+    [UnsupportedOSPlatform("browser")]
+#endif
     public abstract class DiagnosticCounter : IDisposable
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
index 790fda3af318c1..473ce079a23e10 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
@@ -16,6 +16,9 @@ namespace System.Diagnostics.Tracing
     /// See https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs
     /// which shows tests, which are also useful in seeing actual use.
     /// </summary>
+#if !ES_BUILD_STANDALONE
+    [UnsupportedOSPlatform("browser")]
+#endif
     public partial class EventCounter : DiagnosticCounter
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs
index 426b7df495a7dd..0b001e17c663a0 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs
@@ -12,6 +12,9 @@ namespace System.Diagnostics.Tracing
     /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates
     /// the counter value.
     /// </summary>
+#if !ES_BUILD_STANDALONE
+    [UnsupportedOSPlatform("browser")]
+#endif
     public partial class IncrementingEventCounter : DiagnosticCounter
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs
index 927f6df5816ed2..6c5bcec8e28ded 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs
@@ -14,6 +14,9 @@ namespace System.Diagnostics.Tracing
     /// Unlike IncrementingEventCounter, this takes in a polling callback that it can call to update
     /// its own metric periodically.
     /// </summary>
+#if !ES_BUILD_STANDALONE
+    [UnsupportedOSPlatform("browser")]
+#endif
     public partial class IncrementingPollingCounter : DiagnosticCounter
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs
index 87554db84f3696..4e9453a3a4aa88 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs
@@ -13,6 +13,9 @@ namespace System.Diagnostics.Tracing
     /// function to collect metrics on its own rather than the user having to call WriteMetric()
     /// every time.
     /// </summary>
+#if !ES_BUILD_STANDALONE
+    [UnsupportedOSPlatform("browser")]
+#endif
     public partial class PollingCounter : DiagnosticCounter
     {
         /// <summary>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
index da0a5e6e437b58..ab1341e70109f5 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
@@ -5,6 +5,8 @@
 using System.Runtime.CompilerServices;
 using System.Threading;
 
+#pragma warning disable CA1416 // DiagnosticCounter is not supported public API on the browser OS
+
 namespace System.Diagnostics.Tracing
 {
     /// <summary>
diff --git a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml
index 14f1bcb22eb092..1f33b65aeebd3f 100644
--- a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml
+++ b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml
@@ -331,64 +331,4 @@
     <Left>net9.0/System.Runtime.dll</Left>
     <Right>net10.0/System.Runtime.dll</Right>
   </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.DiagnosticCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/netstandard.dll</Left>
-    <Right>net10.0/netstandard.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.EventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/netstandard.dll</Left>
-    <Right>net10.0/netstandard.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.IncrementingEventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/netstandard.dll</Left>
-    <Right>net10.0/netstandard.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.IncrementingPollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/netstandard.dll</Left>
-    <Right>net10.0/netstandard.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.PollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/netstandard.dll</Left>
-    <Right>net10.0/netstandard.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.DiagnosticCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
-    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.EventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
-    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.IncrementingEventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
-    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.IncrementingPollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
-    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
-  </Suppression>
-  <Suppression>
-    <DiagnosticId>CP0014</DiagnosticId>
-    <Target>T:System.Diagnostics.Tracing.PollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute]</Target>
-    <Left>net9.0/System.Diagnostics.Tracing.dll</Left>
-    <Right>net10.0/System.Diagnostics.Tracing.dll</Right>
-  </Suppression>
 </Suppressions>
\ No newline at end of file

From 48be8994108fb0c859c305a8702667aa14cd1c6d Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Wed, 19 Mar 2025 13:00:15 +0100
Subject: [PATCH 18/28] more

---
 .../tests/Microsoft.Extensions.Diagnostics.Tests.csproj        | 2 +-
 .../tests/System.Diagnostics.DiagnosticSource.Tests.csproj     | 2 +-
 .../tests/System.Diagnostics.Tracing.Tests.csproj              | 2 +-
 .../FunctionalTests/System.Net.Http.Functional.Tests.csproj    | 2 +-
 src/mono/wasm/build/WasmApp.Common.targets                     | 3 +++
 5 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
index e1143d2ac6c85a..30220f55c4a2cc 100644
--- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
+++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
@@ -10,7 +10,7 @@
     https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
     -->
     <MetricsSupport>true</MetricsSupport>
-    <EventSourceSupport>true</EventSourceSupport>
+    <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
index 0f7ef438977ef6..d610db5cf933ef 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
@@ -9,7 +9,7 @@
     https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
     -->
     <MetricsSupport>true</MetricsSupport>
-    <EventSourceSupport>true</EventSourceSupport>
+    <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
   </PropertyGroup>
 
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
index e3dc180bd310f7..05ce16f4350ab3 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
+++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
@@ -11,7 +11,7 @@
     https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
     -->
     <MetricsSupport>true</MetricsSupport>
-    <EventSourceSupport>true</EventSourceSupport>
+    <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
   </PropertyGroup>
   <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
     <!-- this is necessary for libmono-component-diagnostics_tracing-static.a to be linked, which makes the EventPipeEventProvider.EventActivityIdControl to work in Mono -->
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index f3a6187970f5ee..22f90ee20ad48d 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -15,7 +15,7 @@
     https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
     -->
     <MetricsSupport>true</MetricsSupport>
-    <EventSourceSupport>true</EventSourceSupport>
+    <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
   </PropertyGroup>
 
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
diff --git a/src/mono/wasm/build/WasmApp.Common.targets b/src/mono/wasm/build/WasmApp.Common.targets
index 84c034605a9ffd..c1f76d7d9e0f11 100644
--- a/src/mono/wasm/build/WasmApp.Common.targets
+++ b/src/mono/wasm/build/WasmApp.Common.targets
@@ -258,6 +258,9 @@
     <_MonoComponent Include="debugger" />
     <_MonoComponent Include="hot_reload" />
   </ItemGroup>
+  <ItemGroup Condition="'$(WasmPerfTracing)' == 'true'">
+    <_MonoComponent Include="diagnostics_tracing" />
+  </ItemGroup>
   <!-- PUBLISH -->
 
   <!-- public top-level target for Build -->

From c97ce30b0fd2ce264a54ed57e6f38dcac30a6454 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Wed, 19 Mar 2025 13:58:05 +0100
Subject: [PATCH 19/28] fix

---
 .../src/System.Diagnostics.DiagnosticSource.csproj            | 2 +-
 .../src/System/Diagnostics/Metrics/AggregationManager.cs      | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
index 177f33efb1ee3f..68082e5a183c94 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
@@ -17,7 +17,7 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
   <PropertyGroup>
     <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(DefineConstants);ENABLE_HTTP_HANDLER</DefineConstants>
-    <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT</DefineConstants>
+    <DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT;OS_ISBROWSER_SUPPORT</DefineConstants>
     <IncludePlatformAttributes>true</IncludePlatformAttributes>
     <!-- TODO: Add package README file: https://github.com/dotnet/runtime/issues/99358 -->
     <EnableDefaultPackageReadmeFile>false</EnableDefaultPackageReadmeFile>
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
index c66240c0809348..c56c38cbef5987 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
@@ -164,12 +164,14 @@ public void Start()
             Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs);
 
             _intervalStartTime = _nextIntervalStartTime = _startTime = DateTime.UtcNow;
+#if OS_ISBROWSER_SUPPORT
             if (OperatingSystem.IsBrowser())
             {
                 TimeSpan delayTime = CalculateDelayTime(CollectionPeriod.TotalSeconds);
                 _pollingTimer = new Timer(CollectOnTimer, null, (int)delayTime.TotalMilliseconds, 0);
             }
             else
+#endif
             {
                 // This explicitly uses a Thread and not a Task so that metrics still work
                 // even when an app is experiencing thread-pool starvation. Although we
@@ -298,12 +300,14 @@ private void CollectOnTimer(object? _)
         public void Dispose()
         {
             _cts.Cancel();
+#if OS_ISBROWSER_SUPPORT
             if (OperatingSystem.IsBrowser())
             {
                 _pollingTimer?.Dispose();
                 _pollingTimer = null;
             }
             else
+#endif
             {
                 _collectThread?.Join();
                 _collectThread = null;

From ea727417a85c674c5c53f9a8010a618fb1f8cfa3 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Wed, 19 Mar 2025 14:19:06 +0100
Subject: [PATCH 20/28] fix

---
 .../src/System/Diagnostics/Metrics/AggregationManager.cs        | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
index c56c38cbef5987..036d2aa5c21650 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
@@ -28,7 +28,9 @@ internal sealed class AggregationManager
         private readonly ConcurrentDictionary<Instrument, InstrumentState> _instrumentStates = new();
         private readonly CancellationTokenSource _cts = new();
         private Thread? _collectThread;
+#if OS_ISBROWSER_SUPPORT
         private Timer? _pollingTimer;
+#endif
         private readonly MeterListener _listener;
         private int _currentTimeSeries;
         private int _currentHistograms;

From d1d4f273252538d05d82e5d515d2d451efc771f2 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Wed, 19 Mar 2025 14:53:29 +0100
Subject: [PATCH 21/28] fix

---
 .../src/System/Diagnostics/Metrics/AggregationManager.cs        | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
index 036d2aa5c21650..e64844875c6c4d 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
@@ -271,6 +271,7 @@ private void CollectWorker()
             }
         }
 
+#if OS_ISBROWSER_SUPPORT
         private void CollectOnTimer(object? _)
         {
             try
@@ -298,6 +299,7 @@ private void CollectOnTimer(object? _)
                 _collectionError(e);
             }
         }
+#endif
 
         public void Dispose()
         {

From f242d64eb3cfc9542623cab3fdfe35ea7c619a2c Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Wed, 19 Mar 2025 18:00:02 +0100
Subject: [PATCH 22/28] fix

---
 .../Microsoft.Extensions.Diagnostics.Tests.csproj      |  5 ++---
 .../System.Diagnostics.DiagnosticSource.Tests.csproj   |  5 ++---
 .../tests/System.Diagnostics.Tracing.Tests.csproj      |  7 -------
 .../System.Net.Http.Functional.Tests.csproj            | 10 ++++------
 4 files changed, 8 insertions(+), 19 deletions(-)

diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
index 30220f55c4a2cc..c9ab6a8751cd9e 100644
--- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
+++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj
@@ -1,16 +1,15 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkMinimum)</TargetFrameworks>
+    <TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppCurrent)-browser;$(NetFrameworkMinimum)</TargetFrameworks>
     <EnableDefaultItems>true</EnableDefaultItems>
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
   </PropertyGroup>
-  <PropertyGroup>
+  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
     <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
     https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
     -->
     <MetricsSupport>true</MetricsSupport>
-    <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
index d610db5cf933ef..4d134fb2c41fe3 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj
@@ -1,15 +1,14 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkCurrent)</TargetFrameworks>
+    <TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppCurrent)-browser;$(NetFrameworkCurrent)</TargetFrameworks>
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
   </PropertyGroup>
-  <PropertyGroup>
+  <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
     <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
     https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
     -->
     <MetricsSupport>true</MetricsSupport>
-    <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
   </PropertyGroup>
 
   <!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
index 05ce16f4350ab3..7f4870678636e6 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
+++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
@@ -6,13 +6,6 @@
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
     <TestDisableParallelization>true</TestDisableParallelization>
   </PropertyGroup>
-  <PropertyGroup>
-    <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
-    https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
-    -->
-    <MetricsSupport>true</MetricsSupport>
-    <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
-  </PropertyGroup>
   <PropertyGroup Condition="'$(TargetOS)' == 'browser'">
     <!-- this is necessary for libmono-component-diagnostics_tracing-static.a to be linked, which makes the EventPipeEventProvider.EventActivityIdControl to work in Mono -->
     <WasmPerfTracing>true</WasmPerfTracing>
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index 22f90ee20ad48d..defc1a687c6f5f 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -9,12 +9,6 @@
     <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
     <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-osx</TargetFrameworks>
     <EnablePreviewFeatures>true</EnablePreviewFeatures>
-  </PropertyGroup>
-  <PropertyGroup>
-    <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
-    https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
-    -->
-    <MetricsSupport>true</MetricsSupport>
     <EventSourceSupport Condition="'$(TestNativeAot)' == 'true'">true</EventSourceSupport>
   </PropertyGroup>
 
@@ -34,6 +28,10 @@
     <!-- This WASM test is slow on NodeJS. This sets the xharness timeout but there is also override in sendtohelix-browser.targets -->
     <WasmXHarnessTestsTimeout>01:15:00</WasmXHarnessTestsTimeout>
     <XunitShowProgress Condition="'$(FeatureWasmManagedThreads)' == 'true'">true</XunitShowProgress>
+    <!-- Enable diagnostic features. They will add appropriate RuntimeHostConfigurationOption values to runtime config and ILLink.
+    https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features 
+    -->
+    <MetricsSupport>true</MetricsSupport>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(TargetOS)' == 'wasi'">

From f4cb8649d341e1aa1f2078962cd383325ca4131b Mon Sep 17 00:00:00 2001
From: Pavel Savara <pavelsavara@microsoft.com>
Date: Wed, 19 Mar 2025 20:47:04 +0100
Subject: [PATCH 23/28] fix

---
 .../FunctionalTests/System.Net.Http.Functional.Tests.csproj     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index defc1a687c6f5f..340819fc688edb 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -57,7 +57,7 @@
   <ItemGroup>
     <TrimmerRootDescriptor Include="$(MSBuildThisFileDirectory)ILLink.Descriptor.xml" Condition="'$(TargetOS)' == 'browser' or '$(TargetOS)' == 'wasi'"/>
 
-    <RuntimeHostConfigurationOption Include="System.Net.Http.EnableActivityPropagation" Value="true" Trim="true" />
+    <RuntimeHostConfigurationOption Include="System.Net.Http.EnableActivityPropagation" Value="true" Trim="true" Condition="'$(TargetOS)' == 'browser'" />
   </ItemGroup>
 
   <ItemGroup>

From 52daddc3f0b43f4c5af440152aa57f2aaf3e5c4c Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Thu, 20 Mar 2025 09:41:19 +0100
Subject: [PATCH 24/28] feedback

---
 .../System.Private.CoreLib.Shared.projitems   |  4 +-
 .../src/System/AppContext.AnyOS.cs            |  2 +-
 .../Tracing/CounterGroup.Threads.cs           | 53 -------------------
 .../Diagnostics/Tracing/CounterGroup.Wasm.cs  | 34 ------------
 .../Diagnostics/Tracing/CounterGroup.cs       | 43 ++++++++++++---
 .../System/Diagnostics/Tracing/EventSource.cs |  2 +
 .../Diagnostics/Tracing/RuntimeEventSource.cs |  5 +-
 7 files changed, 42 insertions(+), 101 deletions(-)
 delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
 delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs

diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index ae0325a504c31d..d6ec12abecca60 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -1548,8 +1548,6 @@
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\ActivityTracker.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\DiagnosticCounter.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\CounterGroup.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\CounterGroup.Threads.cs" Condition="('$(TargetsWasi)' != 'true' and '$(TargetsBrowser)' != 'true') or '$(FeatureWasmManagedThreads)' == 'true'" />
-    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\CounterGroup.Wasm.cs" Condition="('$(TargetsWasi)' == 'true' or '$(TargetsBrowser)' == 'true') and '$(FeatureWasmManagedThreads)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\CounterPayload.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventActivityOptions.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventCounter.cs" />
@@ -1573,7 +1571,7 @@
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\NativeRuntimeEventSource.Threading.NativeSinks.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\NativeRuntimeEventSource.Threading.NativeSinks.Internal.cs" Condition="'$(FeaturePerfTracing)' == 'true' and '$(FeatureMono)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\PollingCounter.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\RuntimeEventSource.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\RuntimeEventSource.cs" Condition="'$(FeaturePerfTracing)' == 'true' and '$(TargetsBrowser)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\Winmeta.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\ArrayTypeInfo.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\ConcurrentSet.cs" />
diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
index b2c83e67dd4538..1450dff2f683d7 100644
--- a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
@@ -36,7 +36,7 @@ private static string GetBaseDirectoryCore()
         }
 #endif
 
-#if FEATURE_PERFTRACING
+#if FEATURE_PERFTRACING && !TARGET_BROWSER && !TARGET_WASI
         internal static void LogSwitchValues(RuntimeEventSource ev)
         {
             if (s_switches is not null)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
deleted file mode 100644
index 618e1e6c3e353d..00000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.Runtime.Versioning;
-using System.Threading;
-
-namespace System.Diagnostics.Tracing
-{
-    internal sealed partial class CounterGroup
-    {
-        private static Thread? s_pollingThread;
-        // Used for sleeping for a certain amount of time while allowing the thread to be woken up
-        private static AutoResetEvent? s_pollingThreadSleepEvent;
-
-        private static void CreatePollingTimer()
-        {
-            // Create the polling thread and init all the shared state if needed
-            if (s_pollingThread == null)
-            {
-                s_pollingThreadSleepEvent = new AutoResetEvent(false);
-                s_counterGroupEnabledList = new List<CounterGroup>();
-                s_pollingThread = new Thread(PollForValues)
-                {
-                    IsBackground = true,
-                    Name = ".NET Counter Poller"
-                };
-                s_pollingThread.Start();
-            }
-            else
-            {
-                // notify the polling thread that the polling interval may have changed and the sleep should be recomputed
-                s_pollingThreadSleepEvent!.Set();
-            }
-        }
-
-        private static void PollForValues()
-        {
-            AutoResetEvent? sleepEvent = null;
-            lock (s_counterGroupLock)
-            {
-                sleepEvent = s_pollingThreadSleepEvent;
-            }
-
-            while (true)
-            {
-                var sleepDurationInMilliseconds = PollOnce();
-
-                sleepEvent?.WaitOne(sleepDurationInMilliseconds);
-            }
-        }
-    }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs
deleted file mode 100644
index 2f9a0acb6788e8..00000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.Runtime.Versioning;
-using System.Threading;
-
-namespace System.Diagnostics.Tracing
-{
-    internal sealed partial class CounterGroup
-    {
-        private static Timer? s_pollingTimer;
-
-        private static void CreatePollingTimer()
-        {
-            if (s_pollingTimer == null)
-            {
-                s_pollingTimer = new Timer(PollForValues, null, 0, 0);
-                s_counterGroupEnabledList = new List<CounterGroup>();
-            }
-            else
-            {
-                // notify the polling callback that the polling interval may have changed and the sleep should be recomputed
-                s_pollingTimer.Change(0, 0);
-            }
-        }
-
-        private static void PollForValues(object? state)
-        {
-            var sleepDurationInMilliseconds = PollOnce();
-            s_pollingTimer!.Change(sleepDurationInMilliseconds, 0);
-        }
-    }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
index a6541ee7ea5f46..d08c6949616c10 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
@@ -5,11 +5,12 @@
 using System.Runtime.Versioning;
 using System.Threading;
 
-#pragma warning disable CA1416 // DiagnosticCounter is not supported public API on the browser OS
-
 namespace System.Diagnostics.Tracing
 {
-    internal sealed partial class CounterGroup
+#if !ES_BUILD_STANDALONE
+    [UnsupportedOSPlatform("browser")]
+#endif
+    internal sealed class CounterGroup
     {
         private readonly EventSource _eventSource;
         private readonly List<DiagnosticCounter> _counters;
@@ -158,12 +159,27 @@ private void EnableTimer(float pollingIntervalInSeconds)
                 _timeStampSinceCollectionStarted = DateTime.UtcNow;
                 _nextPollingTimeStamp = DateTime.UtcNow + new TimeSpan(0, 0, (int)pollingIntervalInSeconds);
 
-                CreatePollingTimer();
+                // Create the polling thread and init all the shared state if needed
+                if (s_pollingThread == null)
+                {
+                    s_pollingThreadSleepEvent = new AutoResetEvent(false);
+                    s_counterGroupEnabledList = new List<CounterGroup>();
+                    s_pollingThread = new Thread(PollForValues)
+                    {
+                        IsBackground = true,
+                        Name = ".NET Counter Poller"
+                    };
+                    s_pollingThread.Start();
+                }
 
                 if (!s_counterGroupEnabledList!.Contains(this))
                 {
                     s_counterGroupEnabledList.Add(this);
                 }
+
+                // notify the polling thread that the polling interval may have changed and the sleep should
+                // be recomputed
+                s_pollingThreadSleepEvent!.Set();
             }
         }
 
@@ -251,21 +267,29 @@ private void OnTimer()
             }
         }
 
+        private static Thread? s_pollingThread;
+        // Used for sleeping for a certain amount of time while allowing the thread to be woken up
+        private static AutoResetEvent? s_pollingThreadSleepEvent;
+
         private static List<CounterGroup>? s_counterGroupEnabledList;
         private static List<IncrementingPollingCounter> s_needsResetIncrementingPollingCounters = [];
 
-        private static int PollOnce()
+        private static void PollForValues()
         {
+            AutoResetEvent? sleepEvent = null;
+
             // Cache of onTimer callbacks for each CounterGroup.
             // We cache these outside of the scope of s_counterGroupLock because
             // calling into the callbacks can cause a re-entrancy into CounterGroup.Enable()
             // and result in a deadlock. (See https://github.com/dotnet/runtime/issues/40190 for details)
             var onTimers = new List<CounterGroup>();
             List<IncrementingPollingCounter>? countersToReset = null;
-
+            while (true)
+            {
                 int sleepDurationInMilliseconds = int.MaxValue;
                 lock (s_counterGroupLock)
                 {
+                    sleepEvent = s_pollingThreadSleepEvent;
                     foreach (CounterGroup counterGroup in s_counterGroupEnabledList!)
                     {
                         DateTime now = DateTime.UtcNow;
@@ -292,6 +316,8 @@ private static int PollOnce()
                     {
                         counter.UpdateMetric();
                     }
+
+                    countersToReset = null;
                 }
 
                 foreach (CounterGroup onTimer in onTimers)
@@ -303,9 +329,10 @@ private static int PollOnce()
                 {
                     sleepDurationInMilliseconds = -1; // WaitOne uses -1 to mean infinite
                 }
-
-            return sleepDurationInMilliseconds;
+                sleepEvent?.WaitOne(sleepDurationInMilliseconds);
+            }
         }
+
 #endregion // Timer Processing
 
     }
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
index f8f07adc304417..d2811be57d5427 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
@@ -3888,7 +3888,9 @@ internal static void InitializeDefaultEventSources()
 // it to mean other aspects of tracing such as these EventSources.
 #if FEATURE_PERFTRACING
             _ = NativeRuntimeEventSource.Log;
+#if !TARGET_BROWSER && !TARGET_WASI
             _ = RuntimeEventSource.Log;
+#endif
 #endif
             // System.Diagnostics.MetricsEventSource allows listening to Meters and indirectly
             // also creates the System.Runtime Meter.
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
index ab1341e70109f5..cb3f45c2092c69 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
@@ -5,8 +5,6 @@
 using System.Runtime.CompilerServices;
 using System.Threading;
 
-#pragma warning disable CA1416 // DiagnosticCounter is not supported public API on the browser OS
-
 namespace System.Diagnostics.Tracing
 {
     /// <summary>
@@ -14,6 +12,9 @@ namespace System.Diagnostics.Tracing
     /// </summary>
     [EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = EventSourceName)]
     [EventSourceAutoGenerate]
+#if !ES_BUILD_STANDALONE
+    [UnsupportedOSPlatform("browser")]
+#endif
     internal sealed partial class RuntimeEventSource : EventSource
     {
         internal static readonly Guid EventSourceGuid = new Guid("49592C0F-5A05-516D-AA4B-A64E02026C89");

From 149746b517c7c80e66bd907c89cb9ebec31c88e7 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Thu, 20 Mar 2025 10:21:53 +0100
Subject: [PATCH 25/28] fix

---
 .../src/System/Diagnostics/Tracing/RuntimeEventSource.cs       | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
index cb3f45c2092c69..da0a5e6e437b58 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
@@ -12,9 +12,6 @@ namespace System.Diagnostics.Tracing
     /// </summary>
     [EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = EventSourceName)]
     [EventSourceAutoGenerate]
-#if !ES_BUILD_STANDALONE
-    [UnsupportedOSPlatform("browser")]
-#endif
     internal sealed partial class RuntimeEventSource : EventSource
     {
         internal static readonly Guid EventSourceGuid = new Guid("49592C0F-5A05-516D-AA4B-A64E02026C89");

From 4c4ef09c438481fe6594c0c2a7f9607ca45d0c70 Mon Sep 17 00:00:00 2001
From: Pavel Savara <pavelsavara@microsoft.com>
Date: Thu, 20 Mar 2025 10:51:53 +0100
Subject: [PATCH 26/28] just browser

---
 .../System.Private.CoreLib/src/System/AppContext.AnyOS.cs       | 2 +-
 .../src/System/Diagnostics/Tracing/EventSource.cs               | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
index 1450dff2f683d7..c71c5c95c9e3c5 100644
--- a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
@@ -36,7 +36,7 @@ private static string GetBaseDirectoryCore()
         }
 #endif
 
-#if FEATURE_PERFTRACING && !TARGET_BROWSER && !TARGET_WASI
+#if FEATURE_PERFTRACING && !TARGET_BROWSER
         internal static void LogSwitchValues(RuntimeEventSource ev)
         {
             if (s_switches is not null)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
index d2811be57d5427..0d5178bda06a1c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
@@ -3888,7 +3888,7 @@ internal static void InitializeDefaultEventSources()
 // it to mean other aspects of tracing such as these EventSources.
 #if FEATURE_PERFTRACING
             _ = NativeRuntimeEventSource.Log;
-#if !TARGET_BROWSER && !TARGET_WASI
+#if !TARGET_BROWSER
             _ = RuntimeEventSource.Log;
 #endif
 #endif

From 6fb21e99078f2b58df2c07deac3126033a19e140 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Fri, 21 Mar 2025 11:53:10 +0100
Subject: [PATCH 27/28] disable
 RequestDuration_EnrichmentHandler_ContentLengthError_Recorded for firefox

---
 .../Common/tests/TestUtilities/System/PlatformDetection.cs     | 1 +
 .../System.Net.Http/tests/FunctionalTests/MetricsTest.cs       | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
index fb6d6ddb0e990e..6bd64bdf84fd09 100644
--- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
@@ -163,6 +163,7 @@ private static bool ComputeIsLinqSizeOptimized()
         public static bool IsFirefox => IsEnvironmentVariableTrue("IsFirefox");
         public static bool IsChromium => IsEnvironmentVariableTrue("IsChromium");
         public static bool IsNotNodeJS => !IsNodeJS;
+        public static bool IsNotNodeJSOrFirefox => !IsNodeJS && !IsFirefox;
         public static bool IsNodeJSOnWindows => GetNodeJSPlatform() == "win32";
         public static bool LocalEchoServerIsNotAvailable => !LocalEchoServerIsAvailable;
         public static bool LocalEchoServerIsAvailable => IsBrowser;
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
index 8a2e1fde4e4f75..929d79dedd1202 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
@@ -34,6 +34,7 @@ protected static void VerifyTag<T>(IEnumerable<KeyValuePair<string, object?>> ta
             }
             else
             {
+                Assert.True(tags.Any(t => t.Key == name), $"Tag {name} not found in tags.");
                 object? actualValue = tags.Single(t => t.Key == name).Value;
                 Assert.Equal(value, (T)actualValue);
             }
@@ -936,7 +937,7 @@ public HttpMetricsTest_Http11(ITestOutputHelper output) : base(output)
         {
         }
 
-        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNodeJS))]
+        [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNodeJSOrFirefox))]
         public async Task RequestDuration_EnrichmentHandler_ContentLengthError_Recorded()
         {
             await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>

From 57c9692821d60f195e66915fdca293fceb452470 Mon Sep 17 00:00:00 2001
From: pavelsavara <pavel.savara@gmail.com>
Date: Fri, 21 Mar 2025 14:20:41 +0100
Subject: [PATCH 28/28] RequestDuration_Success_Recorded not firefox

---
 .../System.Net.Http/tests/FunctionalTests/MetricsTest.cs        | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
index 929d79dedd1202..d68a95e0c6a23d 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs
@@ -345,7 +345,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
             });
         }
 
-        [Theory]
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNodeJSOrFirefox))]
         [InlineData("GET", HttpStatusCode.OK)]
         [InlineData("PUT", HttpStatusCode.Created)]
         public Task RequestDuration_Success_Recorded(string method, HttpStatusCode statusCode)
