Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using System.IO;
using System.Reflection;

Expand Down Expand Up @@ -30,5 +33,52 @@ private static string GetBaseDirectoryCore()

return directory;
}

internal static void LogSwitchValues(RuntimeEventSource ev)
{
if (s_switches is not null)
{
lock (s_switches)
{
foreach (KeyValuePair<string, bool> kvp in s_switches)
{
// Convert bool to int because it's cheaper to log (no boxing)
ev.LogAppContextSwitch(kvp.Key, kvp.Value ? 1 : 0);
}
}
}

if (s_dataStore is not null)
{
lock (s_dataStore)
{
if (s_switches is not null)
{
lock (s_switches)
{
LogDataStore(ev, s_switches);
}
}
else
{
LogDataStore(ev, null);
}

static void LogDataStore(RuntimeEventSource ev, Dictionary<string, bool>? switches)
{
Debug.Assert(s_dataStore is not null);
foreach (KeyValuePair<string, object?> kvp in s_dataStore)
{
if (kvp.Value is string s &&
bool.TryParse(s, out bool isEnabled) &&
switches?.ContainsKey(kvp.Key) != true)
{
ev.LogAppContextSwitch(kvp.Key, isEnabled ? 1 : 0);
}
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ internal sealed partial class RuntimeEventSource : EventSource
{
internal const string EventSourceName = "System.Runtime";

public static class Keywords
{
public const EventKeywords AppContext = (EventKeywords)0x1;
}

private static RuntimeEventSource? s_RuntimeEventSource;
private PollingCounter? _gcHeapSizeCounter;
private IncrementingPollingCounter? _gen0GCCounter;
Expand Down Expand Up @@ -50,6 +55,17 @@ public static void Initialize()
// as you can't make a constructor partial.
private RuntimeEventSource(int _) { }

private enum EventId : int
{
AppContextSwitch = 1
}

[Event((int)EventId.AppContextSwitch, Level = EventLevel.Informational, Keywords = Keywords.AppContext)]
internal void LogAppContextSwitch(string switchName, int value)
{
base.WriteEvent((int)EventId.AppContextSwitch, switchName, value);
}

protected override void OnEventCommand(EventCommandEventArgs command)
{
if (command.Command == EventCommand.Enable)
Expand Down Expand Up @@ -87,6 +103,8 @@ protected override void OnEventCommand(EventCommandEventArgs command)
_ilBytesJittedCounter ??= new PollingCounter("il-bytes-jitted", this, () => System.Runtime.JitInfo.GetCompiledILBytes()) { DisplayName = "IL Bytes Jitted", DisplayUnits = "B" };
_methodsJittedCounter ??= new PollingCounter("methods-jitted-count", this, () => System.Runtime.JitInfo.GetCompiledMethodCount()) { DisplayName = "Number of Methods Jitted" };
_jitTimeCounter ??= new IncrementingPollingCounter("time-in-jit", this, () => System.Runtime.JitInfo.GetCompilationTime().TotalMilliseconds) { DisplayName = "Time spent in JIT", DisplayUnits = "ms", DisplayRateTimeScale = new TimeSpan(0, 0, 1) };

AppContext.LogSwitchValues(this);
}

}
Expand Down
6 changes: 4 additions & 2 deletions src/tests/tracing/eventcounter/runtimecounters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ protected override void OnEventSourceCreated(EventSource source)
{
Dictionary<string, string> refreshInterval = new Dictionary<string, string>();
refreshInterval.Add("EventCounterIntervalSec", "1");
EnableEvents(source, EventLevel.Informational, (EventKeywords)(-1), refreshInterval);
EnableEvents(source, EventLevel.Informational,
(EventKeywords)(-1 & (~1 /* RuntimeEventSource.Keywords.AppContext */)),
refreshInterval);
}
}

Expand Down Expand Up @@ -100,7 +102,7 @@ public static int Main(string[] args)
// Create an EventListener.
using (RuntimeCounterListener myListener = new RuntimeCounterListener())
{
Thread.Sleep(3000);
Thread.Sleep(3000);
if (myListener.Verify())
{
Console.WriteLine("Test passed");
Expand Down
114 changes: 114 additions & 0 deletions src/tests/tracing/runtimeeventsource/NativeRuntimeEventSourceTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using System.Diagnostics.Tracing;
using System.Runtime.CompilerServices;
using System.Threading;
using Tracing.Tests.Common;

namespace Tracing.Tests
{
public sealed class NativeRuntimeEventSourceTest
{
static int Main(string[] args)
{
SimpleEventListener.EnableKeywords = (EventKeywords)0;
using (SimpleEventListener noEventsListener = new SimpleEventListener("NoEvents"))
{
// Create an EventListener.
SimpleEventListener.EnableKeywords = (EventKeywords)0x4c14fccbd;
using (SimpleEventListener listener = new SimpleEventListener("Simple"))
{
// Trigger the allocator task.
System.Threading.Tasks.Task.Run(new Action(Allocator));

// Wait for events.
Thread.Sleep(1000);

// Generate some GC events.
GC.Collect(2, GCCollectionMode.Forced);

// Wait for more events.
Thread.Sleep(1000);

// Ensure that we've seen some events.
Assert.True("listener.EventCount > 0", listener.EventCount > 0);
}

// Generate some more GC events.
GC.Collect(2, GCCollectionMode.Forced);

// Ensure that we've seen no events.
Assert.True("noEventsListener.EventCount == 0", noEventsListener.EventCount == 0);
}

return 100;
}

private static void Allocator()
{
while (true)
{
for(int i=0; i<1000; i++)
GC.KeepAlive(new object());

Thread.Sleep(10);
}
}
}

internal sealed class SimpleEventListener : EventListener
{
private string m_name;

// Keep track of the set of keywords to be enabled.
public static EventKeywords EnableKeywords
{
get;
set;
}

public SimpleEventListener(string name)
{
m_name = name;
}

public int EventCount { get; private set; } = 0;

protected override void OnEventSourceCreated(EventSource eventSource)
{
if (eventSource.Name.Equals("Microsoft-Windows-DotNETRuntime"))
{
if (EnableKeywords != 0)
{
// Enable events.
EnableEvents(eventSource, EventLevel.Verbose, EnableKeywords);
}
else
{
// Enable the provider, but not any keywords, so we should get no events as long as no rundown occurs.
EnableEvents(eventSource, EventLevel.Critical, EnableKeywords);
}
}
}

protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
Console.WriteLine($"[{m_name}] ThreadID = {eventData.OSThreadId} ID = {eventData.EventId} Name = {eventData.EventName}");
Console.WriteLine($"TimeStamp: {eventData.TimeStamp.ToLocalTime()}");
Console.WriteLine($"LocalTime: {DateTime.Now}");
Console.WriteLine($"Difference: {DateTime.UtcNow - eventData.TimeStamp}");
Assert.True("eventData.TimeStamp <= DateTime.UtcNow", eventData.TimeStamp <= DateTime.UtcNow);
for (int i = 0; i < eventData.Payload.Count; i++)
{
string payloadString = eventData.Payload[i] != null ? eventData.Payload[i].ToString() : string.Empty;
Console.WriteLine($"\tName = \"{eventData.PayloadNames[i]}\" Value = \"{payloadString}\"");
}
Console.WriteLine("\n");

EventCount++;
}
}
}
Loading