数学建模嵌入式中的串行流水线 + 消息并发

串行流水线 + 消息并发,这是嵌入式ISP处理中最典型、也最棘手的场景。

好消息是:串行拓扑 让数学模型大大简化,不需要处理复杂的DAG分叉合并。但消息并发 引入了资源竞争,这才是建模的核心难点。

下面给出一套精确的确定性数学模型,专门针对"多消息在串行流水线上并发执行"的场景。


1. 问题形式化

1.1 系统参数(全部已知)

  • CPU核心数 :KKK(固定)
  • 单核算力 :α\alphaα(归一化因子,如 1.0)
  • 流水线阶段 :PPP个线程节点(按顺序执行,固定映射到各核心)
  • 硬件阶段:穿插在流水线中的硬件等待节点(固定时间)
  • 每个阶段执行时间 :eie_iei(固定,已知)
  • 消息到达时间 :t1,t2,t3,...t_1, t_2, t_3, ...t1,t2,t3,...(实际观测值,但建模时作为已知输入)

1.2 流水线拓扑(串行)

复制代码
消息 M 的流水线:
[线程1 on Core A] → [硬件1 (10ms)] → [线程2 on Core B] → [硬件2 (5ms)] → [线程3 on Core C] → 完成

每个阶段只能在前一阶段完成后开始。

1.3 调度规则(固定策略)

  • 每个核心维护一个FIFO队列(或优先级队列,但串行场景下通常同优先级FIFO)。
  • 抢占?如果高优先级可抢占,稍复杂;先按非抢占式FIFO建模(最常用),后文扩展抢占式。

2. 核心数学模型:流水线调度 + 排队论

对于串行流水线,每个消息的完成时间可以递推计算 ,关键是要跟踪每个核心在每个时间点的队列状态

2.1 符号定义

符号 含义
MjM_jMj 第 jjj个到达的消息
tjt_jtj 消息 MjM_jMj的到达时刻
stagei\text{stage}_istagei 流水线第 iii个阶段(i=1..Pi=1..Pi=1..P)
core(i)\text{core}(i)core(i) 阶段 iii所在CPU核心编号
eie_iei 阶段 iii的执行时间(线程处理)
hih_ihi 阶段 iii后的硬件等待时间(如果有)
Sj,iS_{j,i}Sj,i 消息 MjM_jMj在阶段 iii的实际开始时间
Fj,iF_{j,i}Fj,i 消息 MjM_jMj在阶段 iii的实际完成时间

2.2 递推公式(核心)

阶段1(第一个线程):Sj,1=max⁡(tj,核心 core(1) 在 tj 时刻的队列空闲时间)S_{j,1} = \max\left( t_j, \text{核心 } \text{core}(1) \text{ 在 } t_j \text{ 时刻的队列空闲时间} \right)Sj,1=max(tj,核心 core(1) 在 tj 时刻的队列空闲时间)Fj,1=Sj,1+e1F_{j,1} = S_{j,1} + e_1Fj,1=Sj,1+e1
阶段 iii(i≥2i \ge 2i≥2):

阶段 iii的理论就绪时间 (所有前置阶段完成):Rj,i=Fj,i−1+hi−1R_{j,i} = F_{j,i-1} + h_{i-1}Rj,i=Fj,i−1+hi−1

其中 hi−1h_{i-1}hi−1是阶段 i−1i-1i−1后的硬件等待时间(如果阶段 i−1i-1i−1后无硬件,则 hi−1=0h_{i-1}=0hi−1=0)。

实际开始时间:Sj,i=max⁡(Rj,i,核心 core(i) 在 Rj,i 时刻的队列空闲时间)S_{j,i} = \max\left( R_{j,i}, \text{核心 } \text{core}(i) \text{ 在 } R_{j,i} \text{ 时刻的队列空闲时间} \right)Sj,i=max(Rj,i,核心 core(i) 在 Rj,i 时刻的队列空闲时间)Fj,i=Sj,i+eiF_{j,i} = S_{j,i} + e_iFj,i=Sj,i+ei

消息完成时间:Tj=Fj,PT_j = F_{j,P}Tj=Fj,P

3. 关键:如何计算"核心队列空闲时间"?

核心队列空闲时间是指:该核心在时刻 ttt之前已经排队的任务全部完成后,首次空闲的时刻

3.1 维护每个核心的"完成时间列表"

对于核心 ccc,维护一个按开始时间排序的任务完成时间列表 :CompletionListc={(S1,F1),(S2,F2),...}\text{CompletionList}_c = \{(S_1, F_1), (S_2, F_2), ...\}CompletionListc={(S1,F1),(S2,F2),...}

其中 Fk=Sk+etaskF_k = S_k + e_{\text{task}}Fk=Sk+etask,且这些任务按 SkS_kSk递增。

当新任务在时刻 ttt到达该核心队列时,其空闲时间 为:idle_timec(t)=max⁡(t,max⁡(Sk,Fk)∈CompletionListcSk≥last_idleFk)\text{idle\_time}c(t) = \max\left( t, \max{\substack{(S_k, F_k) \in \text{CompletionList}_c \\ S_k \ge \text{last\_idle}}} F_k \right)idle_timec(t)=max(t,max(Sk,Fk)∈CompletionListcSk≥last_idleFk)

但更简单的方式是维护一个"当前队列尾部时间"

3.2 高效方法:维护每个核心的"队列尾部时间" QcQ_cQc

定义 QcQ_cQc为:核心 ccc在当前时刻之前所有排队任务预计完成的最晚时间

  • 初始化 :Qc=0Q_c = 0Qc=0(所有核心空闲)
  • 当新任务在时刻 ttt加入核心 ccc
    S=max⁡(t,Qc)S = \max(t, Q_c)S=max(t,Qc)
    F=S+etaskF = S + e_{\text{task}}F=S+etask
    Qc=F(更新队列尾部时间)Q_c = F\quad(\text{更新队列尾部时间})Qc=F(更新队列尾部时间)

这个 QcQ_cQc就是该核心的**"空闲时间"**------即新任务最早能开始的时间。

3.3 为什么这有效?

因为串行流水线 + FIFO调度,每个核心上的任务严格顺序执行 ,不存在任务穿插。队列尾部时间 QcQ_cQc就是该核心完成所有已有任务的时间,新任务只能在 QcQ_cQc之后开始。

注意 :如果有优先级抢占,QcQ_cQc需要替换为**"当前正在执行的高优先级任务完成时间"**,稍后扩展。


4. 完整的递推算法(确定性)

4.1 算法伪代码

python 复制代码
# 初始化:每个核心的队列尾部时间
Q = [0] * K  # K个核心

# 存储每个消息的阶段完成时间
F = {}  # F[(j, i)] = 完成时间

for j in range(num_messages):  # 按到达顺序处理消息
    t_arr = arrival_times[j]
    
    # 阶段1
    S = max(t_arr, Q[core(1)])
    F[(j, 1)] = S + e_1
    Q[core(1)] = F[(j, 1)]
    
    # 阶段2..P
    for i in range(2, P+1):
        # 前驱完成 + 硬件等待
        R = F[(j, i-1)] + h_{i-1}
        # 排队等待
        S = max(R, Q[core(i)])
        F[(j, i)] = S + e_i
        Q[core(i)] = F[(j, i)]
    
    # 消息完成时间
    T_j = F[(j, P)]

4.2 举例说明

假设系统:

  • Core 0:阶段1(5ms) + 阶段3(3ms)
  • Core 1:阶段2(4ms) + 硬件(2ms)

两个消息到达:

  • M1:t=0
  • M2:t=2

手动计算

时间 事件 Core0 Q Core1 Q
0 M1到达,阶段1开始 Q0=5 Q1=0
2 M1阶段1完成,阶段2就绪(R=2),Core1空闲,开始阶段2 Q0=5 Q1=6(4+2硬件)
5 M1阶段2完成,阶段3就绪(R=5+2=7),但Core0队列尾部是5,所以S=max(7,5)=7 Q0=10(3+7) Q1=6
2 M2到达,阶段1就绪,Core0队列尾部是5,S=max(2,5)=5 Q0=10 Q1=6
7 M1阶段3完成,M1完成时间=7 - -
10 M2阶段1完成,阶段2就绪(R=10),Core1队列尾部是6,S=max(10,6)=10 - Q1=14(4+10)
14 M2阶段2完成,阶段3就绪(R=14+2=16),Core0队列尾部是10,S=max(16,10)=16 Q0=19(3+16) -
19 M2阶段3完成,M2完成时间=19 - -

结论

  • M1完成时间 = 7ms
  • M2完成时间 = 19ms(因为被M1阻塞)

5. 扩展:支持优先级调度

如果你的系统支持高优先级消息抢占低优先级消息,模型需要调整:

5.1 维护每个核心的"按优先级排序的完成时间树"

核心 ccc上不再是一个FIFO队列,而是按优先级排序的队列。当高优先级任务到达时,它可以插入到队列头部,导致低优先级任务延迟。

改造方案

  • 每个核心维护一个优先级队列(按优先级降序)。
  • 当新任务加入时,插入到合适位置。
  • 核心的"队列尾部时间" QcQ_cQc不再简单等于最后一个任务完成时间,而是所有任务按优先级顺序执行的最终完成时间

5.2 递推公式(抢占式)

如果允许抢占(即高优先级任务到达时,立即暂停低优先级任务),则:

  • 当前正在执行的低优先级任务会被打断,剩余时间放入队列。
  • 高优先级任务先执行完毕。
  • 继续执行低优先级任务剩余部分。

实现方式:在事件模拟中,每次新任务到达时,检查当前核心上执行的任务优先级,如果新任务优先级更高,则:

  1. 当前任务的剩余时间记录
  2. 新任务先执行
  3. 完成后恢复原任务

由于串行场景下每个核心同时只执行一个任务,这个逻辑实现起来很简单。


6. 数学模型 vs 事件模拟

上面的递推公式实际上就是事件驱动的确定性模拟。区别在于:

方法 实现方式 优点 缺点
递推公式(离线计算) 按消息到达顺序一次性算完所有完成时间 快速,O(n*P) 需要所有消息到达时间已知
事件模拟(在线计算) 随着消息到达逐步更新Q_c 在线,实时预测 每次新消息需O§计算

在你的场景中,消息不定期到达 ,因此推荐事件模拟(在线),每次消息到达时:

  1. 用当前系统快照(各核心Q_c值)
  2. 运行递推公式预测该消息的完成时间
  3. 更新系统状态(Q_c)

7. 终极简化:完全数学公式(无需循环)

对于串行流水线 ,每个消息的完成时间可以写成闭合形式:Tj=tj+∑i=1Pei+∑i=1Phi+∑i=1Pmax⁡(0,Qcore(i)−tj−∑k=1i−1(ek+hk))T_j = t_j + \sum_{i=1}^P e_i + \sum_{i=1}^P h_i + \sum_{i=1}^P \max\left(0, Q_{\text{core}(i)} - t_j - \sum_{k=1}^{i-1} (e_k + h_k) \right)Tj=tj+∑i=1Pei+∑i=1Phi+∑i=1Pmax(0,Qcore(i)−tj−∑k=1i−1(ek+hk))

但这个公式在并发场景下变得复杂(因为Q_c本身依赖历史任务)。更实际的做法:用上述递推算法,每个消息只遍历一次流水线阶段,复杂度O§,极快。


8. 实操建议

8.1 在嵌入式RTOS中实现

c 复制代码
// 每个核心维护一个"预计完成时间"
uint32_t core_completion_time[K] = {0};

// 当新消息到达时调用
uint32_t predict_completion_time(uint32_t arrival_time) {
    uint32_t prev_finish = arrival_time;
    
    for (int stage = 0; stage < P; stage++) {
        int core = stage_core[stage];
        uint32_t exec_time = stage_exec[stage];
        uint32_t hardware_wait = stage_hw[stage]; // 本阶段后的硬件等待
        
        uint32_t ready_time = prev_finish + hardware_wait;
        uint32_t start_time = max(ready_time, core_completion_time[core]);
        uint32_t finish_time = start_time + exec_time;
        
        // 更新核心完成时间(用于后续消息)
        core_completion_time[core] = finish_time;
        prev_finish = finish_time;
    }
    return prev_finish; // 消息完成时间
}

8.2 处理"多个阶段在同一核心"的情况

如果阶段1和阶段3都在Core 0上,上述算法自动处理:

  • 阶段1完成后,Core 0的Q0更新为F1。
  • 阶段3就绪时(可能已经过了很久),取S = max(R, Q0),如果Q0 > R,说明Core 0还在处理其他消息,新阶段需要等待。

9. 结论

对于串行流水线 + 消息并发的场景:

  1. 无需机器学习,数学模型完全精确。
  2. 核心思想 :为每个CPU核心维护一个队列尾部时间 Q_c,表示该核心完成所有已有任务的最晚时间。
  3. 递推公式 :每个消息遍历流水线阶段,用S = max(ready_time, Q_c)计算开始时间,更新Q_c = S + exec_time
  4. 时间复杂度:O§每个消息,嵌入式可实时运行。

这套模型可以精确预测每条消息的完成时间,误差为0(因为所有参数确定)。

相关推荐
【云轩】2 小时前
离散量输入输出电路设计:V/地、V/开、地/开信号与单片机接口的电路实现
单片机·嵌入式硬件·mongodb
2401_854151552 小时前
STM32 低功耗模式:SLEEP / STOP / STANDBY 怎么选
stm32·单片机·嵌入式硬件
Kuakewei8882 小时前
7533稳压芯片ic输入串电阻原理:3.3V输出功耗计算与散热指南
嵌入式硬件
KaifuZeng4 小时前
模电面试问题汇总二
单片机·嵌入式硬件·面试·模电·通信与接口协议
冰茶丿4 小时前
状态机在嵌入式系统中的应用:不只是switch-case这么简单
数据库·嵌入式硬件·mongodb
是摆烂第一名呀5 小时前
【RK3506】RGB屏幕与背光调试记录
linux·arm开发·驱动开发·嵌入式硬件
KaifuZeng5 小时前
模电面试问题汇总三
单片机·嵌入式硬件·面试·模电
2401_854151555 小时前
STM32 复用功能(AF)配置的常见误区
stm32·单片机·嵌入式硬件
菠萝地亚狂想曲5 小时前
STM32_gitea workflow
stm32·嵌入式硬件·gitea