Skip to main content

Execution Intelligence Tool — Bottleneck Engine + Human Report Generator

Project description

metrun — Execution Intelligence Tool

AI Cost Tracking

PyPI Version Python License AI Cost Human Time Model

  • 🤖 LLM usage: $0.4500 (3 commits)
  • 👤 Human dev: ~$350 (3.5h @ $100/h, 30min dedup)

Generated on 2026-04-06 using openrouter/qwen/qwen3-coder-next


metrun doesn't just show you data — it tells you what the problem is and how to fix it.

What is metrun?

metrun is a Python performance analysis library that turns raw profiling data into an intelligible execution report: bottleneck scores, dependency graphs, critical path highlighting, and actionable fix suggestions — all in one tool.

❌ traditional profilers → "here is your data"
✅ metrun               → "here is your problem and why it exists"

Features

Feature Description
🧠 Bottleneck Engine Builds an execution graph, computes score = time + calls + nested amplification, ranks hotspots
📊 Human Report Generator Emoji-annotated report with time %, call count, score and diagnosis per function
🧨 Critical Path Finds the hottest nested call chain root → leaf
💡 Fix Suggestion Engine Library-specific advice per diagnosis: lru_cache, asyncio, numba, viztracer, scalene
🔥 ASCII Flamegraph Terminal-friendly proportional bar chart, zero extra dependencies
🖼️ SVG Flamegraph Interactive SVG via flameprof
🔌 cProfile Bridge Use stdlib cProfile as the profiling backend; feed results into the Bottleneck Engine
⌨️ CLI metrun profile, metrun inspect, metrun flame commands

Installation

pip install metrun            # core (click included)
pip install metrun[flamegraph] # + SVG flamegraph support (flameprof)

Quick Start

Decorator tracing

from metrun import trace, get_records, analyse, print_report

@trace
def slow_query(n):
    return sum(i * i for i in range(n))

@trace
def handler(items):
    return [slow_query(i) for i in items]

handler(list(range(100)))

bottlenecks = analyse(get_records())
print_report(bottlenecks)

Context-manager tracing

from metrun import section, get_records, analyse, print_report

with section("data_load"):
    data = load_from_db()

with section("transform"):
    result = process(data)

print_report(analyse(get_records()))

Full enhanced report

from metrun import analyse, get_records, print_report

records = get_records()
bottlenecks = analyse(records)

print_report(
    bottlenecks,
    show_graph=True,           # dependency graph
    show_critical_path=True,   # hottest call chain
    records=records,
    show_suggestions=True,     # fix advice
)

Example output

🔥 METRUN PERFORMANCE REPORT
=============================

🔴 slow_query
   → time:      0.8200s  (78.2%)
   → calls:     12,430
   → score:     12.9
   → diagnosis: 🔥 loop hotspot

── Critical Path ─────────────────────────────
🧨 Critical Path  (depth=2, hottest leaf: 0.8200s)

  handler  [1.0500s, 1 calls]
    └─ slow_query  [0.8200s, 12430 calls]   ← 🔥 hottest leaf (0.8200s)

── Fix Suggestions ───────────────────────────
  💡 Fix suggestions for: slow_query
     1. Cache repeated results with lru_cache [functools]
           from functools import lru_cache

           @lru_cache(maxsize=None)
           def slow_query(x): ...

     2. Vectorise the loop with NumPy [numpy]
           import numpy as np
           result = np.sum(arr ** 2)

Auto-diagnosis labels

Label Trigger
🔥 loop hotspot calls ≥ 1 000
🌲 dependency bottleneck ≥ 3 direct children in the execution graph
🐢 slow execution ≥ 30 % of total wall time (time_pct ≥ 0.30), low calls
nominal below all thresholds

Score formula:

score = (total_time / max_time) × 10  +  log10(calls + 1)  +  n_children × 0.5

ASCII Flamegraph

from metrun import render_ascii, print_ascii

print_ascii(bottlenecks, title="My App Flamegraph")
🔥 My App Flamegraph
────────────────────────────────────────────────────────
  slow_query    ████████████████████████████████████████  78.2%  score=12.9
  handler       █████████████████████████████████████████ 100.0%  score=9.4
  serialize     ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░   5.1%  score=2.1
────────────────────────────────────────────────────────

SVG Flamegraph (via flameprof)

from metrun.cprofile_bridge import CProfileBridge
from metrun import render_svg

bridge = CProfileBridge()
with bridge.profile_block():
    my_function()

render_svg(bridge.get_stats(), "flame.svg")
# Open flame.svg in a browser for the interactive flamegraph

cProfile Bridge

Integrate with stdlib cProfile or any existing .prof dump:

from metrun.cprofile_bridge import CProfileBridge
from metrun import analyse, print_report

bridge = CProfileBridge()

@bridge.profile_func
def my_function():
    ...

my_function()

# Analyse with the Bottleneck Engine
bottlenecks = analyse(bridge.to_records())
print_report(bottlenecks)

# Save for snakeviz / flameprof CLI
bridge.save("profile.prof")

Compatible with these popular tools (no code changes needed):

Tool Command
snakeviz — interactive web viewer snakeviz profile.prof
flameprof — SVG flamegraph flameprof profile.prof > flame.svg
py-spy — sampling profiler py-spy record -o flame.svg -- python script.py
viztracer — full trace + HTML flamegraph see below
scalene — line-level CPU+memory python -m scalene script.py

VizTracer integration

# pip install viztracer
from viztracer import VizTracer

with VizTracer(output_file="trace.json"):
    my_function()

# vizviewer trace.json  →  opens interactive HTML flamegraph

Critical Path

from metrun import find_critical_path, print_critical_path, get_records

path = find_critical_path(get_records())
print_critical_path(path)
🧨 Critical Path  (depth=3, hottest leaf: 0.4200s)

  handler  [0.9100s, 1 calls]
    └─ db_query  [0.6300s, 50 calls]
      └─ serialize  [0.4200s, 50 calls]   ← 🔥 hottest leaf (0.4200s)

Fix Suggestion Engine

from metrun import analyse, get_records, suggest, format_suggestions

for b in analyse(get_records()):
    tips = suggest(b)
    print(format_suggestions(b.name, tips))

Suggestion catalogue per diagnosis:

Diagnosis Suggestions
🔥 loop hotspot functools.lru_cache, numpy vectorisation, numba @jit
🌲 dependency bottleneck concurrent.futures, asyncio.gather, batching
🐢 slow execution cProfile + snakeviz, algorithmic review, joblib.Memory
Score ≥ 8 (any) scalene, viztracer

CLI

# Profile a script — bottleneck report
metrun profile my_script.py

# Profile + ASCII flamegraph in terminal
metrun profile my_script.py --ascii-flame

# Profile + save SVG flamegraph
metrun profile my_script.py --flame flame.svg

# Full enhanced report: bottlenecks + critical path + suggestions
metrun inspect my_script.py

# Convert existing .prof dump to SVG
metrun flame profile.prof -o flame.svg

Architecture

  @trace / section()          cProfile.Profile
       │                            │
       ▼                            ▼
 ExecutionTracer              CProfileBridge
  (FunctionRecord)             .to_records()
       │                            │
       └──────────┬─────────────────┘
                  ▼
         BottleneckEngine.analyse()
          score + diagnosis + rank
                  │
       ┌──────────┼──────────────┐
       ▼          ▼              ▼
  print_report  find_critical  suggest()
  (report.py)    _path()      (suggestions.py)
                            
  ASCII/SVG flamegraph ← flamegraph.py

The two tracing backends (ExecutionTracer for decorator/section API and CProfileBridge for cProfile API) both produce the same Dict[str, FunctionRecord] structure consumed by the engine.

Module overview

metrun/
├── profiler.py        # ExecutionTracer — decorator + context-manager tracing
├── bottleneck.py      # BottleneckEngine — score, diagnosis, ranking
├── report.py          # Human Report Generator
├── critical_path.py   # Critical path analysis (DFS on call graph)
├── suggestions.py     # Fix Suggestion Engine
├── flamegraph.py      # ASCII + SVG (flameprof) flamegraphs
├── cprofile_bridge.py # cProfile ↔ metrun bridge
└── cli.py             # Click CLI entry-point

Known limitations

Limitation Detail
Name collisions in cProfile mode CProfileBridge.to_records() uses function name only as key (no file:lineno) — functions with the same name in different modules are merged
Decorator tracing is opt-in Only functions decorated with @trace or wrapped in section() appear in get_records() — not the full call tree
Thread-local call stack Each thread has an independent call stack; cross-thread parent→child links are not recorded
No async support asyncio coroutines are not automatically traced by the decorator backend

License

Licensed under Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

metrun-0.1.4.tar.gz (34.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

metrun-0.1.4-py3-none-any.whl (27.8 kB view details)

Uploaded Python 3

File details

Details for the file metrun-0.1.4.tar.gz.

File metadata

  • Download URL: metrun-0.1.4.tar.gz
  • Upload date:
  • Size: 34.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for metrun-0.1.4.tar.gz
Algorithm Hash digest
SHA256 ccfd0580d6fdec8ecee6ad4e24dafd44fed7eb9242baa5d793f2ed032ca3bc77
MD5 c7470eab85823174230d6ea4951110d0
BLAKE2b-256 e48df0ce27a75ec64b5a226aa182f5895ff46f232f0b4095404e58d2dca6a64f

See more details on using hashes here.

File details

Details for the file metrun-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: metrun-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 27.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for metrun-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 9866e9502b00599cf23c1b57f713090aaf024e74546dcf3b1da77598801b1300
MD5 16f129077590839aeb837662deb66110
BLAKE2b-256 4d163aecff0b4b96d9c7e96d428b99f25c5ce46bc6d1b0c2349a521480475db8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page