refactor: reorganize tests/tools, share python protocol helpers
Some checks failed
CI / test (push) Has been cancelled
Some checks failed
CI / test (push) Has been cancelled
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
pipeview-tauri 极限压力测试脚本
|
||||
pipeview GUI(egui)极限压力测试脚本
|
||||
|
||||
模拟各种高数据量场景,测试 Tauri 前端的渲染性能和稳定性:
|
||||
模拟各种高数据量场景,测试 pipeview GUI 的渲染性能和稳定性:
|
||||
- 文本洪水:大文本行 + ANSI 颜色
|
||||
- 十六进制洪水:大批量 hex dump
|
||||
- 波形洪水:高频 plot 采样点
|
||||
@@ -20,20 +20,11 @@ import argparse
|
||||
import math
|
||||
import random
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
PLOT_ESCAPE = 0x1E
|
||||
PLOT_MARKER = ord("P")
|
||||
|
||||
DISCONNECT_WINERRORS = {
|
||||
10053, # Software caused connection abort
|
||||
10054, # Connection reset by peer
|
||||
10058, # Socket shutdown race on Windows
|
||||
}
|
||||
import pv_protocol
|
||||
|
||||
# ── ANSI Color Palette ─────────────────────────────────────────────
|
||||
|
||||
@@ -108,57 +99,32 @@ def build_plot_frame(
|
||||
frequency_hz: float,
|
||||
sample_rate_hz: float,
|
||||
) -> bytes:
|
||||
"""Build a raw COBS-encoded plot frame (matching test_plot.py format)."""
|
||||
values = []
|
||||
if plot_format == "xy":
|
||||
for _ in range(samples_per_channel):
|
||||
t = (sample_index * samples_per_channel + len(values)) / sample_rate_hz
|
||||
values.append(amplitude * math.sin(2 * math.pi * frequency_hz * t))
|
||||
values.append(amplitude * math.cos(2 * math.pi * frequency_hz * t))
|
||||
elif plot_format == "block":
|
||||
for ch in range(channels):
|
||||
phase = 2 * math.pi * ch / channels
|
||||
for _ in range(samples_per_channel):
|
||||
t = (sample_index * samples_per_channel + len(values) // channels) / sample_rate_hz
|
||||
values.append(amplitude * math.sin(2 * math.pi * frequency_hz * t + phase))
|
||||
else: # interleaved
|
||||
for _ in range(samples_per_channel):
|
||||
t = (sample_index * samples_per_channel + len(values) // channels) / sample_rate_hz
|
||||
for ch in range(channels):
|
||||
phase = 2 * math.pi * ch / channels
|
||||
values.append(amplitude * math.sin(2 * math.pi * frequency_hz * t + phase))
|
||||
|
||||
# Pack as f32 little-endian
|
||||
payload = struct.pack(f"<{len(values)}f", *values)
|
||||
return cobs_encode(payload)
|
||||
|
||||
|
||||
def cobs_encode(data: bytes) -> bytes:
|
||||
"""Consistent Overhead Byte Stuffing encoder."""
|
||||
result = bytearray()
|
||||
block_start = 0
|
||||
while block_start < len(data):
|
||||
end = min(block_start + 254, len(data))
|
||||
block = data[block_start:end]
|
||||
if end < len(data):
|
||||
result.append(len(block) + 1)
|
||||
result.extend(block)
|
||||
else:
|
||||
result.append(len(block) + 1 if len(block) < 254 else 255)
|
||||
result.extend(block)
|
||||
result.append(0)
|
||||
block_start = end
|
||||
return bytes(result)
|
||||
"""Build a raw little-endian f32 plot payload (no framing)."""
|
||||
return pv_protocol.build_plot_payload(
|
||||
sample_index=sample_index,
|
||||
channels=channels,
|
||||
plot_format=plot_format,
|
||||
samples_per_channel=samples_per_channel,
|
||||
amplitude=amplitude,
|
||||
frequency_hz=frequency_hz,
|
||||
sample_rate_hz=sample_rate_hz,
|
||||
)
|
||||
|
||||
|
||||
def build_mixed_frame(seq: int, text_rate_per_plot: int, channels: int) -> bytes:
|
||||
"""Build a MixedTextPlot frame: text lines + one COBS plot frame."""
|
||||
"""Build a MixedTextPlot frame: text lines + one XP plot frame."""
|
||||
frames = []
|
||||
for i in range(text_rate_per_plot):
|
||||
frames.append(generate_text_line(seq * text_rate_per_plot + i, ansi=True))
|
||||
# Add one plot frame per text_rate_per_plot text lines
|
||||
plot_data = build_plot_frame(seq, channels, "interleaved", 32, 100.0, 10.0, 1000.0)
|
||||
frames.append(bytes([PLOT_ESCAPE, PLOT_MARKER]) + plot_data)
|
||||
plot_payload = build_plot_frame(seq, channels, "interleaved", 32, 100.0, 10.0, 1000.0)
|
||||
frames.append(
|
||||
pv_protocol.build_mixed_plot_frame(
|
||||
payload=plot_payload,
|
||||
channels=channels,
|
||||
samples_per_channel=32,
|
||||
plot_format="interleaved",
|
||||
)
|
||||
)
|
||||
return b"".join(frames)
|
||||
|
||||
|
||||
@@ -273,7 +239,7 @@ class StressServer:
|
||||
last_count_time = time.time()
|
||||
|
||||
except OSError as e:
|
||||
if hasattr(e, "winerror") and e.winerror in DISCONNECT_WINERRORS:
|
||||
if pv_protocol.is_disconnect_error(e):
|
||||
pass
|
||||
elif not self.running:
|
||||
pass
|
||||
@@ -324,7 +290,7 @@ class StressServer:
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="pipeview-tauri 极限压力测试",
|
||||
description="pipeview GUI(egui)极限压力测试",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
示例:
|
||||
|
||||
Reference in New Issue
Block a user