// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Internal.Runtime.CompilerServices;
namespace System.Diagnostics.Tracing
{
[EventSource(Guid = "8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1", Name = "System.Diagnostics.Eventing.FrameworkEventSource")]
internal sealed class FrameworkEventSource : EventSource
{
public static readonly FrameworkEventSource Log = new FrameworkEventSource();
// Keyword definitions. These represent logical groups of events that can be turned on and off independently
// Often each task has a keyword, but where tasks are determined by subsystem, keywords are determined by
// usefulness to end users to filter. Generally users don't mind extra events if they are not high volume
// so grouping low volume events together in a single keywords is OK (users can post-filter by task if desired)
public static class Keywords
{
public const EventKeywords ThreadPool = (EventKeywords)0x0002;
public const EventKeywords ThreadTransfer = (EventKeywords)0x0010;
}
/// ETW tasks that have start/stop events.
public static class Tasks // this name is important for EventSource
{
/// Send / Receive - begin transfer/end transfer
public const EventTask ThreadTransfer = (EventTask)3;
}
// The FrameworkEventSource GUID is {8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1}
private FrameworkEventSource() : base(new Guid(0x8e9f5090, 0x2d75, 0x4d03, 0x8a, 0x81, 0xe5, 0xaf, 0xbf, 0x85, 0xda, 0xf1), "System.Diagnostics.Eventing.FrameworkEventSource") { }
// optimized for common signatures (used by the ThreadTransferSend/Receive events)
[NonEvent]
private unsafe void WriteEvent(int eventId, long arg1, int arg2, string? arg3, bool arg4, int arg5, int arg6)
{
if (IsEnabled())
{
arg3 ??= "";
fixed (char* string3Bytes = arg3)
{
EventSource.EventData* descrs = stackalloc EventSource.EventData[6];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 8;
descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 4;
descrs[1].Reserved = 0;
descrs[2].DataPointer = (IntPtr)string3Bytes;
descrs[2].Size = ((arg3.Length + 1) * 2);
descrs[2].Reserved = 0;
descrs[3].DataPointer = (IntPtr)(&arg4);
descrs[3].Size = 4;
descrs[3].Reserved = 0;
descrs[4].DataPointer = (IntPtr)(&arg5);
descrs[4].Size = 4;
descrs[4].Reserved = 0;
descrs[5].DataPointer = (IntPtr)(&arg6);
descrs[5].Size = 4;
descrs[5].Reserved = 0;
WriteEventCore(eventId, 6, descrs);
}
}
}
// optimized for common signatures (used by the ThreadTransferSend/Receive events)
[NonEvent]
private unsafe void WriteEvent(int eventId, long arg1, int arg2, string? arg3)
{
if (IsEnabled())
{
arg3 ??= "";
fixed (char* string3Bytes = arg3)
{
EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 8;
descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 4;
descrs[1].Reserved = 0;
descrs[2].DataPointer = (IntPtr)string3Bytes;
descrs[2].Size = ((arg3.Length + 1) * 2);
descrs[2].Reserved = 0;
WriteEventCore(eventId, 3, descrs);
}
}
}
[Event(30, Level = EventLevel.Verbose, Keywords = Keywords.ThreadPool | Keywords.ThreadTransfer)]
public void ThreadPoolEnqueueWork(long workID)
{
WriteEvent(30, workID);
}
[NonEvent]
public unsafe void ThreadPoolEnqueueWorkObject(object workID)
{
// convert the Object Id to a long
ThreadPoolEnqueueWork((long)*((void**)Unsafe.AsPointer(ref workID)));
}
[Event(31, Level = EventLevel.Verbose, Keywords = Keywords.ThreadPool | Keywords.ThreadTransfer)]
public void ThreadPoolDequeueWork(long workID)
{
WriteEvent(31, workID);
}
[NonEvent]
public unsafe void ThreadPoolDequeueWorkObject(object workID)
{
// convert the Object Id to a long
ThreadPoolDequeueWork((long)*((void**)Unsafe.AsPointer(ref workID)));
}
// id - represents a correlation ID that allows correlation of two activities, one stamped by
// ThreadTransferSend, the other by ThreadTransferReceive
// kind - identifies the transfer: values below 64 are reserved for the runtime. Currently used values:
// 1 - managed Timers ("roaming" ID)
// 2 - managed async IO operations (FileStream, PipeStream, a.o.)
// 3 - WinRT dispatch operations
// info - any additional information user code might consider interesting
// intInfo1/2 - any additional integer information user code might consider interesting
[Event(150, Level = EventLevel.Informational, Keywords = Keywords.ThreadTransfer, Task = Tasks.ThreadTransfer, Opcode = EventOpcode.Send)]
public void ThreadTransferSend(long id, int kind, string info, bool multiDequeues, int intInfo1, int intInfo2)
{
WriteEvent(150, id, kind, info, multiDequeues, intInfo1, intInfo2);
}
// id - is a managed object. it gets translated to the object's address. ETW listeners must
// keep track of GC movements in order to correlate the value passed to XyzSend with the
// (possibly changed) value passed to XyzReceive
[NonEvent]
public unsafe void ThreadTransferSendObj(object id, int kind, string info, bool multiDequeues, int intInfo1, int intInfo2)
{
ThreadTransferSend((long)*((void**)Unsafe.AsPointer(ref id)), kind, info, multiDequeues, intInfo1, intInfo2);
}
// id - represents a correlation ID that allows correlation of two activities, one stamped by
// ThreadTransferSend, the other by ThreadTransferReceive
// kind - identifies the transfer: values below 64 are reserved for the runtime. Currently used values:
// 1 - managed Timers ("roaming" ID)
// 2 - managed async IO operations (FileStream, PipeStream, a.o.)
// 3 - WinRT dispatch operations
// info - any additional information user code might consider interesting
[Event(151, Level = EventLevel.Informational, Keywords = Keywords.ThreadTransfer, Task = Tasks.ThreadTransfer, Opcode = EventOpcode.Receive)]
public void ThreadTransferReceive(long id, int kind, string? info)
{
WriteEvent(151, id, kind, info);
}
// id - is a managed object. it gets translated to the object's address. ETW listeners must
// keep track of GC movements in order to correlate the value passed to XyzSend with the
// (possibly changed) value passed to XyzReceive
[NonEvent]
public unsafe void ThreadTransferReceiveObj(object id, int kind, string? info)
{
ThreadTransferReceive((long)*((void**)Unsafe.AsPointer(ref id)), kind, info);
}
}
}