RSCG – Silhouette
| name | Silhouette |
| nuget | https://www.nuget.org/packages/Silhouette/ |
| link | https://github.com/kevingosse/Silhouette |
| author | Kevin Gosse |
Profiling .net applications
Measuring performance improvements
This is how you can use Silhouette .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Silhouette" Version="3.2.0" />
</ItemGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
</Project>
The code that you will use is
// See https://andrewlock.net/creating-a-dotnet-profiler-using-csharp-with-silhouette/
Console.WriteLine("Please read https://andrewlock.net/creating-a-dotnet-profiler-using-csharp-with-silhouette/");
using Silhouette;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace ProfilerDemo;
[Profiler("8AD62131-BF21-47C1-A4D4-3AEF5D7C75C6")]
internal class MyProfiler : CorProfilerCallback5Base
{
protected override HResult Initialize(int iCorProfilerInfoVersion)
{
Console.WriteLine("[SilhouetteProf] Initialize");
if (iCorProfilerInfoVersion < 5)
{
// we need at least ICorProfilerInfo5 and we got < 5
return HResult.E_FAIL;
}
// Call SetEventMask to tell the .NET runtime which events we're interested in
return ICorProfilerInfo5.SetEventMask(COR_PRF_MONITOR.COR_PRF_MONITOR_ALL);
}
protected override HResult ClassLoadStarted(ClassId classId)
{
try
{
ClassIdInfo classIdInfo = ICorProfilerInfo.GetClassIdInfo(classId).ThrowIfFailed();
using ComPtr<IMetaDataImport>? metaDataImport = ICorProfilerInfo2
.GetModuleMetaDataImport(classIdInfo.ModuleId, CorOpenFlags.ofRead)
.ThrowIfFailed()
.Wrap();
TypeDefPropsWithName classProps = metaDataImport.Value.GetTypeDefProps(classIdInfo.TypeDef).ThrowIfFailed();
Console.WriteLine($"[SilhouetteProf] ClassLoadStarted: {classProps.TypeName}");
return HResult.S_OK;
}
catch (Win32Exception ex)
{
Console.WriteLine($"[SilhouetteProf] ClassLoadStarted failed: {ex}");
return ex.NativeErrorCode;
}
}
protected override HResult Shutdown()
{
Console.WriteLine("[SilhouetteProf] Shutdown");
return HResult.S_OK;
}
}
The code that is generated is
namespace Silhouette._Generated
{
using System;
using System.Runtime.InteropServices;
file static class DllMain
{
[UnmanagedCallersOnly(EntryPoint = "DllGetClassObject")]
public static unsafe HResult DllGetClassObject(Guid* rclsid, Guid* riid, nint* ppv)
{
if (*rclsid != new Guid("8ad62131-bf21-47c1-a4d4-3aef5d7c75c6"))
{
return HResult.CORPROF_E_PROFILER_CANCEL_ACTIVATION;
}
*ppv = ClassFactory.For(new global::ProfilerDemo.MyProfiler());
return HResult.S_OK;
}
}
}
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/Silhouette