x) Add new logging events for GC and ThreadPoolWorkerThread x) Implement method to extract method information from TraceEvent x) Enhance log details display for specific event types x) Improve time header format in log messages x) Refactor verbose logging messages to include type friendly names
235 lines
7.8 KiB
C#
235 lines
7.8 KiB
C#
using Microsoft.Diagnostics.NETCore.Client;
|
|
using Microsoft.Diagnostics.Tracing;
|
|
using Microsoft.Diagnostics.Tracing.Etlx;
|
|
using Microsoft.Diagnostics.Tracing.EventPipe;
|
|
using Microsoft.Diagnostics.Tracing.Parsers;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Diagnostics.Tracing;
|
|
using System.Text;
|
|
using TraceKeywords = Microsoft.Diagnostics.Tracing.Parsers.ClrTraceEventParser.Keywords;
|
|
|
|
|
|
public class RuntimeGCEventsPrinter
|
|
{
|
|
static ImmutableHashSet<string> blacklist;
|
|
static ImmutableHashSet<string> stacklist;
|
|
|
|
static RuntimeGCEventsPrinter()
|
|
{
|
|
blacklist = ImmutableHashSet.Create(
|
|
"Method/ILToNativeMap",
|
|
"GC/BulkMovedObjectRanges",
|
|
"GC/BulkSurvivingObjectRanges",
|
|
"GC/FinalizeObject",
|
|
"Type/BulkType",
|
|
"GC/SetGCHandle",
|
|
"GC/DestoryGCHandle",
|
|
"TypeLoad/Start",
|
|
"Method/R2RGetEntryPointStart",
|
|
"Method/MethodDetails",
|
|
"Method/MemoryAllocatedForJitCode",
|
|
"Method/JittingStarted",
|
|
"GC/BulkRootStaticVar",
|
|
"GC/BulkNode",
|
|
"GC/BulkEdge",
|
|
"GC/BulkRootEdge",
|
|
"ThreadPoolWorkerThread/Wait",
|
|
"ILStub/StubGenerated"
|
|
|
|
);
|
|
stacklist = ImmutableHashSet.Create( "{TEST_ITEM}" );
|
|
|
|
log.logEndpointForCategory( "Method/MemoryAllocatedForJitCode", log.Endpoints.File );
|
|
log.logEndpointForCategory( "TypeLoad/Stop", log.Endpoints.File );
|
|
log.logEndpointForCategory( "GC/BulkRootStaticVar", log.Endpoints.File );
|
|
log.logEndpointForCategory( "GC/BulkNode", log.Endpoints.File );
|
|
log.logEndpointForCategory( "GC/BulkRootStaticVar", log.Endpoints.File );
|
|
|
|
}
|
|
|
|
public static string MethodInfo( TraceEvent te, string prefix = "Method" )
|
|
{
|
|
return $"{te.PayloadStringByName($"{prefix}Namespace")}.{te.PayloadStringByName($"{prefix}Name")}{te.PayloadStringByName($"{prefix}Signature")}";
|
|
}
|
|
|
|
public static Action<TraceEvent> LogCategoryFunc( string catIn )
|
|
{
|
|
return ( TraceEvent te ) =>
|
|
{
|
|
var cat = catIn;
|
|
|
|
if( blacklist.Contains( te.EventName )) return;
|
|
|
|
{
|
|
var methodBeingCompiledNamespace = te.PayloadStringByName("MethodBeingCompiledNamespace") ?? "";
|
|
if( ( methodBeingCompiledNamespace.StartsWith( "Microsoft" ) || methodBeingCompiledNamespace.StartsWith( "System" ) ) ) return;
|
|
}
|
|
|
|
{
|
|
var methodNamespace = te.PayloadStringByName("MethodNamespace") ?? "";
|
|
if( ( methodNamespace.StartsWith( "Microsoft" ) || methodNamespace.StartsWith( "System" ) ) ) return;
|
|
}
|
|
|
|
{
|
|
var ns = te.PayloadStringByName("TypeName") ?? "";
|
|
if( ( ns.StartsWith( "Microsoft" ) || ns.StartsWith( "System" ) ) ) return;
|
|
}
|
|
|
|
|
|
{
|
|
var ns = te.PayloadStringByName("TypeLoad/Stop") ?? "";
|
|
if( ns.StartsWith( "Godot" ) ) return;
|
|
}
|
|
|
|
{
|
|
var payloadIndex = te.PayloadIndex( "count" );
|
|
|
|
if( payloadIndex > 0 )
|
|
{
|
|
var count = (int)te.PayloadValue( payloadIndex );
|
|
if( count > 16 ) return;
|
|
}
|
|
}
|
|
|
|
//<Event EventName="Method/JittingStarted" MethodILSize="0x00000059" MethodNamespace="NilEvent" MethodName="DebugString" MethodSignature="instance class System.String ()" ClrInstanceID="0"/>
|
|
//<Event EventName="Method/LoadVerbose" MethodStartAddress="0x00000003045736B8" MethodSize="0x000001BC" MethodToken="0x060001BB" MethodFlags="Jitted" MethodNamespace="NilEvent" MethodName="DebugString" MethodSignature="instance class System.String ()" ClrInstanceID="0" ReJITID="0x00000000" OptimizationTier="MinOptJitted"/>
|
|
|
|
//<Event EventName="Method/InliningFailed" MethodBeingCompiledNamespace="dynamicClass" MethodBeingCompiledName="InvokeStub_EventAttribute.set_Message" MethodBeingCompiledNameSignature="class System.Object (class System.Object,class System.Object,int*)" InlinerNamespace="dynamicClass" InlinerName="InvokeStub_EventAttribute.set_Message" InlinerNameSignature="class System.Object (class System.Object,class System.Object,int*)" InlineeNamespace="System.Diagnostics.Tracing.EventAttribute" InlineeName="set_Message" InlineeNameSignature="instance void (class System.String)" FailAlways="False" FailReason="uses NextCallReturnAddress intrinsic" ClrInstanceID="0"/>
|
|
|
|
if( !te.EventName.StartsWith( "EventID") )
|
|
{
|
|
var logDetails = "";
|
|
// Custom event displays
|
|
if( te.EventName == "Method/LoadVerbose" )
|
|
{
|
|
log.info( $"{te.PayloadStringByName("OptimizationTier")} {MethodInfo(te)}", cat: te.EventName );
|
|
return;
|
|
//logDetails = "| Details: ";
|
|
}
|
|
else if( te.EventName.StartsWith( "Method/Inlining" ) )
|
|
{
|
|
log.info( $"Inlining {te.PayloadStringByName("FailReason")} {te.PayloadStringByName("OptimizationTier")} {MethodInfo(te, "MethodBeingCompiled")}", cat: te.EventName );
|
|
return;
|
|
//logDetails = "| Details: ";
|
|
}
|
|
else if( te.EventName == "TypeLoad/Stop" )
|
|
{
|
|
var typeName = te.PayloadStringByName("TypeName");
|
|
if( typeName.StartsWith( "Godot." ) ) return;
|
|
|
|
log.info( $"{typeName} Level: {te.PayloadStringByName("LoadLevel")}", cat: te.EventName );
|
|
return;
|
|
//logDetails = "| Details: ";
|
|
}
|
|
else if( te.EventName.StartsWith( "Method/R2RGetEntryPoint" ) )
|
|
{
|
|
log.info( $"{MethodInfo(te)} Entry: {te.PayloadStringByName("EntryPoint")}", cat: te.EventName );
|
|
return;
|
|
//logDetails = "| Details: ";
|
|
}
|
|
|
|
//76 CHARACTERS
|
|
//<Event MSec= "180.2315" PID="35297" PName="Process(35297)" TID="294046"
|
|
|
|
var teStr = te.ToString().Replace("ClrInstanceID=\"0\"", "" );
|
|
|
|
var teStrSlice = teStr.AsSpan( 74, teStr.Length - (74 + 1 + 1) );
|
|
|
|
log.debug( $"{logDetails}{teStrSlice}", cat: te.EventName );
|
|
|
|
|
|
|
|
/*
|
|
if( eventData.Length > 0 )
|
|
{
|
|
Encoding enc = new UnicodeEncoding(false, false, true);
|
|
var eventDataUtf16 = enc.GetString( eventData );
|
|
log.debug( $"> {eventDataUtf16}" );
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
var payloadNames = te.PayloadNames;
|
|
var channel = te.Channel;
|
|
var formattedMsg = te.FormattedMessage;
|
|
var keywords = te.Keywords;
|
|
var source = te.Source;
|
|
var dump = te.Dump();
|
|
var dynMemberNames = te.GetDynamicMemberNames();
|
|
var dataStart = te.DataStart;
|
|
*/
|
|
|
|
var eventData = te.EventData();
|
|
|
|
//var eventDataStr = eventData.ToString();
|
|
|
|
Encoding enc = new UnicodeEncoding(false, false, true);
|
|
var eventDataUtf16 = enc.GetString( eventData );
|
|
//var safeEventData = eventDataUtf16.Replace( (char)0, '\n' );
|
|
|
|
var arrEventData = eventDataUtf16.Split( (char)0 );
|
|
var joinedEventData = string.Join( " | ", arrEventData );
|
|
|
|
//log.info( $"{te.FormattedMessage}", cat: catIn );
|
|
log.info( $"{joinedEventData}", cat: catIn );
|
|
}
|
|
|
|
|
|
};
|
|
}
|
|
|
|
|
|
public static void PrintRuntimeGCEvents( int processId )
|
|
{
|
|
var providers = new List<EventPipeProvider>()
|
|
{
|
|
new EventPipeProvider("Microsoft-Windows-DotNETRuntime",
|
|
EventLevel.Verbose, (long)(
|
|
TraceKeywords.GC |
|
|
TraceKeywords.Contention |
|
|
TraceKeywords.Debugger |
|
|
TraceKeywords.Exception |
|
|
TraceKeywords.GCAllObjectAllocation |
|
|
TraceKeywords.GCSampledObjectAllocationHigh |
|
|
TraceKeywords.GCSampledObjectAllocationLow |
|
|
TraceKeywords.Security |
|
|
TraceKeywords.Threading |
|
|
TraceKeywords.Type |
|
|
TraceKeywords.TypeDiagnostic |
|
|
TraceKeywords.WaitHandle |
|
|
TraceKeywords.All
|
|
) )
|
|
};
|
|
|
|
var client = new DiagnosticsClient( processId );
|
|
using( EventPipeSession session = client.StartEventPipeSession( providers, false ) )
|
|
{
|
|
var source = new EventPipeEventSource( session.EventStream );
|
|
|
|
|
|
|
|
source.Clr.All += LogCategoryFunc( "clr" );
|
|
|
|
source.Kernel.All += LogCategoryFunc( "kernel" );
|
|
|
|
// Doesnt seem to be too interesting.
|
|
//source.Dynamic.All += LogCategoryFunc( "dynamic" );
|
|
|
|
|
|
try
|
|
{
|
|
source.Process();
|
|
}
|
|
catch( Exception e )
|
|
{
|
|
Console.WriteLine( "Error encountered while processing events" );
|
|
Console.WriteLine( e.ToString() );
|
|
}
|
|
}
|
|
}
|
|
}
|