MonkeyCode性能测试与调优:让AI生成的代码跑得更快
代码跑得慢,AI也救不了
MonkeyCode能生成功能正确的代码,但性能不一定最优。N+1查询、内存泄漏、算法复杂度高……这些问题AI不一定能自动避免。
这篇文章用MonkeyCode生成性能测试和调优方案,覆盖:基准测试、Profiling、内存分析、并发压测。
给MonkeyCode的统一Prompt
用Python实现完整的性能测试与调优工具链,要求:
1. 基准测试(Benchmark)框架
2. 函数级Profiling(cProfile + line_profiler)
3. 内存分析(memory_profiler + tracemalloc)
4. 并发压测(Locust + 自定义压测)
5. 性能回归测试(CI/CD集成)
6. 自动生成性能报告(Markdown + HTML)
7. 性能瓶颈自动诊断
需要完整可运行的代码,包含实际案例(Web API、数据处理、并发场景)
1. 基准测试框架
# benchmark_framework.py - MonkeyCode生成
import time
import statistics
import functools
from dataclasses import dataclass, field
from typing import Callable, Any, List, Dict
import pickle
import json
@dataclass
class BenchmarkResult:
name: str
mean: float
median: float
stdev: float
min: float
max: float
iterations: int
warmup_iterations: int
metadata: Dict[str, Any] = field(default_factory=dict)
class Benchmark:
"""基准测试框架"""
def __init__(self, warmup: int = 10, iterations: int = 100):
self.warmup = warmup
self.iterations = iterations
self.results: List[BenchmarkResult] = []
def run(self, name: str, func: Callable, *args, **kwargs) -> BenchmarkResult:
"""运行基准测试"""
print(f"Running benchmark: {name}")
# 预热
for _ in range(self.warmup):
func(*args, **kwargs)
# 正式测试
times = []
for _ in range(self.iterations):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
times.append((end - start) * 1000) # 转换为毫秒
# 统计
result = BenchmarkResult(
name=name,
mean=statistics.mean(times),
median=statistics.median(times),
stdev=statistics.stdev(times) if len(times) > 1 else 0,
min=min(times),
max=max(times),
iterations=self.iterations,
warmup_iterations=self.warmup,
)
self.results.append(result)
self._print_result(result)
return result
def _print_result(self, result: BenchmarkResult):
print(f" Mean: {result.mean:.3f} ms")
print(f" Median: {result.median:.3f} ms")
print(f" StDev: {result.stdev:.3f} ms")
print(f" Min: {result.min:.3f} ms")
print(f" Max: {result.max:.3f} ms")
print()
def compare(self, baseline: BenchmarkResult, current: BenchmarkResult) -> float:
"""对比两个基准测试结果,返回加速比"""
speedup = baseline.mean / current.mean
print(f"Speedup: {speedup:.2f}x (baseline: {baseline.name}, current: {current.name})")
return speedup
def save_results(self, filepath: str):
"""保存结果到JSON"""
data = [
{
"name": r.name,
"mean_ms": r.mean,
"median_ms": r.median,
"stdev_ms": r.stdev,
"min_ms": r.min,
"max_ms": r.max,
"iterations": r.iterations,
"metadata": r.metadata,
}
for r in self.results
]
with open(filepath, 'w') as f:
json.dump(data, f, indent=2)
print(f"Results saved to {filepath}")
def generate_report(self, output_path: str = "benchmark_report.html"):
"""生成HTML报告"""
html = """
<!DOCTYPE html>
<html>
<head>
<title>Benchmark Report</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body { font-family: sans-serif; margin: 20px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.chart-container { width: 800px; margin: 20px 0; }
</style>
</head>
<body>
<h1>Benchmark Report</h1>
<table>
<tr>
<th>Name</th>
<th>Mean (ms)</th>
<th>Median (ms)</th>
<th>StDev (ms)</th>
<th>Min (ms)</th>
<th>Max (ms)</th>
</tr>
"""
for r in self.results:
html += f"""
<tr>
<td>{r.name}</td>
<td>{r.mean:.3f}</td>
<td>{r.median:.3f}</td>
<td>{r.stdev:.3f}</td>
<td>{r.min:.3f}</td>
<td>{r.max:.3f}</td>
</tr>
"""
html += """
</table>
<div class="chart-container">
<canvas id="benchmarkChart"></canvas>
</div>
<script>
const ctx = document.getElementById('benchmarkChart').getContext('2d');
const chart = new Chart(ctx, {
type: 'bar',
data: {
labels: """ + str([r.name for r in self.results]) + """,
datasets: [{
label: 'Mean (ms)',
data: """ + str([r.mean for r in self.results]) + """,
backgroundColor: 'rgba(54, 162, 235, 0.5)',
}]
},
options: {
responsive: true,
scales: {
y: { beginAtZero: true }
}
}
});
</script>
</body>
</html>
"""
with open(output_path, 'w') as f:
f.write(html)
print(f"Report generated: {output_path}")
# 装饰器版本
def benchmark(name: str = None, iterations: int = 100, warmup: int = 10):
"""基准测试装饰器"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
bench = Benchmark(warmup=warmup, iterations=iterations)
return bench.run(name or func.__name__, func, *args, **kwargs)
return wrapper
return decorator
# 使用示例
if __name__ == '__main__':
bench = Benchmark(warmup=5, iterations=50)
# 测试JSON序列化性能
data = {"key": "value", "number": 42, "list": list(range(100))}
json_result = bench.run("json_dumps", lambda: json.dumps(data))
pickle_result = bench.run("pickle_dumps", lambda: pickle.dumps(data))
bench.compare(json_result, pickle_result)
bench.generate_report()
2. 函数级Profiling
# profiling.py - MonkeyCode生成
import cProfile
import pstats
import io
import line_profiler
import functools
from typing import Callable, List
import time
class Profiler:
"""性能分析工具"""
@staticmethod
def profile_cprofile(func: Callable, *args, **kwargs) -> pstats.Stats:
"""使用cProfile进行性能分析"""
profiler = cProfile.Profile()
profiler.enable()
result = func(*args, **kwargs)
profiler.disable()
# 输出结果
stream = io.StringIO()
stats = pstats.Stats(profiler, stream=stream)
stats.sort_stats(pstats.SortKey.CUMULATIVE)
stats.print_stats(20) # 显示前20个函数
print(stream.getvalue())
return stats
@staticmethod
def profile_line(func: Callable, *args, **kwargs):
"""使用line_profiler进行逐行分析"""
# 需要安装: pip install line_profiler
try:
from line_profiler import LineProfiler
profiler = LineProfiler()
profiler.add_function(func)
profiler.enable()
result = func(*args, **kwargs)
profiler.disable()
# 输出结果
profiler.print_stats()
except ImportError:
print("line_profiler not installed. Install with: pip install line_profiler")
@staticmethod
def time_it(func: Callable, *args, iterations: int = 1000, **kwargs) -> float:
"""简单计时"""
start = time.perf_counter()
for _ in range(iterations):
func(*args, **kwargs)
end = time.perf_counter()
avg_time = (end - start) / iterations * 1000 # 毫秒
print(f"{func.__name__}: {avg_time:.3f} ms/iteration (avg over {iterations} iterations)")
return avg_time
# 装饰器版本
def profile(func: Callable = None, *, cprofile: bool = True, line_profile: bool = False):
"""性能分析装饰器"""
def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
if cprofile:
print(f"\n{'='*60}")
print(f"Profiling: {f.__name__}")
print(f"{'='*60}")
Profiler.profile_cprofile(f, *args, **kwargs)
if line_profile:
print(f"\n{'='*60}")
print(f"Line Profiling: {f.__name__}")
print(f"{'='*60}")
Profiler.profile_line(f, *args, **kwargs)
return f(*args, **kwargs)
return wrapper
if func is None:
return decorator
else:
return decorator(func)
# 使用示例
@profile(cprofile=True, line_profile=False)
def expensive_operation(n: int = 10000):
"""模拟耗时操作"""
result = []
for i in range(n):
result.append(i ** 2)
return result
@profile(line_profile=True)
def process_data(data: List[int]):
"""处理数据(逐行分析)"""
# 查找所有偶数
evens = [x for x in data if x % 2 == 0]
# 计算平方和
squares = [x ** 2 for x in evens]
# 求和
total = sum(squares)
return total
if __name__ == '__main__':
# cProfile分析
data = list(range(10000))
result = process_data(data)
# 简单计时
Profiler.time_it(expensive_operation, 1000, iterations=100)
3. 内存分析
# memory_profiler.py - MonkeyCode生成
import tracemalloc
import memory_profiler
from memory_profiler import profile as memory_profile
import psutil
import os
from typing import Callable
import gc
class MemoryAnalyzer:
"""内存分析工具"""
@staticmethod
def analyze_tracemalloc(func: Callable, *args, **kwargs):
"""使用tracemalloc追踪内存分配"""
tracemalloc.start()
result = func(*args, **kwargs)
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
print("\n[Top 10 Memory Allocations]")
for stat in top_stats[:10]:
print(stat)
tracemalloc.stop()
return result
@staticmethod
def measure_peak_memory(func: Callable, *args, **kwargs) -> float:
"""测量函数执行期间的内存峰值(MB)"""
process = psutil.Process(os.getpid())
# 清理内存
gc.collect()
mem_before = process.memory_info().rss / 1024 / 1024 # MB
result = func(*args, **kwargs)
mem_after = process.memory_info().rss / 1024 / 1024 # MB
mem_peak = mem_after - mem_before
print(f"Peak memory usage: {mem_peak:.2f} MB")
return mem_peak
@staticmethod
def detect_memory_leak(func: Callable, iterations: int = 100, *args, **kwargs):
"""检测内存泄漏"""
process = psutil.Process(os.getpid())
mem_usage = []
for i in range(iterations):
gc.collect() # 强制垃圾回收
mem_before = process.memory_info().rss / 1024 / 1024
result = func(*args, **kwargs)
mem_after = process.memory_info().rss / 1024 / 1024
mem_usage.append(mem_after)
if i % 10 == 0:
print(f"Iteration {i}: {mem_after:.2f} MB")
# 检查是否泄漏
if len(mem_usage) > 10:
trend = (mem_usage[-1] - mem_usage[0]) / len(mem_usage)
if trend > 0.1: # 每次迭代增长超过0.1MB
print(f"⚠️ Potential memory leak detected! Trend: {trend:.2f} MB/iteration")
else:
print(f"✅ No memory leak detected. Trend: {trend:.2f} MB/iteration")
@staticmethod
def get_object_counts():
"""获取各类型对象数量(调试内存问题)"""
import collections
counts = collections.Counter(type(obj).__name__ for obj in gc.get_objects())
print("\n[Top 20 Object Types]")
for obj_type, count in counts.most_common(20):
print(f" {obj_type}: {count}")
# 装饰器版本
def memory_track(func: Callable = None, *, detailed: bool = False):
"""内存追踪装饰器"""
def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
if detailed:
print(f"\n{'='*60}")
print(f"Memory Tracking (detailed): {f.__name__}")
print(f"{'='*60}")
MemoryAnalyzer.analyze_tracemalloc(f, *args, **kwargs)
else:
print(f"\n{'='*60}")
print(f"Memory Tracking: {f.__name__}")
print(f"{'='*60}")
MemoryAnalyzer.measure_peak_memory(f, *args, **kwargs)
return f(*args, **kwargs)
return wrapper
if func is None:
return decorator
else:
return decorator(func)
# 使用示例
@memory_track(detailed=False)
def create_large_list(size: int = 1000000):
"""创建大列表"""
return [i for i in range(size)]
@memory_profile # 需要安装: pip install memory_profiler
def process_large_data():
"""处理大量数据"""
data = [i ** 2 for i in range(100000)]
filtered = [x for x in data if x % 3 == 0]
return sum(filtered)
if __name__ == '__main__':
# 测量内存峰值
result = create_large_list(1000000)
# 检测内存泄漏
def leaky_func():
# 模拟内存泄漏(全局列表不断增长)
global _leak_list
if not hasattr(sys.modules[__name__], '_leak_list'):
_leak_list = []
_leak_list.extend([1] * 10000)
print("\n[Memory Leak Detection]")
MemoryAnalyzer.detect_memory_leak(leaky_func, iterations=50)
# 获取对象统计
MemoryAnalyzer.get_object_counts()
4. 并发压测
# load_testing.py - MonkeyCode生成
import asyncio
import aiohttp
import time
import statistics
from typing import List, Dict, Any
import json
import concurrent.futures
import threading
class LoadTester:
"""并发压测工具"""
def __init__(self, base_url: str, concurrency: int = 10, total_requests: int = 1000):
self.base_url = base_url
self.concurrency = concurrency
self.total_requests = total_requests
self.results: List[float] = []
self.errors: List[str] = []
self.status_codes: Dict[int, int] = {}
async def single_request(self, session: aiohttp.ClientSession, endpoint: str) -> float:
"""发送单个请求,返回响应时间(毫秒)"""
url = f"{self.base_url}{endpoint}"
start = time.perf_counter()
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response:
await response.text()
status = response.status
self.status_codes[status] = self.status_codes.get(status, 0) + 1
elapsed = (time.perf_counter() - start) * 1000
return elapsed
except Exception as e:
self.errors.append(str(e))
return -1
async def run_load_test(self, endpoint: str = "/"):
"""运行压测"""
print(f"Starting load test: {self.total_requests} requests, concurrency: {self.concurrency}")
connector = aiohttp.TCPConnector(limit=self.concurrency * 2)
async with aiohttp.ClientSession(connector=connector) as session:
tasks = []
for _ in range(self.total_requests):
task = self.single_request(session, endpoint)
tasks.append(task)
# 限制并发数
semaphore = asyncio.Semaphore(self.concurrency)
async def bounded_task(task):
async with semaphore:
return await task
bounded_tasks = [bounded_task(t) for t in tasks]
start_time = time.perf_counter()
results = await asyncio.gather(*bounded_tasks)
end_time = time.perf_counter()
# 统计结果
self.results = [r for r in results if r > 0]
total_time = (end_time - start_time) * 1000 # 毫秒
self._print_statistics(total_time)
def _print_statistics(self, total_time: float):
"""打印统计信息"""
if not self.results:
print("No successful requests!")
return
print(f"\n{'='*60}")
print(f"Load Test Results")
print(f"{'='*60}")
print(f"Total Requests: {self.total_requests}")
print(f"Successful: {len(self.results)}")
print(f"Failed: {len(self.errors)}")
print(f"Total Time: {total_time/1000:.2f} seconds")
print(f"Requests/Second (RPS): {len(self.results) / (total_time/1000):.2f}")
print(f"Mean Response Time: {statistics.mean(self.results):.2f} ms")
print(f"Median Response Time: {statistics.median(self.results):.2f} ms")
print(f"Min Response Time: {min(self.results):.2f} ms")
print(f"Max Response Time: {max(self.results):.2f} ms")
if len(self.results) > 1:
print(f"StdDev Response Time: {statistics.stdev(self.results):.2f} ms")
print(f"\nStatus Code Distribution:")
for status, count in sorted(self.status_codes.items()):
print(f" {status}: {count} ({count/len(self.results)*100:.1f}%)")
if self.errors:
print(f"\nErrors (first 5):")
for err in self.errors[:5]:
print(f" {err}")
def save_results(self, filepath: str):
"""保存结果到JSON"""
data = {
"total_requests": self.total_requests,
"successful": len(self.results),
"failed": len(self.errors),
"rps": len(self.results) / (sum(self.results) / 1000),
"mean_ms": statistics.mean(self.results),
"median_ms": statistics.median(self.results),
"min_ms": min(self.results),
"max_ms": max(self.results),
"status_codes": self.status_codes,
"errors": self.errors[:10], # 只保存前10个错误
}
with open(filepath, 'w') as f:
json.dump(data, f, indent=2)
print(f"\nResults saved to {filepath}")
# 使用Locust进行更复杂的压测
try:
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
"""Locust压测用户行为模拟"""
wait_time = between(1, 3) # 每个用户请求间隔1-3秒
@task(3) # 权重:3倍于其他任务
def view_homepage(self):
self.client.get("/")
@task(1)
def view_api(self):
self.client.get("/api/users")
@task(1)
def create_user(self):
self.client.post("/api/users", json={
"name": "Test User",
"email": "test@example.com"
})
except ImportError:
print("Locust not installed. Install with: pip install locust")
if __name__ == '__main__':
# 使用LoadTester
tester = LoadTester(
base_url="http://localhost:8000",
concurrency=50,
total_requests=1000
)
asyncio.run(tester.run_load_test(endpoint="/api/data"))
tester.save_results("load_test_results.json")
5. 性能回归测试
# performance_regression.py - MonkeyCode生成
import json
import subprocess
import sys
from pathlib import Path
from typing import Dict, List, Optional
import difflib
class PerformanceRegressionTest:
"""性能回归测试"""
def __init__(self, baseline_file: str = "baseline_performance.json"):
self.baseline_file = Path(baseline_file)
self.baseline: Dict[str, float] = {}
self.current: Dict[str, float] = {}
self.threshold_percent: float = 10.0 # 性能下降超过10%则报警
def load_baseline(self):
"""加载基线性能数据"""
if self.baseline_file.exists():
with open(self.baseline_file) as f:
self.baseline = json.load(f)
print(f"Loaded baseline from {self.baseline_file}")
else:
print(f"No baseline file found at {self.baseline_file}")
def save_baseline(self):
"""保存当前性能为基线"""
with open(self.baseline_file, 'w') as f:
json.dump(self.current, f, indent=2)
print(f"Saved baseline to {self.baseline_file}")
def run_benchmark(self, name: str, command: List[str]) -> float:
"""运行基准测试命令,返回执行时间(秒)"""
print(f"Running benchmark: {name}")
start = time.perf_counter()
result = subprocess.run(command, capture_output=True, text=True)
end = time.perf_counter()
elapsed = end - start
if result.returncode != 0:
print(f"Benchmark failed: {result.stderr}")
return -1
self.current[name] = elapsed
print(f" Time: {elapsed:.3f}s")
return elapsed
def compare_with_baseline(self) -> List[str]:
"""与基线对比,返回回归列表"""
regressions = []
for name, current_time in self.current.items():
if name not in self.baseline:
print(f"New benchmark: {name}")
continue
baseline_time = self.baseline[name]
change_percent = ((current_time - baseline_time) / baseline_time) * 100
if change_percent > self.threshold_percent:
regression = f"{name}: {change_percent:+.1f}% (baseline: {baseline_time:.3f}s, current: {current_time:.3f}s)"
regressions.append(regression)
print(f"⚠️ Regression detected: {regression}")
elif change_percent < -self.threshold_percent:
print(f"✅ Improvement: {name}: {change_percent:+.1f}%")
else:
print(f"✅ No significant change: {name}: {change_percent:+.1f}%")
return regressions
def generate_report(self, output_path: str = "performance_report.md"):
"""生成性能回归报告"""
regressions = self.compare_with_baseline()
with open(output_path, 'w') as f:
f.write("# Performance Regression Report\n\n")
f.write(f"Generated: {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n")
if regressions:
f.write("## ⚠️ Regressions Detected\n\n")
for r in regressions:
f.write(f"- {r}\n")
else:
f.write("## ✅ No Regressions Detected\n\n")
f.write("\n## Detailed Comparison\n\n")
f.write("| Benchmark | Baseline (s) | Current (s) | Change (%) |\n")
f.write("|-----------|---------------|-------------|-------------|\n")
for name in sorted(set(list(self.baseline.keys()) + list(self.current.keys()))):
baseline = self.baseline.get(name, float('nan'))
current = self.current.get(name, float('nan'))
if baseline is None or current is None:
change = "N/A"
else:
change = f"{((current - baseline) / baseline) * 100:+.1f}%"
f.write(f"| {name} | {baseline:.3f} | {current:.3f} | {change} |\n")
print(f"\nReport generated: {output_path}")
# CI/CD集成示例(GitHub Actions)
def create_github_actions_workflow():
"""生成GitHub Actions性能回归测试配置"""
workflow = """
name: Performance Regression Test
on:
pull_request:
branches: [main]
jobs:
performance-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run performance tests
run: python performance_regression.py --compare
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: performance-report
path: performance_report.md
- name: Comment PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('performance_report.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: report
});
"""
with open('.github/workflows/performance-regression.yml', 'w') as f:
f.write(workflow)
print("Created GitHub Actions workflow: .github/workflows/performance-regression.yml")
if __name__ == '__main__':
# 运行性能回归测试
tester = PerformanceRegressionTest()
tester.load_baseline()
# 运行基准测试
tester.run_benchmark("api_response_time", ["python", "test_api.py"])
tester.run_benchmark("db_query_time", ["python", "test_db.py"])
tester.run_benchmark("memory_usage", ["python", "test_memory.py"])
# 对比并生成报告
tester.compare_with_baseline()
tester.generate_report()
# 更新基线(如果是main分支)
if os.getenv('GITHUB_REF') == 'refs/heads/main':
tester.save_baseline()
6. 自动性能瓶颈诊断
# bottleneck_diagnosis.py - MonkeyCode生成
import psutil
import time
import threading
from typing import List, Dict, Any
import asyncio
import aiohttp
import json
class BottleneckDiagnoser:
"""性能瓶颈自动诊断"""
def __init__(self, api_url: str):
self.api_url = api_url
self.metrics: Dict[str, List[float]] = {
"cpu_usage": [],
"memory_usage": [],
"response_time": [],
"active_connections": [],
}
self.running = False
def start_monitoring(self, interval: float = 1.0):
"""开始监控系统资源"""
self.running = True
def monitor():
while self.running:
# CPU使用率
cpu_percent = psutil.cpu_percent(interval=0.1)
self.metrics["cpu_usage"].append(cpu_percent)
# 内存使用率
memory = psutil.virtual_memory()
self.metrics["memory_usage"].append(memory.percent)
time.sleep(interval)
monitor_thread = threading.Thread(target=monitor, daemon=True)
monitor_thread.start()
print(f"Started system monitoring (interval: {interval}s)")
def stop_monitoring(self):
"""停止监控"""
self.running = False
print("Stopped system monitoring")
async def measure_response_time(self, endpoint: str, requests: int = 100):
"""测量API响应时间"""
print(f"Measuring response time for {endpoint} ({requests} requests)...")
async with aiohttp.ClientSession() as session:
tasks = []
for _ in range(requests):
task = self._single_request(session, endpoint)
tasks.append(task)
results = await asyncio.gather(*tasks)
self.metrics["response_time"].extend([r for r in results if r > 0])
avg_time = sum(self.metrics["response_time"]) / len(self.metrics["response_time"])
print(f"Average response time: {avg_time:.2f} ms")
return avg_time
async def _single_request(self, session: aiohttp.ClientSession, endpoint: str) -> float:
"""发送单个请求"""
url = f"{self.api_url}{endpoint}"
start = time.perf_counter()
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response:
await response.text()
elapsed = (time.perf_counter() - start) * 1000
return elapsed
except:
return -1
def diagnose(self) -> Dict[str, Any]:
"""诊断性能瓶颈"""
diagnosis = {
"bottlenecks": [],
"recommendations": [],
}
# CPU瓶颈
if self.metrics["cpu_usage"]:
avg_cpu = sum(self.metrics["cpu_usage"]) / len(self.metrics["cpu_usage"])
if avg_cpu > 80:
diagnosis["bottlenecks"].append(f"High CPU usage: {avg_cpu:.1f}%")
diagnosis["recommendations"].append("Consider optimizing CPU-intensive operations or scaling horizontally")
# 内存瓶颈
if self.metrics["memory_usage"]:
avg_mem = sum(self.metrics["memory_usage"]) / len(self.metrics["memory_usage"])
if avg_mem > 80:
diagnosis["bottlenecks"].append(f"High memory usage: {avg_mem:.1f}%")
diagnosis["recommendations"].append("Check for memory leaks or increase memory limit")
# 响应时间瓶颈
if self.metrics["response_time"]:
avg_rt = sum(self.metrics["response_time"]) / len(self.metrics["response_time"])
if avg_rt > 500: # 响应时间超过500ms
diagnosis["bottlenecks"].append(f"Slow API response: {avg_rt:.1f} ms")
diagnosis["recommendations"].append("Optimize database queries, add caching, or use async processing")
# 如果没有发现瓶颈
if not diagnosis["bottlenecks"]:
diagnosis["bottlenecks"].append("No significant bottlenecks detected")
return diagnosis
def generate_diagnosis_report(self, output_path: str = "bottleneck_diagnosis.json"):
"""生成诊断报告"""
diagnosis = self.diagnose()
report = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"metrics_summary": {
"cpu_usage_avg": sum(self.metrics["cpu_usage"]) / len(self.metrics["cpu_usage"]) if self.metrics["cpu_usage"] else 0,
"memory_usage_avg": sum(self.metrics["memory_usage"]) / len(self.metrics["memory_usage"]) if self.metrics["memory_usage"] else 0,
"response_time_avg": sum(self.metrics["response_time"]) / len(self.metrics["response_time"]) if self.metrics["response_time"] else 0,
},
"diagnosis": diagnosis,
}
with open(output_path, 'w') as f:
json.dump(report, f, indent=2)
print(f"\n{'='*60}")
print(f"Bottleneck Diagnosis Report")
print(f"{'='*60}")
print(f"CPU Usage (avg): {report['metrics_summary']['cpu_usage_avg']:.1f}%")
print(f"Memory Usage (avg): {report['metrics_summary']['memory_usage_avg']:.1f}%")
print(f"Response Time (avg): {report['metrics_summary']['response_time_avg']:.1f} ms")
print(f"\nBottlenecks:")
for bottleneck in diagnosis["bottlenecks"]:
print(f" ⚠️ {bottleneck}")
print(f"\nRecommendations:")
for rec in diagnosis["recommendations"]:
print(f" 💡 {rec}")
print(f"\nReport saved to {output_path}")
if __name__ == '__main__':
# 诊断API性能瓶颈
diagnoser = BottleneckDiagnoser(api_url="http://localhost:8000")
# 开始监控
diagnoser.start_monitoring(interval=0.5)
# 运行负载测试
asyncio.run(diagnoser.measure_response_time(endpoint="/api/data", requests=500))
# 停止监控
diagnoser.stop_monitoring()
# 生成诊断报告
diagnoser.generate_diagnosis_report()
7. 完整性能优化工作流
# performance_optimization_workflow.py - MonkeyCode生成
"""
完整的性能优化工作流:
1. 基准测试(建立基线)
2. Profiling(定位瓶颈)
3. 优化(代码修改)
4. 回归测试(验证优化效果)
5. 部署(灰度发布)
"""
import json
import time
from typing import Callable, Any
import functools
class PerformanceOptimizationWorkflow:
"""性能优化工作流"""
def __init__(self, baseline_file: str = "performance_baseline.json"):
self.baseline_file = baseline_file
self.baseline = {}
self.load_baseline()
def load_baseline(self):
"""加载基线数据"""
try:
with open(self.baseline_file) as f:
self.baseline = json.load(f)
except FileNotFoundError:
print("No baseline found. Run baseline tests first.")
def save_baseline(self):
"""保存基线数据"""
with open(self.baseline_file, 'w') as f:
json.dump(self.baseline, f, indent=2)
print(f"Baseline saved to {self.baseline_file}")
def establish_baseline(self, func: Callable, *args, **kwargs):
"""建立性能基线"""
print(f"Establishing baseline for {func.__name__}")
# 运行多次取平均
times = []
for _ in range(100):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
times.append((end - start) * 1000)
avg_time = sum(times) / len(times)
self.baseline[func.__name__] = {
"avg_time_ms": avg_time,
"min_ms": min(times),
"max_ms": max(times),
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
}
print(f"Baseline established: {avg_time:.3f} ms")
self.save_baseline()
return result
def compare_with_baseline(self, func: Callable, *args, **kwargs):
"""与基线对比"""
if func.__name__ not in self.baseline:
print(f"No baseline found for {func.__name__}. Establishing baseline first.")
return self.establish_baseline(func, *args, **kwargs)
baseline_data = self.baseline[func.__name__]
baseline_time = baseline_data["avg_time_ms"]
# 测量当前性能
times = []
for _ in range(100):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
times.append((end - start) * 1000)
current_time = sum(times) / len(times)
# 对比
change_percent = ((current_time - baseline_time) / baseline_time) * 100
print(f"\n{'='*60}")
print(f"Performance Comparison: {func.__name__}")
print(f"{'='*60}")
print(f"Baseline: {baseline_time:.3f} ms")
print(f"Current: {current_time:.3f} ms")
print(f"Change: {change_percent:+.1f}%")
if change_percent > 5:
print(f"⚠️ Performance regression detected!")
elif change_percent < -5:
print(f"✅ Performance improvement: {-change_percent:.1f}% faster")
else:
print(f"✅ No significant change")
return result
def optimize_and_validate(self, original_func: Callable, optimized_func: Callable, *args, **kwargs):
"""优化并验证"""
print(f"\n{'='*60}")
print(f"Optimization Validation")
print(f"{'='*60}")
# 测试原始函数
print(f"\n1. Testing original function: {original_func.__name__}")
original_result = self.compare_with_baseline(original_func, *args, **kwargs)
# 测试优化后的函数
print(f"\n2. Testing optimized function: {optimized_func.__name__}")
optimized_result = self.compare_with_baseline(optimized_func, *args, **kwargs)
# 验证结果一致性
if original_result == optimized_result:
print(f"\n✅ Results match! Optimization is safe.")
else:
print(f"\n⚠️ Results don't match! Check optimization.")
print(f"Original: {original_result}")
print(f"Optimized: {optimized_result}")
return optimized_result
# 使用示例
def original_slow_function(data: list) -> list:
"""原始慢函数"""
result = []
for item in data:
if item % 2 == 0:
result.append(item ** 2)
return result
def optimized_fast_function(data: list) -> list:
"""优化后的快函数"""
return [item ** 2 for item in data if item % 2 == 0]
if __name__ == '__main__':
workflow = PerformanceOptimizationWorkflow()
test_data = list(range(10000))
# 建立基线
workflow.establish_baseline(original_slow_function, test_data)
# 对比优化效果
workflow.optimize_and_validate(
original_slow_function,
optimized_fast_function,
test_data
)
MonkeyCode生成的性能测试工具链覆盖了从基准测试到自动优化的完整流程。让AI写功能代码只是第一步,让AI帮你做性能测试才是完整的工作流。但性能优化需要理解业务场景,AI生成的Profiling代码是工具,瓶颈诊断还需要人工经验。

浙公网安备 33010602011771号