20 CPU占用与内存占用
20.1 概述
本文说明 ag_driver 对 CPU 和内存的使用。
请先阅读《ag_driver的线程模型与接口设计》,因为本文引用了其中的概念。

20.2 CPU占用
20.2.1 CPU占用的来源
ag_driver 的 CPU 占用主要来自两个方面:
MSOP/DIFOP Packet 的处理线程
process_thread解析 MSOP/DIFOP Packet,构建点云。process_thread等待 MSOP/DIFOP Packet 时,反复被唤醒->睡眠->唤醒。这个过程 CPU 占用率较高,原因是 Packet 是频率高但不连续的,process_thread切换状态的次数太多了。
20.2.2 降低 CPU 占用率的办法
CMake 编译宏 ENABLE_WAIT_IF_QUEUE_EMPTY 可以让 ag_driver 的 CPU 占用率降低一点,但是弊端是点云延迟会加大。
它的原理是让 process_thread 每次睡眠的时间长一点,这样每次唤醒时处理的包数就多一些,反复 唤醒 -> 睡眠 -> 唤醒 的次数就少一些。
option(ENABLE_WAIT_IF_QUEUE_EMPTY "Enable waiting for a while in handle thread if the queue is empty" OFF)
打开这个宏后,Packet 处理线程会调用 usleep(),而不是等待条件变量通知。
在某平台的测试结果表明,这个宏可以将 CPU 占用率从 25% 降低到 22%。
#ifdef ENABLE_WAIT_IF_QUEUE_EMPTY
...
std::this_thread::sleep_for(std::chrono::microseconds(1000));
return value;
#else
...
std::unique_lock<std::mutex> ul(mtx_);
cv_.wait_for(ul, std::chrono::microseconds(usec), [this] { return (!queue_.empty()); });
...
return value;
#endif
这里也有必要说明这样做的弊端。
对于 usleep() 的等待时间是不确定的。如果等待跨过了点云的分帧点,比如
MEMS 雷达,比如 A0 的 MSOP Packet 序列号跨过了 1344。
这样分帧就会拖后,ag_driver 的使用者“看”到这一帧的时间点就会推迟。
所以请您根据自己的场景,权衡 CPU 占用和点云延迟之间的利弊,再决定是否使能这个编译宏。
20.3 内存占用
20.3.1 MSOP/DIFOP Packet 队列
ag_driver 的内存占用主要来自 MSOP/DIFOP Packet 队列 free_pkt_queue 和 stuffed_pkt_queue。
这两个队列中的 Packet 实例是按需分配的,分配的数量与雷达类型、使用场景相关。
在
ag_driver的实现中,它不会释放这些实例。如果有偶然的意外发生,导致 Packet 实例的数量异常增多,那么后面它们所占用的内存也不会降低。
20.3.2 点云队列
ag_driver 使用的点云实例是调用者分配、管理的,所以这里不讨论点云占用的内存。
20.3.3 查表方式计算三角函数值
关于 MEMS 雷达,
A0 不需要计算三角函数值,也就不需要占用这部分内存。
如果连接多个雷达,
ag_driver的多个实例各有自己的Trigon实例。也就是每个实例都占用 432,000 字节。
20.3.4 Socket 接收缓存
一个比较隐蔽的内存占用,是接收 MSOP/DIFOP Packet 的 Socket 的接收缓存。
MSOP Packet 和 DIFOP Packet 一般各有自己接收的 Socket。在丢包的情况下,可能需要增加Socket接收缓存的大小。