Svc::RateGroupDriver: 许多费率组的转换产品溢出, LCM 将无法处理
作者: ephraim71创建于 2026年9月16日更新于 2026年9月16日
|:---|:---|
|F´ 版本| v4.3.0 |
|受影响的组件| Svc::RateGroupDriver |
功能说明
此提交 添加了一个检查,确保在计算 m_rollover 时不会溢出。 (cc @LeStarch)
这个检查本身非常好。但是,m_rollover 的计算方式可以大大改进。而不是将每个除数相乘在一起,我们可以使用最小公倍数。
以一个 1 ms 基准时钟和 1 ms、2 ms、4 ms、5 ms、10 ms、20 ms、50 ms、100 ms、200 ms、500 ms、1 s、2 s、5 s 和 10 s 的速率组为例:
Svc::RateGroupDriver::DividerSet rateGroupDivisorsSet{
{{1,0},{2,0},{4,0},{5,0},{10,0},{20,0},{50,0},
{100,0},{200,0},{500,0},{1000,0},{2000,0},{5000,0},{10000,0}}};产品的滚动值为:
1*2*4*5*10*20*50*100*200*500*1000*2000*5000*10000 = 400,000,000,000,000,000,000,000,000 (4.0e26),远远超过 64 位 FwSizeType 的最大值 18,446,744,073,709,551,615 (1.8e19)。 Assert 断言(合理)。
相同集合的最小公倍数为:
```cpp
10000
现在,人们被迫将其分成两个速率组驱动器(一个快速驱动器,其最后一个输出时钟为 1 秒,一个较慢的驱动器),纯粹是因为滚动产品达到上限。通过此更改,只需要一个速率组驱动器即可。
所建议的更改,将单独提交。
```cpp
// rollover 值应为所有除数的最小公倍数,以确保整数滚动不会跳过周期
if (dividerSet.dividers[entry].divisor != 0) {
const FwSizeType divisor = dividerSet.dividers[entry].divisor;
const FwSizeType reduced = this->m_rollover / gcd(this->m_rollover, divisor);
// 确保滚动不会溢出
FW_ASSERT((std::numeric_limits<FwSizeType>::max() / divisor) >= reduced,
static_cast<FwAssertArgType>(reduced),
static_cast<FwAssertArgType>(divisor));
this->m_rollover = reduced * divisor;
}保留了原有的溢出断言,只是将其应用于减少后的值。
理由
- 它消除了对速率组数量的人为限制。产品以乘法方式与每个端口相乘,因此即使调度本身完全合理,在添加了适当数量的组后,当前方案也会超出范围。在上面的示例中,14 个具有普通周期的组已经不可调度。与谐音相关的周期的最小公倍数,这几乎是真实的速率调度的样子,无论添加了多少组,都保持很小。
- 此更改不会带来任何运行时成本。计算在 configure() 中发生一次。
- 它使新的溢出断言更难以触发。
内容来源: nasa/fprime