Documentation

Metreja · A .NET profiler built for AI coding agents

Overview

Metreja is a CLI-first .NET profiler designed to be driven by AI coding agents. Every operation is a command. Every output is machine-readable NDJSON. The full measure-analyze-fix loop runs without human intervention.

It consists of two components: a native C++ profiler DLL that attaches to the .NET runtime via COR_PROFILER environment variables, and a C# CLI tool for session management and trace analysis.

CommandWhat it does
metreja hotspotsRank methods by self time, inclusive time, call count, or allocations
metreja calltreeExpand a slow method into its full call tree with timing at every level
metreja callersFind who calls a method and how much time each caller contributes
metreja memoryGC counts by generation, pause times, per-type allocation hotspots
metreja analyze-diffCompare two traces to verify a fix actually improved performance

Installation

Prerequisites: .NET 8 SDK or later, Windows 10/11 (x64).

dotnet tool install -g Metreja.Tool

After installation, the metreja command is available globally in your terminal.

Quick Start

Five commands from zero to actionable hotspot data:

# 1. Create a session
SESSION=$(metreja init --scenario "baseline")

# 2. Tell it what to trace (your code, not the framework)
metreja add include -s $SESSION --assembly MyApp
metreja add exclude -s $SESSION --assembly "System.*"
metreja add exclude -s $SESSION --assembly "Microsoft.*"

# 3. Generate the profiler environment and run your app
metreja generate-env -s $SESSION --format shell > env.sh
source env.sh && dotnet run --project src/MyApp -c Release

# 4. Find the bottleneck
metreja hotspots .metreja/output/*.ndjson --top 10

# 5. Drill into the slowest method
metreja calltree .metreja/output/*.ndjson --method "ValidateInventory"

Commands

Analysis commands read NDJSON trace files produced by the profiler. Pass a file path or a glob pattern as the first argument.

hotspots

Per-method timing ranked by self time, inclusive time, call count, or allocation count.

OptionTypeDefaultDescription
filestringRequired. NDJSON trace file
--topint20Number of methods to show
--min-msdouble0.0Minimum time threshold (ms)
--sortstringselfself, inclusive, calls, or allocs
--filterstring[]Filter by method/class/namespace pattern
metreja hotspots trace.ndjson --top 10 --sort self
metreja hotspots trace.ndjson --filter "MyApp.Services" --min-ms 1

calltree

Call tree for a specific method invocation, slowest first.

OptionTypeDefaultDescription
filestringRequired. NDJSON trace file
--methodstringRequired. Method name or pattern
--tidlongFilter by thread ID
--occurrenceint1Which invocation (1 = slowest)
metreja calltree trace.ndjson --method "ProcessOrder"
metreja calltree trace.ndjson --method "ProcessOrder" --occurrence 2

callers

Who calls a method, with call count and timing per caller.

OptionTypeDefaultDescription
filestringRequired. NDJSON trace file
--methodstringRequired. Method name or pattern
--topint20Number of callers to show
metreja callers trace.ndjson --method "SaveChanges" --top 10

memory

GC summary (generation counts, pause times) and per-type allocation hotspots.

OptionTypeDefaultDescription
filestringRequired. NDJSON trace file
--topint20Number of allocation types
--filterstring[]Filter by class name pattern
metreja memory trace.ndjson --top 20
metreja memory trace.ndjson --filter "System.String"

analyze-diff

Compare two traces. Shows per-method timing delta (base vs. compare).

ArgumentTypeDescription
basestringRequired. Base NDJSON file
comparestringRequired. Comparison NDJSON file
metreja analyze-diff baseline.ndjson optimized.ndjson

report

Report an issue to the GitHub repository. Requires the GitHub CLI (gh) installed and authenticated.

OptionTypeDescription
-t, --titlestringRequired. Issue title
-d, --descriptionstringRequired. Issue body/description
metreja report --title "Bug: crash on empty trace" --description "Detailed description."

Exit codes: 0 success · 1 failed · 2 gh not installed · 3 gh not authenticated

Session Management

Sessions store profiler configuration in .metreja/sessions/{sessionId}.json. Each session has a unique 6-hex-char ID.

init

Create a new profiling session. Returns a random session ID.

OptionTypeDefaultDescription
--scenariostringOptional scenario name
metreja init
metreja init --scenario "before-refactor"

add include / add exclude

Add filter rules controlling which methods get traced. Supports wildcards (*).

OptionTypeDefaultDescription
-s, --sessionstringRequired. Session ID
--assemblystring[]*Assembly name pattern
--namespacestring[]*Namespace pattern
--classstring[]*Class name pattern
--methodstring[]*Method name pattern
metreja add include -s a1b2c3 --assembly MyApp
metreja add include -s a1b2c3 --assembly MyApp --namespace "MyApp.Core"
metreja add exclude -s a1b2c3 --assembly "System.*"
metreja add exclude -s a1b2c3 --class "*Generated*"

generate-env

Generate a script that sets the environment variables to attach the profiler to your app.

OptionTypeDefaultDescription
-s, --sessionstringRequired. Session ID
--formatstringbatchbatch, powershell, or shell
--forceboolfalseGenerate even if profiler DLL is not found
metreja generate-env -s a1b2c3                    # Windows batch
metreja generate-env -s a1b2c3 --format powershell  # PowerShell
metreja generate-env -s a1b2c3 --format shell       # bash/sh

set

Configure session settings via subcommands.

SubcommandArgumentsDescription
set metadata-s ID "scenario-name"Update scenario name
set output-s ID "path/pattern.ndjson"Set output path (supports {sessionId}, {pid} tokens)
set max-events-s ID 50000Cap event count (0 = unlimited)
set compute-deltas-s ID trueEnable delta timing for performance analysis

validate

Check session configuration for errors. Exits with code 1 on failure.

metreja validate -s a1b2c3

clear

Delete profiling sessions.

metreja clear -s a1b2c3   # delete one session
metreja clear --all       # delete all sessions

Session Config Format

Stored at .metreja/sessions/{sessionId}.json:

{
  "sessionId": "a1b2c3",
  "metadata": { "scenario": "baseline" },
  "instrumentation": {
    "maxEvents": 0,
    "computeDeltas": true,
    "includes": [
      { "assembly": "MyApp", "namespace": "*", "class": "*", "method": "*" }
    ],
    "excludes": []
  },
  "output": {
    "path": ".metreja/output/{sessionId}_{pid}.ndjson"
  }
}
FieldTypeDefaultDescription
maxEventsint0Event cap per session (0 = unlimited)
computeDeltasbooltrueInclude delta timing on leave events

Output path tokens:

TokenReplaced With
{sessionId}Session ID from config
{pid}Process ID of the profiled app

Architecture

Metreja is a two-component system:

Metreja.Profiler

Native C++ DLL implementing ICorProfilerCallback3 with ELT3 hooks. Attaches to the .NET runtime via COR_PROFILER environment variables, hooks method enter/leave, and writes NDJSON traces.

Metreja.Tool

C# CLI for session management and trace analysis. Creates session configs, generates profiler environment scripts, and provides analysis commands (hotspots, calltree, callers, memory, diff).

Data flow: CLI creates session config → generate-env sets profiler env vars → profiled app loads DLL → DLL writes NDJSON → CLI analysis commands read NDJSON.

Building from Source

Prerequisites: Windows 10/11 (x64), .NET 10 SDK (multi-targets .NET 8/9/10), Visual Studio 2022 Build Tools with "Desktop development with C++" workload.

# Build components
dotnet build src/Metreja.Tool/Metreja.Tool.csproj -c Release
msbuild src/Metreja.Profiler/Metreja.Profiler.vcxproj /p:Configuration=Release /p:Platform=x64

# Run integration tests
dotnet test test/Metreja.IntegrationTests/Metreja.IntegrationTests.csproj -c Release

# Format C++ code
scripts/format-cpp.bat

Build outputs:

OutputPath
CLIsrc/Metreja.Tool/bin/Release/net10.0/metreja.exe
Profiler DLLbin/Release/Metreja.Profiler.dll

Claude Code Plugin

The metreja-profiler plugin for Claude Code enables fully automated profiling sessions. Install it and ask questions in plain English — Claude handles session setup, profiling, analysis, and fix suggestions automatically.

/plugin marketplace add kodroi/metreja-profiler-marketplace
/plugin install metreja-profiler@metreja-profiler-marketplace

After installation, just ask: "This endpoint takes 3 seconds, find out why" or "Where am I wasting memory?"

Requires Metreja.Tool to be installed globally (dotnet tool install -g Metreja.Tool).