[Apollo Cyber RT] Timer实现

Timer的实现方式

Timer有多种实现方式,CyberRT采用了时间轮(TimingWheel)方式。关于Timing Wheels的详细描述可以参考附录的链接。此处不赘述。

CyberRT Timer的类构成

在这里插入图片描述

实现细节

Timer

Timer类是门户,但定时器真正的核心是TimingWheel。
Timer的定义相对简单,基本就是传入period(多久后触发)、callback(触发后执行的函数)、oneshot(执行一次,还是循环执行)创建定时器,然后调用Start()启动定时器。调用Stop()停止定时器。

测试样例可以再Timer_test.cc中找到。
在这里插入图片描述
Timer的调用Start()后,会调用InitTimerTask()创建一个新的TimerTask, 然后通过timing_wheel_->AddTask(task_)添加到时间轮对应的slot上。

TimerTask指针是时间轮调度操作的单元。Timer::InitTimerTask()函数较长,主要是对循环调用场景下task_->callback的Lambda定义。

在这里插入图片描述
在这里插入图片描述
对于循环场景,我们需要下一次调度的准确时间,所以我们需要计算函数的执行时间execute_time_ms和累积的错误时间accumulated_error_ms。

函数执行消耗时间execute_time_ms比较容易理解, 累积的错误时间accumulated_error_ms第一次看到时,容易让人疑惑。下面用一个简单的例子来解释一下。

假设定时器tick为2ms。一个循环执行的timer,每11ms执行一次。所以第一次会向上取整,落到第12ms这个tick上。到时触发后,执行耗时2ms,此时当前tick为第14ms这个tick。

我们准备重新将timer加入到定时器中,下一次执行时间该是多少呢?如果没有accumulated_error_ms,我们会计算得到 11 - 2 = 9, 使用当前时间14 + 9 = 23,向上取整的到了24。也就是说下一次会在第24ms时触发。这和我们理想情况下第二次22ms触发整整差了2ms。如果没有accumulated_error_ms,越往后累积偏差越大,这样精确性就得不到保障了。

下面我们看下考虑到accumulated_error_ms后的情况。我们通过

accumulated_error_ms += start(当前时刻) - last_execute_time_ms(执行耗时) - interval_ms = 14 - 2 - 11 = 1

的到了accumulated_error_ms=1,在随后的计算中

next_fire_duration_ms= interval_ms-execute_time_ms-accumulated_error_ms= 11 - 2 - 1 = 8

的到了下一次触发间隔时间next_fire_duration_ms=8
也就是说在14(当前时刻)+ 8 = 22ms时触发,这和我们期望的时间完全一致,时间精确性的到了最大限度地保障。

在这里插入图片描述

TimingWheel

CyberRT使用了两个时间轮,一个主时间轮和一个辅助时间轮。
主时间轮512个slot,tick为2ms,可以承载1024ms。
副时间轮64个slot,一个slot对应1024ms。当主时间轮运行一周后,会从副时间轮对应slot中取出task(时间范围1024ms)应用到主时间轮上,继续执行。

所以可以设置的最大间隔为 TIMER_MAX_INTERVAL_MS = 65536ms,约为65秒。

static const uint64_t WORK_WHEEL_SIZE = 512;
static const uint64_t ASSISTANT_WHEEL_SIZE = 64;
static const uint64_t TIMER_RESOLUTION_MS = 2;
static const uint64_t TIMER_MAX_INTERVAL_MS =
    WORK_WHEEL_SIZE * ASSISTANT_WHEEL_SIZE * TIMER_RESOLUTION_MS;  //65536,约65s左右。

  TimerBucket work_wheel_[WORK_WHEEL_SIZE];           //主时间轮
  TimerBucket assistant_wheel_[ASSISTANT_WHEEL_SIZE]; //辅助时间轮

Timer主线程

主线程运行TickFunc函数,代码如下:

  1. Tick()函数是执行当前slot中到期的所有TimerTask。
  2. rate.Sleep() 负责精确休眠tick时间,即2ms。
  3. 更新时间轮index
  4. 如果时间轮走过一圈,则调用Cascade()从辅助时间轮中取对应slot的TimerTask部署到主时间轮上。
    在这里插入图片描述

AddTask函数

AddTask根据current_work_wheel_index + next_fire_duration_ms/TIMER_RESOLUTION_MS 得到对应的时间轮index。

  1. 如果index 没有超过WORK_WHEEL_SIZE,则直接插入到对应slot。
    在这里插入图片描述

  2. 如果index超过WORK_WHEEL_SIZE,但是assistant_ticks为1并且index小于当前时间的index。
    在这里插入图片描述

  3. assistant_ticks为1且work index>= current index或者assistant_ticks > 1
    示例:assistant_ticks=2,直接将任务插入到当前assistant wheel index + 2的slot中。
    在这里插入图片描述
    在这里插入图片描述

附录

Timing Wheels

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Apollo Cyber RT是基于Apollo自动驾驶开放平台的一种实时仿真工具。它能够对自动驾驶算法进行快速的模拟测试和验证。 Apollo Cyber RT可以在没有物理车辆的情况下,使用虚拟仿真环境对自动驾驶系统进行全面的测试。它提供了高度逼真的虚拟场景,包括各种路况、天气条件、道路标志和交通规则。用户可以在这个仿真环境中,验证自动驾驶算法在各种复杂情况下的性能和稳定性。 Apollo Cyber RT还提供了丰富的仿真工具和API接口,可以进行车辆动力学仿真、传感器数据仿真、车辆控制仿真等。用户可以根据实际需求,快速搭建自己的仿真场景,并通过API接口与自己的自动驾驶算法进行集成。这样,用户就可以在不同场景下进行大规模的仿真测试,测试自动驾驶系统对各种情况的应对能力。 与传统的实地测试相比,Apollo Cyber RT的优势在于它可以大大缩短测试周期和降低测试成本。传统的实地测试需要耗费大量的时间和资源,并且受到地理和气候等限制。而Apollo Cyber RT可以在任何时间和地点进行仿真测试,同时还可以通过调整仿真参数、重复测试等方式,快速地验证和迭代自动驾驶算法。 总之,Apollo Cyber RT是一种基于Apollo开放平台的实时仿真工具,它能够帮助用户快速测试和验证自动驾驶算法。它提供了丰富的虚拟场景和仿真工具,可以满足用户在不同场景下的测试需求,同时还能显著缩短测试周期和降低测试成本。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮沉飘摇

码字不易,打赏随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值