Files
Inbox/系统基座文件/2/2.6/2.6.2 多级数据打点策略 (Multi-Level Timestamping Strategy).md
2025-12-11 07:24:36 +08:00

126 lines
6.6 KiB
Markdown
Raw Permalink 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.

---
tags: []
date created: 星期三, 十一月 26日 2025, 9:49:46 晚上
date modified: 星期三, 十一月 26日 2025, 10:06:18 晚上
---
# 2.6.2 多级数据打点策略 (Multi-Level Timestamping Strategy)
**基线核心宗旨****“As Early As Possible (越早越好)”**。
时间戳必须尽可能在物理层PHY或链路层MAC生成以消除操作系统中断调度、驱动处理和协议栈拷贝带来的**不定长抖动Jitter**。
-----
## 1. 约束输入与对齐 (Constraints & Alignment)
基于 2.1.1 审计结果(网迅 WX1860AL4 网卡)和 2.6.1 确立的时钟基线,我们需要对齐以下约束:
1. **硬件能力 (Hardware Cap)**
- **网迅 NIC**:需确认驱动是否支持 `SO_TIMESTAMPING` 接口读取硬件 RX 时间戳。通常企业级网卡Intel X710/Mellanox均支持国产网卡需实测验证。若不支持需回退到内核软打点。
2. **协议支持 (Protocol)**
- UDP 数据包本身不携带“发送时间”(除非应用层协议写了)。因此我们依赖的是**接收端打点 (Ingress Timestamping)**。
3. **数据结构关联**
- 生成的纳秒级时间戳必须填入 `RawDataPacket` 的 Header并最终映射到 Protobuf 的 `timestamp_us`
-----
## 2. 权衡分析与选项呈现 (Trade-off Matrix)
我们按照“离物理线路的距离”定义三个打点层级:
| 选项 | A. 用户态打点 (User-space) | B. 内核软打点 (Kernel SW) **(基线)** | C. 硬件硬打点 (Hardware HW) **(理想)** |
| :--- | :--- | :--- | :--- |
| **生成位置** | `recvmsg()` 返回后的应用层代码。 | 网卡驱动收到中断SKB (Socket Buffer) 创建时刻。 | 网卡 PHY 芯片接收到前导码Preamble时刻。 |
| **抖动来源** | **极大**。受 CPU 调度、软中断处理、内存拷贝影响,抖动可达 10-100µs。 | **中等**。受中断响应延迟影响,抖动约 1-10µs。 | **极小**。几乎无抖动 (\< 100ns)。 |
| **PTP 依赖** | 依赖系统时钟 (`CLOCK_REALTIME`)。 | 依赖系统时钟。 | 依赖网卡 PHC (PTP Hardware Clock) 与系统时钟的同步 (`phc2sys`)。 |
| **实现复杂度**| 低。调用 `Clock::now()` 即可。 | 中。需配置 Socket 选项并解析辅助数据 (`CMSG`)。 | 高。需硬件支持,且需处理 PHC 到 UTC 的转换。 |
| **适用场景** | 功能调试、非实时业务。 | **当前国产环境最稳妥的基线**。 | 相控阵雷达、高频交易。 |
-----
## 3. 基线确立与实施规范
考虑到国产网卡驱动的成熟度风险,我们确立 **“优先硬件,兜底内核,严禁用户态”** 的分级策略。
### 3.1 策略分级定义 (Hierarchy Definition)
- **Priority 1 (HW)**: 尝试启用 **`SO_TIMESTAMPING_RX_HARDWARE`**。
- 如果网卡支持,这是绝对真值。
- *注意*:硬件时间戳通常是 PHC 时间TAI需在用户态根据 `ptp4l` 的 offset 转换为 UTC。
- **Priority 2 (SW)**: 回退到 **`SO_TIMESTAMPNS`** (内核接收时间)。
- 这是**工程基线**。它反映了数据包进入 Linux 网络栈的第一时间点,消除了应用程序调度的延迟。
- **Priority 3 (App)**: **严禁作为生产标准**。仅在上述两者皆失败时,使用 2.6.1 定义的 `HighPrecisionClock::now()` 补救,并标记数据质量为 `LOW_PRECISION`
### 3.2 实现规范:辅助数据解析 (CMSG Parsing)
`DataReceiver` 的 I/O 线程中,必须改造 `recvmmsg` 的调用方式,以提取内核附带的时间戳元数据。
- **Socket 配置**
```cpp
int flags = SO_TIMESTAMPNS; // 请求内核软件时间戳 (纳秒级)
// 如果确认网卡支持硬件打点,则改为:
// int flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE;
setsockopt(sockfd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof(flags));
```
- **接收逻辑 (核心代码范式)**
```cpp
void UdpReceiver::receiveLoop() {
struct mmsghdr msgs[BATCH_SIZE];
struct iovec iovecs[BATCH_SIZE];
char cmsg_buf[BATCH_SIZE][256]; // 存放辅助数据的缓冲区
// … 初始化 msgs, iovecs, cmsg …
int n = recvmmsg(sockfd, msgs, BATCH_SIZE, 0, nullptr);
for (int i = 0; i < n; ++i) {
uint64_t timestamp_ns = 0;
// 解析辅助数据 (Control Message)
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(&msgs[i].msg_hdr); cmsg; cmsg = CMSG_NXTHDR(&msgs[i].msg_hdr, cmsg)) {
// 优先提取硬件时间戳,若无则提取软件时间戳
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
struct timespec *ts = (struct timespec *)CMSG_DATA(cmsg);
timestamp_ns = ts->tv_sec * 1000000000ULL + ts->tv_nsec;
break;
}
}
// 兜底:如果内核没给时间戳,立刻用 TSC 软时钟打点
if (timestamp_ns == 0) {
timestamp_ns = HighPrecisionClock::now();
}
// 固化:写入 RawDataPacket Header
// 这一刻起,这个时间戳就是数据的"法定出生时间"
auto packet = MakePacket(std::move(payload), seq_id);
packet.header.timestamp_us = timestamp_ns / 1000;
// … 推送队列 …
}
}
```
### 3.3 全链路时间戳传递 (Propagation)
这个“出生时间戳” (`timestamp_us`) 必须在系统中神圣不可侵犯:
- **接收端 (`DataReceiver`)**:生成并写入 `RawDataPacket.header`。
- **处理端 (`SignalProcessor`)**:继承该时间戳。虽然 FFT 处理是在 5ms 后进行的,但数据的物理意义依然是“那个时刻的回波”。
- **输出端 (`DisplayController`)**:将该时间戳写入 Protobuf 的 `timestamp_us` 字段发送给显控。
- *注意*:显控端看到的延迟 = `Now() - timestamp_us`。这个延迟包含了:`内核排队 + 信号处理耗时 + 航迹关联耗时 + 序列化耗时 + 网络传输耗时`。这正是我们想要的**真实物理延迟**。
-----
## 总结2.6.2 基线图谱
| 维度 | 核心基线 | 技术细节 |
| :--- | :--- | :--- |
| **打点源** | **内核软打点 (`SO_TIMESTAMPNS`)** | 兼顾精度与兼容性,消除用户态抖动。 |
| **理想源** | **硬件打点 (HW RX)** | 若网卡支持,优先升级至此 (需实测)。 |
| **获取方式** | **`recvmmsg` + `CMSG`** | 从 Socket 辅助数据中提取,而非调用 `time()`。 |
| **语义** | **生成时间 (Generation Time)** | 代表信号到达系统的物理时刻,全链路透传,禁止修改。 |