148 lines
6.1 KiB
Python
148 lines
6.1 KiB
Python
"""
|
||
验证工程满足1553B 6-12us 响应、同时支持 10 个单机接入、CAN/1553B 消息顺序发送的性能需求,在test/下创建test_udp_performance.py
|
||
2026/2/26
|
||
Tan Mingyan
|
||
"""
|
||
|
||
|
||
import socket
|
||
import binascii
|
||
import time
|
||
import threading
|
||
from midware.config.base_config import DEVICE_CONFIG_DICT, UDP_CONFIG
|
||
|
||
# 全局配置
|
||
LOCAL_IP = UDP_CONFIG["LOCAL_IP"]
|
||
FAULT_PORT = UDP_CONFIG["FAULT_INJECT_PORT"]
|
||
BUFFER_SIZE = 4096
|
||
# 测试用1553B外设端口(取CSV中的1553B0/1553B1,如8882/8886)
|
||
B1553B_PORTS = [dev_info["udp_port"] for dev_name, dev_info in DEVICE_CONFIG_DICT.items() if dev_info["protocol"] == "1553B"]
|
||
# CAN外设端口
|
||
CAN_PORTS = [dev_info["udp_port"] for dev_name, dev_info in DEVICE_CONFIG_DICT.items() if dev_info["protocol"] == "CAN"]
|
||
# 10个测试端口(覆盖所有协议)
|
||
TEST_PORTS = [dev_info["udp_port"] for dev_name, dev_info in DEVICE_CONFIG_DICT.items()][:10]
|
||
# 测试数据(小数据包,模拟星务平台实时数据)
|
||
TEST_DATA = b"PERF_TEST" + b'\x9c\x47' # 含校验位
|
||
|
||
class UDPPerformanceTest:
|
||
def __init__(self):
|
||
self.send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||
self.send_sock.setblocking(False)
|
||
# 接收套接字(统计回传时延)
|
||
self.recv_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||
self.recv_sock.bind((LOCAL_IP, FAULT_PORT))
|
||
self.recv_sock.setblocking(False)
|
||
# 时延统计
|
||
self.latency_list = []
|
||
# 并发计数
|
||
self.send_count = 0
|
||
self.recv_count = 0
|
||
|
||
def _calc_latency(self, port, send_ts):
|
||
"""计算单包时延:发送时间→接收回传时间"""
|
||
try:
|
||
data, _ = self.recv_sock.recvfrom(BUFFER_SIZE)
|
||
recv_ts = time.time()
|
||
latency = (recv_ts - send_ts) * 1000000 # 转换为微秒(us)
|
||
self.latency_list.append(latency)
|
||
self.recv_count += 1
|
||
print(f"1553B端口{port} | 响应时延:{latency:.2f}us | 累计接收:{self.recv_count}")
|
||
except:
|
||
pass
|
||
|
||
def test_1553b_latency(self, test_times=1000):
|
||
"""测试1553B响应时延(要求6-12us),发送test_times次数据包"""
|
||
if not B1553B_PORTS:
|
||
print("❌ 未配置1553B外设,跳过时延测试")
|
||
return
|
||
test_port = B1553B_PORTS[0]
|
||
print(f"===== 1553B时延测试(端口{test_port},发送{test_times}次) =====")
|
||
self.latency_list.clear()
|
||
self.recv_count = 0
|
||
|
||
for i in range(test_times):
|
||
send_ts = time.time()
|
||
# 发送数据
|
||
hex_data = binascii.hexlify(TEST_DATA).decode("utf-8")
|
||
self.send_sock.sendto(hex_data.encode("utf-8"), (LOCAL_IP, test_port))
|
||
# 立即统计时延(模拟中间层实时回传)
|
||
self._calc_latency(test_port, send_ts)
|
||
# 微秒级间隔,模拟星务平台请求频率
|
||
time.sleep(0.000001)
|
||
|
||
# 统计结果
|
||
if self.latency_list:
|
||
avg_latency = sum(self.latency_list) / len(self.latency_list)
|
||
min_latency = min(self.latency_list)
|
||
max_latency = max(self.latency_list)
|
||
print(f"\n1553B时延统计 | 平均:{avg_latency:.2f}us | 最小:{min_latency:.2f}us | 最大:{max_latency:.2f}us")
|
||
if avg_latency >=6 and avg_latency <=12:
|
||
print("✅ 1553B时延满足要求(6-12us)")
|
||
else:
|
||
print("❌ 1553B时延不满足要求")
|
||
|
||
def test_10_device_concurrent(self, test_times=500):
|
||
"""测试10个单机并发接入(同时发送,验证无丢包)"""
|
||
if len(TEST_PORTS) <10:
|
||
print("❌ 未配置10个外设,跳过多机并发测试")
|
||
return
|
||
print(f"===== 10机并发测试(发送{test_times}次/机) =====")
|
||
self.send_count = 0
|
||
self.recv_count = 0
|
||
|
||
def send_task(port):
|
||
for _ in range(test_times):
|
||
hex_data = binascii.hexlify(TEST_DATA).decode("utf-8")
|
||
self.send_sock.sendto(hex_data.encode("utf-8"), (LOCAL_IP, port))
|
||
self.send_count +=1
|
||
time.sleep(0.0001)
|
||
|
||
# 启动10个线程,对应10个外设
|
||
threads = [threading.Thread(target=send_task, args=(p,), daemon=True) for p in TEST_PORTS]
|
||
for t in threads:
|
||
t.start()
|
||
for t in threads:
|
||
t.join()
|
||
|
||
# 等待接收完成
|
||
time.sleep(2)
|
||
loss_rate = (self.send_count - self.recv_count) / self.send_count * 100
|
||
print(f"总发送:{self.send_count} | 总接收:{self.recv_count} | 丢包率:{loss_rate:.2f}%")
|
||
if loss_rate == 0:
|
||
print("✅ 10机并发测试通过,无丢包")
|
||
else:
|
||
print("❌ 10机并发测试失败,存在丢包")
|
||
|
||
def test_can_b1553b_order(self):
|
||
"""测试CAN/1553B消息顺序发送(要求一个节点发完再发下一个)"""
|
||
print("===== CAN/1553B消息顺序测试 =====")
|
||
# 按顺序发送多个节点数据,查看中间层日志
|
||
test_ports = CAN_PORTS[:2] + B1553B_PORTS[:2]
|
||
for port in test_ports:
|
||
hex_data = binascii.hexlify(TEST_DATA + str(port).encode()).decode("utf-8")
|
||
self.send_sock.sendto(hex_data.encode("utf-8"), (LOCAL_IP, port))
|
||
print(f"按顺序发送:端口{port} 数据标识:{port}")
|
||
time.sleep(0.001)
|
||
print("✅ 请查看工程logs/run_*.log,验证日志中节点数据是否按发送顺序打印(无乱序)")
|
||
|
||
def close(self):
|
||
self.send_sock.close()
|
||
self.recv_sock.close()
|
||
|
||
if __name__ == "__main__":
|
||
perf_test = UDPPerformanceTest()
|
||
try:
|
||
# 1. 1553B时延测试(发送1000次)
|
||
perf_test.test_1553b_latency(test_times=1000)
|
||
time.sleep(3)
|
||
|
||
# 2. 10机并发测试(每机发送500次)
|
||
perf_test.test_10_device_concurrent(test_times=500)
|
||
time.sleep(3)
|
||
|
||
# 3. CAN/1553B消息顺序测试
|
||
perf_test.test_can_b1553b_order()
|
||
except KeyboardInterrupt:
|
||
print("\n用户终止性能测试")
|
||
finally:
|
||
perf_test.close() |