Files
AI-tianyan/bench_npu.py

150 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
昇腾 310B4 NPU 推理性能基准测试
测试项目:
1. 确认 NPU 推理(非 CPU fallback
2. 单次推理延迟
3. 连续推理吞吐 (FPS)
4. 多 worker 并发
5. 不同分辨率影响
"""
import os
import sys
import time
import socket
import struct
import json
import base64
import threading
import numpy as np
import cv2
from concurrent.futures import ThreadPoolExecutor
SOCK_PATH = "/tmp/edge-infer.sock"
def make_test_image(w=640, h=640):
"""生成随机测试图片"""
img = np.random.randint(0, 255, (h, w, 3), dtype=np.uint8)
_, buf = cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 90])
return buf.tobytes()
def infer_one(jpeg_bytes):
"""发送一次推理请求,返回响应时间(ms)"""
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(SOCK_PATH)
msg = {
"stream_id": 0,
"device_id": "bench",
"url": "bench://test",
"ts": 1234567890.0,
"jpeg_b64": base64.b64encode(jpeg_bytes).decode("utf-8")
}
data = json.dumps(msg).encode("utf-8")
t0 = time.time()
sock.sendall(struct.pack(">I", len(data)) + data)
hdr = sock.recv(4)
length = struct.unpack(">I", hdr)[0]
result = json.loads(sock.recv(length).decode("utf-8"))
elapsed = (time.time() - t0) * 1000 # ms
sock.close()
return elapsed, result
def test_single_infer():
"""单次推理延迟"""
print("\n=== 单次推理延迟测试 ===")
jpeg = make_test_image()
times = []
for i in range(5):
t, _ = infer_one(jpeg)
times.append(t)
print(f"{i+1} 次: {t:.1f} ms")
# 跳过第一次预热
times = times[1:]
avg = sum(times) / len(times)
print(f"\n 平均延迟 (排除预热): {avg:.1f} ms")
print(f" 理论 FPS: {1000/avg:.1f}")
return avg
def test_throughput():
"""连续推理吞吐"""
print("\n=== 连续推理吞吐测试 ===")
jpeg = make_test_image()
count = 30
t0 = time.time()
for i in range(count):
_, _ = infer_one(jpeg)
if (i+1) % 10 == 0:
elapsed = time.time() - t0
print(f" {i+1}/{count} 完成, 累计: {elapsed:.1f}s, FPS: {(i+1)/elapsed:.1f}")
total = time.time() - t0
fps = count / total
print(f"\n 总计 {count} 帧: {total:.2f}s")
print(f" 吞吐: {fps:.1f} FPS")
print(f" 每帧延迟: {total/count*1000:.1f} ms")
return fps
def test_concurrent(workers=4):
"""多 worker 并发推理"""
print(f"\n=== {workers} 路并发测试 ===")
jpeg = make_test_image()
results_per_worker = []
def worker_task(worker_id, n_frames=20):
times = []
for _ in range(n_frames):
t, _ = infer_one(jpeg)
times.append(t)
return worker_id, times
t0 = time.time()
with ThreadPoolExecutor(max_workers=workers) as pool:
futures = [pool.submit(worker_task, i, 15) for i in range(workers)]
for f in futures:
wid, times = f.result()
results_per_worker.append((wid, sum(times)/len(times), max(times), min(times)))
total = time.time() - t0
total_frames = workers * 15
total_fps = total_frames / total
for wid, avg, mx, mn in results_per_worker:
print(f" Worker {wid}: avg={avg:.1f}ms, max={mx:.1f}ms, min={mn:.1f}ms")
print(f"\n 并发 {workers} 路: 总计 {total_frames} 帧, {total:.2f}s")
print(f" 总吞吐: {total_fps:.1f} FPS")
print(f" 单路等效 FPS: {total_fps/workers:.1f}")
return total_fps
def test_power():
"""读取 NPU 功耗信息"""
import subprocess
try:
result = subprocess.run(['npu-smi', 'info'], capture_output=True, text=True, timeout=5)
print("\n=== NPU 状态 ===")
print(result.stdout)
except Exception as e:
print(f"无法读取 NPU 状态: {e}")
if __name__ == "__main__":
print("=" * 60)
print(" 昇腾 310B4 + ACL 原生推理 性能基准测试")
print("=" * 60)
test_power()
test_single_infer()
test_throughput()
test_concurrent(2)
test_concurrent(4)
test_concurrent(6)
print("\n" + "=" * 60)
print("测试完成")
print("=" * 60)