提交qiming-mcp-proxy
This commit is contained in:
66
qiming-mcp-proxy/mcp-proxy/benches/README.md
Normal file
66
qiming-mcp-proxy/mcp-proxy/benches/README.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# 性能基准测试
|
||||
|
||||
这个目录包含使用 Criterion.rs 对 `/api/run_code_with_log` 端点进行性能测试的代码。
|
||||
|
||||
## 可用的基准测试
|
||||
|
||||
1. `run_code_bench` - 基本性能测试,测试三种语言(JS、TS、Python)的简单脚本执行性能
|
||||
2. `run_code_advanced_bench` - 高级性能测试,测试多种场景、不同复杂度的脚本和参数组合
|
||||
|
||||
## 如何运行测试
|
||||
|
||||
使用以下命令运行基本测试:
|
||||
|
||||
```bash
|
||||
cargo bench --bench run_code_bench
|
||||
```
|
||||
|
||||
使用以下命令运行高级测试:
|
||||
|
||||
```bash
|
||||
cargo bench --bench run_code_advanced_bench
|
||||
```
|
||||
|
||||
运行特定的测试场景:
|
||||
|
||||
```bash
|
||||
cargo bench --bench run_code_advanced_bench -- js_basic
|
||||
```
|
||||
|
||||
## 查看测试结果
|
||||
|
||||
测试结果将保存在 `target/criterion` 目录下,你可以在浏览器中打开 HTML 报告查看详细的结果:
|
||||
|
||||
```bash
|
||||
open target/criterion/report/index.html
|
||||
```
|
||||
|
||||
## 配置测试参数
|
||||
|
||||
在基准测试文件中可以修改以下参数,以适应不同性能的机器:
|
||||
|
||||
- `sample_size`: 每个测试场景运行的样本数量(默认为10)
|
||||
- `warm_up_time`: 预热时间(默认为20秒)
|
||||
- `measurement_time`: 测量时间(默认为10秒)
|
||||
- `significance_level`: 统计显著性水平(默认为0.05,即5%)
|
||||
|
||||
如果在较慢的机器上运行,可能需要进一步减少样本数或增加测量时间。可以通过命令行参数指定:
|
||||
|
||||
```bash
|
||||
# 使用命令行参数减少样本数
|
||||
cargo bench --bench run_code_bench -- --sample-size 5
|
||||
|
||||
# 使用命令行参数增加预热时间
|
||||
cargo bench --bench run_code_bench -- --warm-up-time 30
|
||||
|
||||
# 使用命令行参数增加测量时间
|
||||
cargo bench --bench run_code_bench -- --measurement-time 15
|
||||
```
|
||||
|
||||
## 测试脚本说明
|
||||
|
||||
测试使用了 `fixtures` 目录下的各种测试脚本:
|
||||
|
||||
- `test_js.js`、`test_ts.ts`、`test_python_simple.py` - 基本语言测试脚本
|
||||
- `test_js_params.js`、`test_ts_params.ts`、`test_python_params.py` - 带参数的测试脚本
|
||||
- `import_lodash_example.js`、`test_python_logging.py` - 复杂功能测试脚本
|
||||
195
qiming-mcp-proxy/mcp-proxy/benches/run_code_advanced_bench.rs
Normal file
195
qiming-mcp-proxy/mcp-proxy/benches/run_code_advanced_bench.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
|
||||
use mcp_stdio_proxy::{RunCodeMessageRequest, run_code_handler};
|
||||
use serde_json::json;
|
||||
use std::{collections::HashMap, fs};
|
||||
use tokio::runtime::Runtime;
|
||||
use uuid::Uuid;
|
||||
|
||||
// 测试脚本类型
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum ScriptType {
|
||||
Js,
|
||||
Ts,
|
||||
Python,
|
||||
}
|
||||
|
||||
// 测试场景
|
||||
#[allow(dead_code)]
|
||||
struct TestScenario {
|
||||
name: &'static str,
|
||||
file_path: &'static str,
|
||||
script_type: ScriptType,
|
||||
description: &'static str,
|
||||
}
|
||||
|
||||
// 获取所有测试场景
|
||||
fn get_test_scenarios() -> Vec<TestScenario> {
|
||||
vec![
|
||||
// 基本测试场景
|
||||
TestScenario {
|
||||
name: "js_basic",
|
||||
file_path: "fixtures/test_js.js",
|
||||
script_type: ScriptType::Js,
|
||||
description: "基本JavaScript执行",
|
||||
},
|
||||
TestScenario {
|
||||
name: "ts_basic",
|
||||
file_path: "fixtures/test_ts.ts",
|
||||
script_type: ScriptType::Ts,
|
||||
description: "基本TypeScript执行",
|
||||
},
|
||||
TestScenario {
|
||||
name: "python_basic",
|
||||
file_path: "fixtures/test_python_simple.py",
|
||||
script_type: ScriptType::Python,
|
||||
description: "基本Python执行",
|
||||
},
|
||||
// 参数传递测试场景
|
||||
TestScenario {
|
||||
name: "js_params",
|
||||
file_path: "fixtures/test_js_params.js",
|
||||
script_type: ScriptType::Js,
|
||||
description: "带参数的JavaScript执行",
|
||||
},
|
||||
TestScenario {
|
||||
name: "ts_params",
|
||||
file_path: "fixtures/test_ts_params.ts",
|
||||
script_type: ScriptType::Ts,
|
||||
description: "带参数的TypeScript执行",
|
||||
},
|
||||
TestScenario {
|
||||
name: "python_params",
|
||||
file_path: "fixtures/test_python_params.py",
|
||||
script_type: ScriptType::Python,
|
||||
description: "带参数的Python执行",
|
||||
},
|
||||
// 复杂测试场景
|
||||
TestScenario {
|
||||
name: "js_import",
|
||||
file_path: "fixtures/import_lodash_example.js",
|
||||
script_type: ScriptType::Js,
|
||||
description: "导入lodash的JavaScript执行",
|
||||
},
|
||||
TestScenario {
|
||||
name: "python_logging",
|
||||
file_path: "fixtures/test_python_logging.py",
|
||||
script_type: ScriptType::Python,
|
||||
description: "使用logging的Python执行",
|
||||
},
|
||||
TestScenario {
|
||||
name: "ts_complex",
|
||||
file_path: "fixtures/test_ts.ts",
|
||||
script_type: ScriptType::Ts,
|
||||
description: "复杂TypeScript执行",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// 读取测试脚本文件
|
||||
fn read_script_file(file_path: &str) -> String {
|
||||
fs::read_to_string(file_path).unwrap_or_else(|_| panic!("无法读取文件: {file_path}"))
|
||||
}
|
||||
|
||||
// 创建运行代码请求
|
||||
fn create_run_code_request(
|
||||
code: &str,
|
||||
script_type: ScriptType,
|
||||
with_complex_params: bool,
|
||||
) -> RunCodeMessageRequest {
|
||||
let mut json_param = HashMap::new();
|
||||
|
||||
if with_complex_params {
|
||||
// 创建复杂参数
|
||||
json_param.insert("input".to_string(), json!("测试输入"));
|
||||
json_param.insert("number".to_string(), json!(42));
|
||||
json_param.insert("boolean".to_string(), json!(true));
|
||||
json_param.insert("array".to_string(), json!([1, 2, 3, 4, 5]));
|
||||
json_param.insert(
|
||||
"object".to_string(),
|
||||
json!({
|
||||
"name": "测试对象",
|
||||
"properties": {
|
||||
"a": 1,
|
||||
"b": "string",
|
||||
"c": [true, false]
|
||||
}
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
// 创建简单参数
|
||||
json_param.insert("input".to_string(), json!("测试输入"));
|
||||
}
|
||||
|
||||
RunCodeMessageRequest {
|
||||
json_param,
|
||||
code: code.to_string(),
|
||||
uid: Uuid::new_v4().to_string(),
|
||||
engine_type: match script_type {
|
||||
ScriptType::Js => "js".to_string(),
|
||||
ScriptType::Ts => "ts".to_string(),
|
||||
ScriptType::Python => "python".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 设置基准测试
|
||||
fn bench_run_code_advanced(c: &mut Criterion) {
|
||||
// 创建测试组
|
||||
let mut group = c.benchmark_group("run_code_handler_advanced");
|
||||
|
||||
// 设置采样大小和预热次数
|
||||
group.sample_size(10); // 减少到10次取平均值
|
||||
group.warm_up_time(std::time::Duration::from_secs(20)); // 20秒预热时间
|
||||
group.measurement_time(std::time::Duration::from_secs(10)); // 10秒测量时间
|
||||
|
||||
// 获取所有测试场景
|
||||
let scenarios = get_test_scenarios();
|
||||
|
||||
// 创建tokio运行时
|
||||
let rt = Runtime::new().unwrap();
|
||||
|
||||
// 遍历测试场景
|
||||
for scenario in scenarios {
|
||||
// 读取脚本内容
|
||||
let code = read_script_file(scenario.file_path);
|
||||
|
||||
// 设置吞吐量计数为脚本字节大小
|
||||
// 这样可以比较不同大小脚本的执行效率
|
||||
group.throughput(Throughput::Bytes(code.len() as u64));
|
||||
|
||||
// 测试使用简单参数
|
||||
group.bench_function(
|
||||
BenchmarkId::new(format!("{}_simple", scenario.name), "simple_params"),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
let req = create_run_code_request(&code, scenario.script_type, false);
|
||||
rt.block_on(async { run_code_handler(axum::Json(req)).await.unwrap() })
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// 测试使用复杂参数
|
||||
group.bench_function(
|
||||
BenchmarkId::new(format!("{}_complex", scenario.name), "complex_params"),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
let req = create_run_code_request(&code, scenario.script_type, true);
|
||||
rt.block_on(async { run_code_handler(axum::Json(req)).await.unwrap() })
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
name = benches;
|
||||
config = Criterion::default()
|
||||
.significance_level(0.05) // 设置显著性水平为5%
|
||||
.sample_size(10) // 设置样本大小为10
|
||||
.warm_up_time(std::time::Duration::from_secs(20)) // 20秒预热时间
|
||||
.measurement_time(std::time::Duration::from_secs(10)); // 10秒测量时间
|
||||
targets = bench_run_code_advanced
|
||||
);
|
||||
criterion_main!(benches);
|
||||
90
qiming-mcp-proxy/mcp-proxy/benches/run_code_bench.rs
Normal file
90
qiming-mcp-proxy/mcp-proxy/benches/run_code_bench.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
|
||||
use mcp_stdio_proxy::{RunCodeMessageRequest, run_code_handler};
|
||||
use serde_json::json;
|
||||
use std::{collections::HashMap, fs};
|
||||
use tokio::runtime::Runtime;
|
||||
use uuid::Uuid;
|
||||
|
||||
// 测试脚本类型枚举
|
||||
enum ScriptType {
|
||||
Js,
|
||||
Ts,
|
||||
Python,
|
||||
}
|
||||
|
||||
// 读取测试脚本文件
|
||||
fn read_script_file(file_path: &str) -> String {
|
||||
fs::read_to_string(file_path).unwrap_or_else(|_| panic!("无法读取文件: {file_path}"))
|
||||
}
|
||||
|
||||
// 创建运行代码请求
|
||||
fn create_run_code_request(code: &str, script_type: ScriptType) -> RunCodeMessageRequest {
|
||||
let mut json_param = HashMap::new();
|
||||
json_param.insert("input".to_string(), json!("测试输入"));
|
||||
|
||||
RunCodeMessageRequest {
|
||||
json_param,
|
||||
code: code.to_string(),
|
||||
uid: Uuid::new_v4().to_string(),
|
||||
engine_type: match script_type {
|
||||
ScriptType::Js => "js".to_string(),
|
||||
ScriptType::Ts => "ts".to_string(),
|
||||
ScriptType::Python => "python".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 设置基准测试
|
||||
fn bench_run_code(c: &mut Criterion) {
|
||||
// 创建测试组
|
||||
let mut group = c.benchmark_group("run_code_handler");
|
||||
|
||||
// 设置采样配置
|
||||
group.sample_size(10); // 减少样本数量
|
||||
group.warm_up_time(std::time::Duration::from_secs(20)); // 增加预热时间为20秒
|
||||
group.measurement_time(std::time::Duration::from_secs(10)); // 增加测量时间
|
||||
|
||||
// 加载测试脚本
|
||||
let js_code = read_script_file("fixtures/test_js.js");
|
||||
let ts_code = read_script_file("fixtures/test_ts.ts");
|
||||
let py_code = read_script_file("fixtures/test_python_simple.py");
|
||||
|
||||
// 创建运行时
|
||||
let rt = Runtime::new().unwrap();
|
||||
|
||||
// 测试JS代码执行性能
|
||||
group.bench_function(BenchmarkId::new("javascript", "test_js.js"), |b| {
|
||||
b.iter(|| {
|
||||
let req = create_run_code_request(&js_code, ScriptType::Js);
|
||||
rt.block_on(async { run_code_handler(axum::Json(req)).await.unwrap() })
|
||||
});
|
||||
});
|
||||
|
||||
// 测试TS代码执行性能
|
||||
group.bench_function(BenchmarkId::new("typescript", "test_ts.ts"), |b| {
|
||||
b.iter(|| {
|
||||
let req = create_run_code_request(&ts_code, ScriptType::Ts);
|
||||
rt.block_on(async { run_code_handler(axum::Json(req)).await.unwrap() })
|
||||
});
|
||||
});
|
||||
|
||||
// 测试Python代码执行性能
|
||||
group.bench_function(BenchmarkId::new("python", "test_python_simple.py"), |b| {
|
||||
b.iter(|| {
|
||||
let req = create_run_code_request(&py_code, ScriptType::Python);
|
||||
rt.block_on(async { run_code_handler(axum::Json(req)).await.unwrap() })
|
||||
});
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default()
|
||||
.sample_size(10) // 减少样本数量
|
||||
.warm_up_time(std::time::Duration::from_secs(20)) // 设置20秒的预热时间
|
||||
.measurement_time(std::time::Duration::from_secs(10)); // 设置更长的测量时间
|
||||
targets = bench_run_code
|
||||
}
|
||||
criterion_main!(benches);
|
||||
Reference in New Issue
Block a user