This commit updates logging to handle nullable value types and parameters. The following changes were made: - Updated the Value record to use '!' instead of '?' for nullability. - Added '!' to the default Value. - Added '!= null' checks to conditional assignment. - Removed unnecessary nullable-disable compiler directives.
163 lines
4.3 KiB
C#
163 lines
4.3 KiB
C#
using Microsoft.Diagnostics.Tracing.Session;
|
|
using ProfilerHelpers;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Tracing
|
|
{
|
|
static class Program
|
|
{
|
|
|
|
|
|
static public int CreateTracingSession( bool noSampling, bool sortBySize, int topTypesLimit )
|
|
{
|
|
ShowHeader();
|
|
|
|
try
|
|
{
|
|
|
|
TraceEventSession session = new TraceEventSession(
|
|
"Tracing",
|
|
TraceEventSessionOptions.Create
|
|
);
|
|
|
|
log.info( $"Create PerProcessProfilingState" );
|
|
|
|
using( var processes = new PerProcessProfilingState() )
|
|
{
|
|
log.info( $"Create Memory profiler for session" );
|
|
var profiler = new Memory( session, processes );
|
|
|
|
log.info( $"Start task" );
|
|
var task = profiler.StartAsync( noSampling );
|
|
|
|
/*
|
|
log.info( $"await the Continue" );
|
|
await task.ContinueWith( ( t ) => {
|
|
log.info( $"Task is done, Dispose" );
|
|
session.Dispose();
|
|
} );
|
|
*/
|
|
|
|
//log.info("Press ENTER to stop memory profiling");
|
|
//Console.ReadLine();
|
|
|
|
/*
|
|
try
|
|
{
|
|
await task;
|
|
ShowResults( processes, sortBySize, topTypesLimit );
|
|
|
|
return 0;
|
|
}
|
|
catch( Exception x )
|
|
{
|
|
log.info( x.Message );
|
|
ShowHelp();
|
|
}
|
|
*/
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
catch( Exception x )
|
|
{
|
|
log.info( x.Message );
|
|
ShowHelp();
|
|
}
|
|
|
|
return -2;
|
|
}
|
|
|
|
private static void ShowResults( PerProcessProfilingState processes, bool sortBySize, int topTypesLimit )
|
|
{
|
|
foreach( var pid in processes.Allocations.Keys )
|
|
{
|
|
// skip processes without symbol resolution
|
|
if( !processes.Methods.ContainsKey( pid ) )
|
|
continue;
|
|
|
|
// skip processes without allocations
|
|
if( !processes.Allocations[pid].GetAllAllocations().Any() )
|
|
continue;
|
|
|
|
ShowResults( GetProcessName( pid, processes.Names ), processes.Methods[pid], processes.Allocations[pid], sortBySize, topTypesLimit );
|
|
}
|
|
}
|
|
|
|
private static string GetProcessName( int pid, Dictionary<int, string> names )
|
|
{
|
|
if( names.TryGetValue( pid, out var name ) )
|
|
return name;
|
|
|
|
return pid.ToString();
|
|
}
|
|
|
|
private static void ShowResults( string name, MethodStore methods, ProcessAllocations allocations, bool sortBySize, int topTypesLimit )
|
|
{
|
|
log.info( $"Memory allocations for {name}" );
|
|
log.info( $"" );
|
|
log.info( "---------------------------------------------------------" );
|
|
log.info( " Count Size Type" );
|
|
log.info( "---------------------------------------------------------" );
|
|
IEnumerable<AllocationInfo> types = ( sortBySize )
|
|
? allocations.GetAllAllocations().OrderByDescending( a => a.Size )
|
|
: allocations.GetAllAllocations().OrderByDescending( a => a.Count )
|
|
;
|
|
if( topTypesLimit != -1 )
|
|
types = types.Take( topTypesLimit );
|
|
|
|
foreach( var allocation in types )
|
|
{
|
|
log.info( $"{allocation.Count,9} {allocation.Size,11} {allocation.TypeName}" );
|
|
|
|
log.info( $"" );
|
|
DumpStacks( allocation, methods );
|
|
log.info( $"" );
|
|
}
|
|
log.info( $"" );
|
|
log.info( $"" );
|
|
}
|
|
|
|
private static void DumpStacks( AllocationInfo allocation, MethodStore methods )
|
|
{
|
|
var stacks = allocation.Stacks.OrderByDescending( s => s.Count ).Take( 10 );
|
|
foreach( var stack in stacks )
|
|
{
|
|
log.info( $"{stack.Count,6} allocations" );
|
|
log.info( "----------------------------------" );
|
|
DumpStack( stack.Stack, methods );
|
|
log.info( $"" );
|
|
}
|
|
}
|
|
|
|
private static void DumpStack( AddressStack stack, MethodStore methods )
|
|
{
|
|
var callstack = stack.Stack;
|
|
for( int i = 0; i < Math.Min( 10, callstack.Count ); i++ )
|
|
{
|
|
log.info( $" {methods.GetFullName( callstack[i] )}" );
|
|
}
|
|
}
|
|
|
|
private static void ShowHeader()
|
|
{
|
|
log.info( "Tracing v1.0.0 - Sampled memory profiler for .NET applications" );
|
|
log.info( "by Christophe Nasarre" );
|
|
log.info( $"" );
|
|
}
|
|
private static void ShowHelp()
|
|
{
|
|
log.info( $"" );
|
|
log.info( "Tracing shows sampled allocations of a given .NET application." );
|
|
log.info( "Usage: Tracing [-a (all allocations)] [-c (sort by count instead of default by size)] [-t <type count (instead of 3 types by default)>]" );
|
|
log.info( " Ex: Tracing -t -1 (all types sampled allocations sorted by size)" );
|
|
log.info( " Ex: Tracing -c -t 10 (allocations for top 10 types sorted by count)" );
|
|
log.info( $"" );
|
|
}
|
|
}
|
|
}
|