diff --git a/API.md b/API.md
index 53c7374..c797f2e 100644
--- a/API.md
+++ b/API.md
@@ -114,11 +114,12 @@
},
"gen": {
"name": "Qwen3 不同上下文长度速度对比",
- "context_lengths": [512, 2048, 4096, 8192, 16384, 32768, 65536, 131072],
+ "context_lengths": [4096, 8192, 16384, 32768, 65536, 98304, 131072],
"max_tokens": 128,
"samples": 2,
"warmup": true,
- "avoid_cache": true
+ "avoid_cache": true,
+ "interval": 5
}
}
```
@@ -128,12 +129,13 @@
| 字段 | 类型 | 默认 | 说明 |
|------|------|------|------|
| `name` | string | `""` | 测试名称/主题(会存入测试记录并展示在历史与详情) |
-| `context_lengths` | number[] | `[512,2048,4096,8192,16384,32768,65536,131072]` | 要测试的上下文长度列表,每个长度独立校准+预热+采样 |
+| `context_lengths` | number[] | `[4096,8192,16384,32768,65536,98304,131072]` | 要测试的上下文长度列表,每个长度独立校准+预热+采样 |
| `max_tokens` | number | `128` | 解码输出 token 长度 |
| `samples` | number | `2` | 每个(长度×并发)组合的采样次数 |
| `concurrency_levels` | number[] | `[1]` | 并发数列表(默认单流)。>1 时每采样同时发起 N 个并行流,聚合为整批吞吐指标;多档自动并排对比 |
| `warmup` | bool | `true` | 测试前空转预热(不计速度,按并发数预热) |
| `avoid_cache` | bool | `true` | 随机前缀避免缓存命中(每个并发流独立前缀) |
+| `interval` | number | `5` | 每次采样之间的间隔秒数,让接口空闲休息(0 表示不等待) |
**响应:** `{ "ok": true, "id": 9 }`
diff --git a/static/index.html b/static/index.html
index 86d6b82..0a3a5a8 100644
--- a/static/index.html
+++ b/static/index.html
@@ -130,6 +130,11 @@
⏱
连接测试与速度采样共用:超过此时长仍未收到数据才判定超时(默认 1800 秒 = 30 分钟)。测慢接口/超长上下文时建议调大,如 3600。
+
+
+
⏳
+
每次采样完成后等待 N 秒再发下一次请求,让大模型接口空闲休息一下(默认 5 秒,设为 0 关闭)。
+
diff --git a/static/js/app.js b/static/js/app.js
index 8e4b1a7..beb7696 100644
--- a/static/js/app.js
+++ b/static/js/app.js
@@ -71,6 +71,7 @@ function currentGen() {
avoid_cache: $("#gen-avoid-cache").checked,
warmup: $("#gen-warmup").checked,
read_timeout: parseInt($("#gen-timeout").value) || 1800,
+ interval: Math.max(0, parseInt($("#gen-interval").value) || 5),
};
}
diff --git a/tester.py b/tester.py
index 82bb06c..0a66232 100644
--- a/tester.py
+++ b/tester.py
@@ -32,6 +32,15 @@ class TestRunner(threading.Thread):
def log(self, level, msg):
db.add_log(self.test_id, level, msg)
+ def _sleep_interval(self, secs):
+ """测试间隔等待:期间可被用户停止,返回 False 表示已被取消"""
+ deadline = time.time() + secs
+ while time.time() < deadline:
+ if self.should_stop():
+ return False
+ time.sleep(0.2)
+ return not self.should_stop()
+
# ───────────────────────── 主流程 ─────────────────────────
def run(self):
@@ -61,6 +70,11 @@ class TestRunner(threading.Thread):
max_tokens = max(1, int(gen.get("max_tokens", 128))) # 解码输出长度
avoid_cache = bool(gen.get("avoid_cache"))
warmup = bool(gen.get("warmup", True)) # 测试前空转预热
+ # 测试间隔(秒):每次采样之间让接口空闲休息,默认 5 秒,0 表示不等待
+ try:
+ interval = 5 if gen.get("interval") in (None, "") else max(0, float(gen.get("interval")))
+ except (TypeError, ValueError):
+ interval = 5
# 并发数列表(默认单流 [1];支持 2/4 及自定义,如 [1,2,4,8])
raw_concs = gen.get("concurrency_levels") or []
@@ -73,10 +87,10 @@ class TestRunner(threading.Thread):
if name:
self.log("INFO", "测试名称(主题): %s" % name)
self.log("INFO", "提供商: %s | 模型: %s" % (lp.PROVIDER_LABELS.get(provider, provider), model))
- self.log("INFO", "上下文长度: %s tokens | 生成长度: %d tokens | 并发数: %s | 每个组合采样: %d 次 | 预热: %s | 避免缓存: %s"
+ self.log("INFO", "上下文长度: %s tokens | 生成长度: %d tokens | 并发数: %s | 每个组合采样: %d 次 | 预热: %s | 避免缓存: %s | 测试间隔: %g 秒"
% (" / ".join(str(x) for x in lengths), max_tokens,
" / ".join(str(x) for x in concurrency_levels), n,
- "开" if warmup else "关", "开" if avoid_cache else "关"))
+ "开" if warmup else "关", "开" if avoid_cache else "关", interval))
to = self.gen.get("read_timeout") or "默认(1800)"
self.log("INFO", "请求超时: 连接 %s s | 等待首字/预处理 %s s(接口慢可在左侧调大)"
% (self.gen.get("connect_timeout") or 60, to))
@@ -86,6 +100,7 @@ class TestRunner(threading.Thread):
self.log("INFO", "校准完成: %.3f tok/字符(%.2f 字符/token)" % (ratio, 1.0 / ratio))
run_seq = 0
+ sample_done = 0 # 已完成的采样数,用于控制测试间隔(首个采样不等待)
last_conc = None # 只在实际切换并发档时打印一次表头,避免同一并发数重复刷屏
for L in lengths:
if self.should_stop():
@@ -103,7 +118,12 @@ class TestRunner(threading.Thread):
for i in range(1, n + 1):
if self.should_stop():
raise StopRequested()
+ if sample_done > 0 and interval > 0:
+ self.log("INFO", "⏳ 接口空闲休息 %g 秒后继续下一采样..." % interval)
+ if not self._sleep_interval(interval):
+ raise StopRequested()
run_seq += 1
+ sample_done += 1
self.log("INFO", "── [%d tok · 并发%d] 采样 %d/%d 开始 ──" % (L, C, i, n))
try:
m = self._run_sample(C, base_prompt, max_tokens, avoid_cache)