Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Profile Proxy

ASecurity

Profile the Claude proxy to identify performance bottlenecks, event loop blocking, and optimization opportunities using py-spy and other profiling tools.

8 stars
0 votes
0 copies
0 views
Added 9/20/2026
toolspythongobashfastapidebugginggitapiperformance

Works with

terminalcliapi

Security Analysis

A92/100
mediumUses curl or wget to download content
mediumInstalls packages at runtime which could introduce malicious dependencies

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add tstapler/dotfiles --skill profile-proxy --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Profile Proxy?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Profile Proxy
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tstapler-profile-proxy/badge)](https://www.skillsdirectory.com/skills/tstapler-profile-proxy)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
# Claude Proxy Profiling Skill

## Purpose
Profile the Claude proxy to identify performance bottlenecks, event loop blocking, and optimization opportunities using py-spy and other profiling tools.

## When to Use
- Investigating high event loop lag (>50ms)
- Debugging slow request performance
- Validating optimization impact
- Understanding CPU vs I/O bottlenecks
- Profiling before/after code changes

## Prerequisites
```bash
# Install py-spy (requires sudo on macOS)
brew install py-spy

# Or with pip
pip install py-spy

# Install other useful profilers
pip install scalene  # Line-level profiler
pip install memray   # Memory profiler
```

## Profile Commands

### 1. Basic Flame Graph (30s sample)
```bash
# Find the main uvicorn process
PID=$(pgrep -f "uvicorn main:app" | head -1)

# Record to SVG flame graph
sudo py-spy record -o /tmp/flamegraph.svg -d 30 -p $PID

# Open in browser
open /tmp/flamegraph.svg
```

**What to look for:**
- **Wide bars at bottom** = hot paths (functions taking most time)
- **Synchronous operations** = `diskcache`, `boto3.client`, `httpx.post`
- **Event loop** = Look for `asyncio` near top (good) vs sync code (bad)

### 2. Live Top View (Like htop for Python)
```bash
sudo py-spy top -p $PID
```

**What to look for:**
- Functions with **>5% CPU** are hot paths
- `GIL` column shows Global Interpreter Lock contention
- High `Own Time` = function itself is slow (not callees)

### 3. Profile Under Load
```bash
# Terminal 1: Start load test
ab -n 10000 -c 50 -H "Authorization: Bearer $CLAUDE_CODE_OAUTH_TOKEN" \
   -H "anthropic-version: 2023-06-01" \
   -H "Content-Type: application/json" \
   -p /tmp/request.json \
   http://localhost:47000/v1/messages

# Terminal 2: Record during load
sudo py-spy record -o /tmp/under-load.svg -d 60 -p $PID
```

**Sample request body** (`/tmp/request.json`):
```json
{
  "model": "claude-haiku-4-5-20251001",
  "messages": [{"role": "user", "content": "Say hello"}],
  "max_tokens": 20
}
```

### 4. Profile Specific Scenarios

**Streaming requests:**
```bash
# Generate streaming load
for i in {1..100}; do
  curl -X POST 'http://localhost:47000/v1/messages?stream=true' \
    -H "Authorization: Bearer $CLAUDE_CODE_OAUTH_TOKEN" \
    -H "anthropic-version: 2023-06-01" \
    -H "Content-Type: application/json" \
    -d '{"model": "claude-haiku-4-5-20251001", "messages": [{"role": "user", "content": "Count to 10"}], "max_tokens": 100}' &
done

# Profile
sudo py-spy record -o /tmp/streaming.svg -d 30 -p $PID
```

**Non-streaming requests:**
```bash
# Non-streaming load
ab -n 1000 -c 50 -p /tmp/request.json \
   http://localhost:47000/v1/messages
```

**Metrics dashboard queries:**
```bash
# Generate dashboard load
for i in {1..100}; do
  curl -s http://localhost:47000/metrics > /dev/null
done &

sudo py-spy record -o /tmp/metrics.svg -d 10 -p $PID
```

### 5. Dump Current State (Non-Intrusive)
```bash
# Take snapshot without stopping process
sudo py-spy dump -p $PID

# See what each thread is doing right now
sudo py-spy dump --threads -p $PID
```

## Advanced Profiling

### Line-Level Profiling with Scalene
```bash
# More detailed than py-spy, shows line-by-line timing
scalene main.py

# Or attach to running process
sudo scalene --pid $PID --reduced-profile
```

**Advantages:**
- Shows CPU time per line
- Identifies memory allocations
- Tracks GPU usage (if applicable)

**Disadvantages:**
- Higher overhead than py-spy
- May slow down production traffic

### Memory Profiling with memray
```bash
# Track memory allocations
memray run main.py

# Attach to running process
sudo memray attach $PID --duration 30

# Generate flamegraph
memray flamegraph memray-*.bin
```

## Reading Flame Graphs

### Anatomy of a Flame Graph
```
┌─────────────────────────────────────────┐ ← Top = main entry point
│         main.py                         │
├───────────────────┬─────────────────────┤
│  fallback.py      │   metrics.py        │ ← Callees
├─────────┬─────────┼──────────┬──────────┤
│bedrock.py│anthropic│cache.set │iterkeys │ ← Bottlenecks (wide = hot)
└─────────┴─────────┴──────────┴──────────┘
```

**X-axis:** Width = % of total time (wider = more time)
**Y-axis:** Call stack depth (bottom to top)
**Color:** Random (for contrast only)

### Identifying Blocking Operations

**❌ Bad Pattern (Synchronous I/O):**
```
uvicorn.run
  └─ FastAPI.handle_request
       └─ FallbackHandler.send_message
            └─ diskcache.Cache.set        ← WIDE BAR = BLOCKING
                 └─ fcntl.flock           ← File lock!
                      └─ os.write          ← Disk I/O
```

**✅ Good Pattern (Async I/O):**
```
uvicorn.run
  └─ FastAPI.handle_request
       └─ FallbackHandler.send_message
            └─ asyncio.to_thread         ← Narrow (fast)
                 └─ [thread pool]         ← Off event loop
```

## Proxy-Specific Hot Paths

### Expected Top Functions (by time):

1. **`bedrock.py:_stream_bedrock_sync`** (20-40%)
   - Streaming responses from Bedrock
   - **Expected:** This is doing real work, should be wide

2. **`providers/anthropic.py:send_message`** (10-20%)
   - HTTP requests to Anthropic API
   - **Expected:** Network I/O, should show `httpx.post`

3. **`fallback.py:send_message`** (10-15%)
   - Provider orchestration
   - **Expected:** Should be orchestration, not computation

4. **`metrics.py:record_request_complete`** (5-10% **before Phase 1**)
   - Recording metrics
   - **Expected:** Should drop to <1% after Phase 1 optimizations

5. **`diskcache` operations** (10-20% **before Phase 1**)
   - Cache reads/writes
   - **Expected:** Should move to thread pool or disappear

### ⚠️ Red Flags (investigate if you see these):

- **`cache.iterkeys()` is wide** → Still scanning full cache (should be cached)
- **`diskcache.Lock()` appears** → File locking still happening (should be removed)
- **`boto3.client()` in hot path** → Client recreation (should be cached)
- **`json.dumps/loads` is wide** → Serialization overhead (consider msgpack)
- **`logging` is wide** → Too much logging (use lazy evaluation)

## Profiling Workflow

### Before Optimization:
```bash
# 1. Baseline profile
sudo py-spy record -o /tmp/before.svg -d 60 -p $PID

# 2. Check metrics
curl -s http://localhost:47000/metrics | jq '.lag_data[-1]'

# 3. Load test
ab -n 1000 -c 50 http://localhost:47000/health

# 4. Record max lag
```

### After Optimization:
```bash
# 1. Profile again
sudo py-spy record -o /tmp/after.svg -d 60 -p $PID

# 2. Compare lag
curl -s http://localhost:47000/metrics | jq '.lag_data[-1]'

# 3. Same load test
ab -n 1000 -c 50 http://localhost:47000/health

# 4. Compare results
```

### Side-by-Side Comparison:
```bash
# Open both flame graphs
open /tmp/before.svg /tmp/after.svg

# Visual diff:
# - Blocking operations should shrink or disappear
# - Event loop should be thinner (less blocking)
# - Thread pool operations should appear
```

## Integration with Metrics Dashboard

### Correlate Profile with Lag Spikes

1. **Note timestamp of high lag:**
   ```bash
   curl -s http://localhost:47000/metrics | jq '.lag_data[] | select(.max_ms > 100)'
   ```

2. **Profile during next spike:**
   ```bash
   # Wait for lag warning in logs
   tail -f /tmp/claude-proxy.app.log | grep "Event loop lag"

   # When you see warning, immediately profile:
   sudo py-spy record -o /tmp/spike.svg -d 5 -p $PID
   ```

3. **Analyze correlation:**
   - What operation was running during spike?
   - Is it a known hot path?
   - Can it be moved to thread pool?

## Common Bottlenecks & Solutions

| Symptom in Flame Graph | Root Cause | Solution |
|------------------------|------------|----------|
| `diskcache.Cache.set` is wide | Sync disk writes | `await asyncio.to_thread()` |
| `cache.iterkeys()` is wide | Full cache scan | Cache the result for 5s |
| `diskcache.Lock` appears | File-based locking | Use in-memory `deque` |
| `boto3.Session()` in hot path | Client recreation | Cache client, refresh proactively |
| `httpx.post` is wide | Network latency | Expected (but check connection pooling) |
| `json.dumps` is wide | Serialization overhead | Consider msgpack or reduce payload |
| Deep call stacks | Too many indirections | Flatten architecture |

## Automation Script

Create `/tmp/profile-proxy.sh`:

```bash
#!/bin/bash
set -e

PID=$(pgrep -f "uvicorn main:app" | head -1)
DURATION=${1:-30}
OUTPUT=${2:-/tmp/proxy-profile.svg}

echo "Profiling PID $PID for ${DURATION}s..."
echo "Output: $OUTPUT"

# Profile
sudo py-spy record -o "$OUTPUT" -d "$DURATION" -p "$PID"

# Show top functions
echo ""
echo "Top 10 functions by time:"
sudo py-spy top -p "$PID" -d 5 | head -20

# Check current lag
echo ""
echo "Current event loop lag:"
curl -s http://localhost:47000/metrics | jq '.current_lag_ms'

# Open flame graph
open "$OUTPUT"
```

Usage:
```bash
chmod +x /tmp/profile-proxy.sh
/tmp/profile-proxy.sh 60 /tmp/my-profile.svg
```

## Profiling Checklist

Before claiming an optimization worked:

- [ ] Profile before and after with same load
- [ ] Run load test during profiling
- [ ] Check event loop lag metrics
- [ ] Validate no regression in functionality
- [ ] Compare flame graph widths
- [ ] Check application logs for warnings
- [ ] Test under streaming and non-streaming load
- [ ] Profile all worker processes (not just one)

## Multi-Worker Profiling

Since you run 10 workers, profile all of them:

```bash
# Profile all workers
for pid in $(pgrep -f "uvicorn main:app"); do
  sudo py-spy record -o "/tmp/worker-${pid}.svg" -d 30 -p "$pid" &
done
wait

# Open all flame graphs
open /tmp/worker-*.svg
```

Look for:
- **Consistency:** All workers should show similar patterns
- **Outliers:** One worker much slower? Bad cache state or stuck request
- **Load distribution:** All workers equally busy? Or some idle?

## Resources

- [py-spy GitHub](https://github.com/benfred/py-spy)
- [Reading Flame Graphs](http://www.brendangregg.com/flamegraphs.html)
- [Python Profiling Guide](https://docs.python.org/3/library/profile.html)
- [AsyncIO Performance Tips](https://docs.python.org/3/library/asyncio-dev.html#debug-mode)

## Notes

- **Requires root:** py-spy needs sudo for process attachment
- **Low overhead:** py-spy samples (doesn't instrument), ~1% overhead
- **Production safe:** Can run in production without noticeable impact
- **Multi-language:** Works with C extensions (shows native calls)
- **Real-time:** See results immediately with `top` mode

Attribution

tstaplertstapler
View sourceMore from tstapler →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

ucoz-landing-skill

Playbook for creating and editing uCoz landing pages via MCP tools (`templates_tool`, `ftp_tool`, `modules_tool`). Use for tasks such as: "build a landing page", "update the homepage as a landing page", "create a promo page on the homepage", "add a lead form / menu / SEO to the homepage". Homepage: `page_list`, `page_get`; first publish — `page_update` with full `page_tmpl`; HTML edits after generation — `patch_template` (module_id=2, template_id=1), not `update_template`. Activate the mail f...

107 votes

Paperclip

Interact with the Paperclip control plane API for task coordination and governance. Use when checking assignments, updating issue status, posting comments, delegating work, managing routines, or calling Paperclip API endpoints.

805541 votes

Instantly Rdsthomas Mission Control

Instantly.ai cold email outreach API - manage campaigns, leads, accounts, and analytics. Use for cold email automation, lead management, campaign creation/monitoring, and email account warmup.

761 votes

Daw Music

Digital Audio Workstation usage, music composition, interactive music systems, and game audio implementation for immersive soundscapes.

761 votes

Caveman Compress

Compress natural language memory files (CLAUDE.md, todos, preferences) into caveman format to save input tokens. Preserves all technical substance, code, URLs, and structure. Compressed version overwrites the original file. Human-readable backup saved as FILE.original.md. Trigger: /caveman-compress FILEPATH or "compress memory file"

1023330 votes
View all in tools →