Files
Inbox/系统基座文件/2/2.4/2.4.4 热节流响应与流量整形 (Thermal Throttling Response & Traffic Shaping).md
2025-12-11 07:24:36 +08:00

6.2 KiB
Raw Blame History

tags, aliases, date created, date modified
tags aliases date created date modified
2.4.4 热节流响应与流量整形 (Thermal Throttling Response & Traffic Shaping)
星期一, 十一月 24日 2025, 4:33:19 下午 星期一, 十一月 24日 2025, 4:38:23 下午

2.4.4 热节流响应与流量整形 (Thermal Throttling Response & Traffic Shaping)

这是数据网关的“被动防御机制”。不同于 2.3.5 中 SignalProcessor主动降速(通过 sleep 减少计算热量),DisplayController 在此处的任务是通过减少数据发送量降低发送频率,来降低 CPU 的序列化开销、PCIe 总线功耗以及网卡的中断频率,从而辅助系统整体降温。

一、 约束输入与对齐 (Constraints & Alignment)

基于 ECN-2025-001 和之前的讨论,我们需对齐以下硬性约束:

  1. 被动执行DisplayController 不感知温度,只响应 SetComputeThrottleEvent 指令。

  2. 原子性保持:即使在节流状态下,发送出去的 TrackDataBatch 仍然必须是原子批次。严禁将一个 CPI 的数据拆成两半发送(例如发一半航迹),这会破坏显控端的一致性。

  3. 优先级明确

    • P0 (保命):确认航迹 (Confirmed Tracks)。这是雷达存在的意义。
    • P1 (辅助):未确认航迹 (Tentative)、系统状态。
    • P2 (冗余):点迹 (Plots)、调试日志、原始回波切片。

二、 权衡分析与选项呈现 (Trade-off Matrix)

议题:流量整形策略 (Shaping Strategy)

选项 A. 仅内容剪裁 (Content Pruning) B. 仅频率抽稀 (Frame Skipping) C. 混合降级 (Hybrid Degradation) (推荐)
机制 保持 100Hz 发送频率,但把包里的点迹删掉,包变小了。 保持包内容完整,但每隔一帧发一帧(降为 50Hz 轻度过热时剪裁内容;重度过热时既剪裁内容又抽稀频率。
热收益 。减少了序列化开销和带宽,但网卡中断频率没变(依然是 100Hz 。网卡中断减半,序列化开销减半。 极高。全方位降低负载。
显控体验 流畅但空洞。画面依然丝滑,只是点迹没了。 卡顿但丰富。画面有顿挫感,但信息量全。 平滑过渡。优先保流畅,实在不行再保生存。

三、 基线确立与实施规范

为了在“保护硬件”和“维持态势感知”之间取得最佳平衡,我们确立 C. 混合降级 为基线。

1. 节流等级映射表 (Throttling Mapping Table)

我们定义各级节流状态下,DisplayController 的具体行为规范:

节流等级 (Throttle Level) 发送频率 (Frequency) 内容策略 (Content Policy) 显控端表现
L0 (NO_THROTTLE) 100% (全速) 全量 (航迹 + 点迹 + 状态 + 调试) 正常显示。
L1 (LIGHT) 100% (全速) 剪裁 P2 (丢弃点迹、调试信息)。保留所有航迹。 画面流畅,但背景点迹消失。提示 "Data Pruned"。
L2 (HEAVY) 50% (二抽一) 剪裁 P1+P2 (仅保留确认航迹)。 画面帧率减半 (50Hz),仅显示核心目标。提示 "Low Rate"。
L3 (SUSPEND) 0% (暂停) 停止发送 (仅发心跳包维持连接)。 画面静止/黑屏。提示 "Server Overheat"。

2. 实现规范:发送间隔插入 (Gap Insertion)

为了实现 L2 级别的降频,我们不能依赖上游 SignalProcessor 的降速(虽然它也在降,但我们要在网络层做双重保险)。

  • 位置DisplayController 的独立 IO 线程循环中。

  • 逻辑:维护一个 frame_counter

  • 代码范式

    void DisplayController::ioLoop() {
        uint64_t frame_counter = 0;
    
        while (running_) {
            // 1. 从队列取数据
            TrackDataPacket packet;
            if (!queue_.pop(packet)) continue; // Non-blocking pop or wait
    
            // 2. 获取当前节流等级 (原子读取,无锁)
            auto level = current_throttle_level_.load(std::memory_order_relaxed);
    
            // 3. L3 级熔断:直接丢弃,仅维持心跳
            if (level == Level::SUSPEND) {
                sendHeartbeat();
                continue;
            }
    
            // 4. L2 级抽稀Gap Insertion (每2帧丢1帧)
            frame_counter++;
            if (level == Level::HEAVY && (frame_counter % 2 != 0)) {
                continue; // Drop this frame completely
            }
    
            // 5. L1/L2 级内容剪裁 (在序列化前执行节省CPU)
            if (level >= Level::LIGHT) {
                packet.plots.clear(); // 丢弃点迹
                packet.debug_info.clear();
            }
            if (level >= Level::HEAVY) {
                // 仅保留确认航迹
                packet.tracks.erase(
                    std::remove_if(packet.tracks.begin(), packet.tracks.end(),
                        [](const Track& t){ return t.status != CONFIRMED; }),
                    packet.tracks.end());
            }
    
            // 6. 序列化并发送 (Protobuf Encode -> sendto)
            serializeAndSend(packet);
        }
    }
    

3. 流量整形对丢包检测的影响 (2.4.3 联动)

  • 问题:如果在 L2 级别主动抽稀(丢弃偶数帧),显控端会不会误判为“丢包”?
  • 解决方案
    • 序列号连续性batch_sequence_id 是在**序列化步骤(第 6 步)**生成的。
    • 结论:被主动丢弃的帧(第 4 步)根本不会获得序列号。因此,发送出去的数据包序列号依然是连续的。显控端不会误报丢包,只会感知到数据刷新变慢(两次更新的时间间隔变大)。这是非常优雅的设计。

总结2.4.4 基线图谱

策略维度 核心基线 设计意图
响应模式 被动执行 听从 ResourceCoordinator 指挥,不独立决策。
L1 策略 内容剪裁 (Pruning) 牺牲次要数据,保流畅度,降序列化开销。
L2 策略 频率抽稀 (Skipping) 牺牲刷新率,保核心数据,降中断和总线功耗。
序列号 后置生成 确保主动丢弃不破坏传输层的序列连续性。