data: publish complete Calculet NPU research archive

This commit is contained in:
2026-08-02 14:57:11 +08:00
parent b5c4fbffab
commit 98e6cadcb6
12400 changed files with 6166642 additions and 0 deletions
@@ -0,0 +1,339 @@
#!/usr/bin/env python3
import subprocess
import time
import requests
import json
import os
import sys
import argparse
from datetime import datetime
import csv
import random
# 配置常量
LOG_FILE = "llama_perf_logs.csv"
CONTENT_FILE = "llama_content_logs.csv"
MAX_RETRIES = 10
RETRY_DELAY = 15
def init_log_file():
"""初始化日志文件,写入CSV表头(如果文件不存在)"""
if not os.path.exists(LOG_FILE):
with open(LOG_FILE, "w") as f:
f.write("timestamp,model,prompt_tokens,completion_tokens,memory_usage,Decode_TPS,TTFT,Prefill_TPS,Power\n")
print(f"Initialized log file: {LOG_FILE}")
if not os.path.exists(CONTENT_FILE):
with open(CONTENT_FILE, "w") as f:
f.write("timestamp,model,prompt,content\n")
print(f"Initialized content file: {CONTENT_FILE}")
def load_test_cases(test_file):
"""从JSON文件加载测试用例"""
try:
with open(test_file, 'r', encoding='utf-8') as f:
data = json.load(f)
meta = data.get("meta_info", {})
test_cases = data.get("test_cases", [])
print(f"filename: {test_file}")
print(f"version: {meta.get('version', 'N/A')}")
print(f"find {len(test_cases)} test cases")
return test_cases
except FileNotFoundError:
print(f"error: file not found {test_file}")
sys.exit(1)
except json.JSONDecodeError as e:
print(f"error: JSON decode failed - {e}")
sys.exit(1)
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"-t", "--test_path",
required=True,
help="Path to test case JSON file"
)
parser.add_argument("--host", default="127.0.0.1", help="Server host")
parser.add_argument("--port", type=int, default=8080, help="Server port")
parser.add_argument(
"--loop-forever",
action="store_true",
help="Run test cases repeatedly until interrupted"
)
parser.add_argument(
"--interval",
type=float,
default=0.0,
help="Seconds to sleep between test cases"
)
return parser.parse_args()
def start_server(server_path, model_path, case_path, port):
"""启动llama-server进程,返回subprocess.Popen对象"""
cmd = ["sudo", server_path, "-m", str(model_path), "--case", str(case_path), "--port", str(port), "-np", str(1), "--verbose", "--no-warmup"]
print(f"Start server: {' '.join(cmd)}")
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(1) # 稍等片刻让进程启动
return process
def health_check(HEALTH_URL):
"""健康检查,重试直到服务就绪或超时"""
for i in range(1, MAX_RETRIES + 1):
try:
response = requests.get(HEALTH_URL, timeout=15)
if response.status_code == 200:
print(f"✔ llama-server is ready (attempt {i}/{MAX_RETRIES})")
return True
except requests.exceptions.RequestException as e:
pass # 忽略连接错误
print(f"Waiting for service to be ready (attempt {i}/{MAX_RETRIES},retry in {RETRY_DELAY}s)...")
time.sleep(RETRY_DELAY)
print("✘ llama-server startup timed out")
return False
def extract_stream_parts(chunk):
choices = chunk.get("choices", [])
if not choices:
return "", ""
c0 = choices[0]
delta = c0.get("delta", {}) or {}
think_piece = delta.get("reasoning_content", "") or ""
answer_piece = delta.get("content", "") or ""
# 兼容部分服务端在非 delta 里返回
if not think_piece and not answer_piece:
msg = c0.get("message", {}) or {}
think_piece = msg.get("reasoning_content", "") or ""
answer_piece = msg.get("content", "") or c0.get("text", "") or ""
return think_piece, answer_piece
def send_request(test_case, API_URL):
model = "deepseek"
test_id = test_case.get("id", "unknown")
prompt = test_case.get("prompt", "")
if not prompt:
return {"error": f"prompt {test_id} is null, skip"}
request_body = {
"model": model,
"messages": [{"role": "user", "content": prompt}],
"stream": True
}
print("Prompt:")
print(prompt)
print("Response(stream):")
think_parts = []
answer_parts = []
think_opened = False
answer_opened = False
usage = {}
timings = {}
try:
with requests.post(API_URL, json=request_body, stream=True, timeout=150) as response:
response.raise_for_status()
response.encoding = "utf-8"
for raw_line in response.iter_lines(decode_unicode=False):
if not raw_line:
continue
line = raw_line.decode("utf-8", errors="replace")
if not line.startswith("data:"):
continue
payload = line[5:].strip()
if not payload:
continue
if payload == "[DONE]":
break
try:
chunk = json.loads(payload)
except json.JSONDecodeError:
continue
think_piece, answer_piece = extract_stream_parts(chunk)
if think_piece:
if not think_opened:
print("[THINK] ", end="", flush=True)
think_opened = True
print(think_piece, end="", flush=True)
think_parts.append(think_piece)
if answer_piece:
if not answer_opened:
if think_opened:
print("\n[ANSWER] ", end="", flush=True)
else:
print("[ANSWER] ", end="", flush=True)
answer_opened = True
print(answer_piece, end="", flush=True)
answer_parts.append(answer_piece)
if "usage" in chunk and isinstance(chunk["usage"], dict):
usage = chunk["usage"]
if "timings" in chunk and isinstance(chunk["timings"], dict):
timings = chunk["timings"]
print()
except requests.exceptions.Timeout:
return {"error": f"test case {test_id} timed out"}
except requests.exceptions.RequestException as e:
return {"error": f"Request failed: {e}"}
think_content = "".join(think_parts)
content = "".join(answer_parts)
prompt_tokens = usage.get("prompt_tokens", 0)
completion_tokens = usage.get("completion_tokens", 0)
decode_tps = timings.get("predicted_per_second", 0.0)
predicted_ms = timings.get("predicted_ms", 0.0)
prompt_ms = timings.get("prompt_ms", 0.0)
ttft = predicted_ms + prompt_ms
prefill_tps = timings.get("prompt_per_second", 0.0)
return {
"prompt_tokens": prompt_tokens,
"completion_tokens": completion_tokens,
"memory_usage": 0,
"decode_tps": decode_tps,
"ttft": ttft,
"prefill_tps": prefill_tps,
"Power": 0,
"prompt": prompt,
"think_content": think_content,
"content": content,
"model": model
}
def print_metrics(round_id, i, total, metrics):
print("\n" + "=" * 80)
print(f"[Round {round_id} | {i}/{total}]")
print(
f"prompt_tokens={metrics['prompt_tokens']}, "
f"completion_tokens={metrics['completion_tokens']}, "
f"decode_tps={metrics['decode_tps']:.2f}, "
f"ttft={metrics['ttft']:.2f} ms, "
f"prefill_tps={metrics['prefill_tps']:.2f}"
)
print("=" * 80)
def log_data(metrics):
"""记录数据到CSV文件"""
if metrics is None:
print("No valid data, skipping logging")
return
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(LOG_FILE, "a", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow([
timestamp,
metrics["model"],
metrics["prompt_tokens"],
metrics["completion_tokens"],
f"{metrics['memory_usage']:.2f}",
f"{metrics['decode_tps']:.2f}",
f"{metrics['ttft']:.2f}",
f"{metrics['prefill_tps']:.2f}",
f"{metrics['Power']:.1f}",
])
with open(CONTENT_FILE, "a", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow([
timestamp,
metrics["model"],
metrics["prompt"],
metrics["content"],
])
def main():
"""主函数,执行完整流程"""
print("=== Starting llama-server test ===")
server_process = None
try:
args = parse_args()
# 1. 初始化日志文件,加载json测试集
init_log_file()
test_cases = load_test_cases(args.test_path)
if not test_cases:
print("error:load test_cases failed")
sys.exit(1)
HEALTH_URL = f"http://{args.host}:{args.port}/health"
API_URL = f"http://{args.host}:{args.port}/v1/chat/completions"
# server_process = start_server(args.server_path, MODEL_PATH, CALBIN_PATH, PORT)
# 3. 健康检查
if not health_check(HEALTH_URL):
raise RuntimeError("Health check failed")
round_id = 0
while True:
round_id += 1
successful_tests = 0
# 每轮发送次数,默认=测试集大小;可按需改成固定值
sample_count = len(test_cases)
print(f"\n=== Round {round_id} start: {sample_count} samples (with replacement) ===")
for i in range(1, sample_count + 1):
test_case = random.choice(test_cases) # 有放回抽样,允许重复
print(f"\n[Round {round_id} | Progress: {i}/{sample_count}]")
metrics = send_request(test_case, API_URL)
if not metrics or "error" in metrics:
err = metrics["error"] if isinstance(metrics, dict) and "error" in metrics else "unknown error"
print(f"[Round {round_id} | {i}/{sample_count}] ERROR: {err}")
else:
print_metrics(round_id, i, sample_count, metrics)
log_data(metrics)
successful_tests += 1
if args.interval > 0 and i < sample_count:
time.sleep(args.interval)
print(f"=== Round {round_id} done: {successful_tests}/{sample_count} success ===")
if not args.loop_forever:
break
except KeyboardInterrupt:
print("\nInterrupted by user, stopping stress test...")
except Exception as e:
print(f"✘ Test failed: {e}")
sys.exit(1)
finally:
# 6. 停止服务器进程
if server_process and server_process.poll() is None: # 检查进程是否仍在运行
server_process.terminate()
try:
server_process.wait(timeout=5)
print("✔ Test completed")
except subprocess.TimeoutExpired:
server_process.kill()
print("✔ Test completed")
sys.exit(0)
if __name__ == "__main__":
main()