Skip to content

Instantly share code, notes, and snippets.

@filipnavara
Created April 30, 2024 12:38
Show Gist options
  • Save filipnavara/7bf3791fb795266fe46f4383a075423c to your computer and use it in GitHub Desktop.
Save filipnavara/7bf3791fb795266fe46f4383a075423c to your computer and use it in GitHub Desktop.
// dotnet counters monitor -n sslcounter Crypto.Memory
using System.Diagnostics.Tracing;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
CryptoMemoryTracker.Initialize();
Console.WriteLine("Ready");
for (;;)
{
var rsa = RSA.Create(4096);
rsa.ExportRSAPublicKey();
Console.WriteLine($"Memory usage: {CryptoMemoryTracker.TotalMemory}");
Thread.Sleep(1000);
rsa.Dispose();
}
[EventSource(Name = SourceName)]
unsafe class CryptoMemoryTracker : EventSource
{
const string SourceName = "Crypto.Memory";
static CryptoMemoryTracker? instance = null!;
static long totalMemory;
PollingCounter? cryptoMemoryCounter;
[DllImport("ssl", EntryPoint = "CRYPTO_set_mem_functions")]
static extern int CRYPTO_set_mem_functions(delegate* unmanaged<nuint, char*, int, void*> mallocFunction, delegate* unmanaged<void*, nuint, char*, int, void*> reallocFunction, delegate* unmanaged<void*, void> freeFunction);
public static long TotalMemory => totalMemory;
private CryptoMemoryTracker()
: base(SourceName, EventSourceSettings.EtwSelfDescribingEventFormat)
{
int res = CRYPTO_set_mem_functions(&CryptoMalloc, &CryptoRealloc, &CryptoFree);
if (res == 1)
{
totalMemory = 0;
cryptoMemoryCounter = new PollingCounter(
"crypto-memory",
this,
() => totalMemory)
{
DisplayName = "Crypto Heap Size",
};
}
}
public static void Initialize()
{
instance = new();
}
[UnmanagedCallersOnly]
internal static void* CryptoMalloc(nuint size, char* file, int line)
{
void* ptr = NativeMemory.Alloc(size + (nuint)sizeof(AllocationHeader));
if (ptr is null)
return null;
AllocationHeader* header = (AllocationHeader*)ptr;
header->Size = size;
Interlocked.Add(ref totalMemory, (nint)size);
return (void*)((nuint)ptr + (nuint)sizeof(AllocationHeader));
}
[UnmanagedCallersOnly]
internal static void* CryptoRealloc(void* oldPtr, nuint size, char* file, int line)
{
nuint oldSize = 0;
AllocationHeader* header = null;
if (oldPtr is not null)
{
header = (AllocationHeader*)((nuint)oldPtr - (nuint)sizeof(AllocationHeader));
oldSize = header->Size;
}
void* newPtr = NativeMemory.Realloc((void*)header, size + (nuint)sizeof(AllocationHeader));
if (newPtr is null)
return null;
header = (AllocationHeader*)newPtr;
header->Size = size;
Interlocked.Add(ref totalMemory, -(nint)oldSize + (nint)size);
return (void*)((nuint)newPtr + (nuint)sizeof(AllocationHeader));
}
[UnmanagedCallersOnly]
internal static void CryptoFree(void* ptr)
{
if (ptr is not null)
{
AllocationHeader* header = (AllocationHeader*)((nuint)ptr - (nuint)sizeof(AllocationHeader));
Interlocked.Add(ref totalMemory, -(nint)header->Size);
NativeMemory.Free((void*)header);
}
}
struct AllocationHeader
{
public nuint Size;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment