FastDDS 零拷贝模式下多个 subscriber 的原理

FastDDS 新推出的零拷贝 (Zero Copy) 模式有很多难以理解的地方,在这里会持续做些整理。

目录

  1. 如何使用 ZeroCopy?
  2. ZeroCopy 理论上 subscriberpublisher 会使用同一个内存地址,为什么打印出来的地址不同?
  3. ZeroCopy 会分配多少空间,什么时候覆盖旧的样本?
  4. qos.history().depthqos.resource_limits().max_samples/extra_samples 什么关系?

1. 如何使用 ZeroCopy?

满足以下条件才能使用 ZeroCopy [1]

  • 不禁用 DataSharingQosPolicy。 使用 AUTO 可以自动启用零拷贝;
  • 数据类型必须为 LoanableSequence
  • 在 publisher 使用 loan_sample() write() discard_loan() 操作数据样本;
  • 在 subscriber 使用 read() take() return_loan() 访问数据样本,类似 take_next_sample 会执行一次拷贝。[2]

2. ZeroCopy 理论上 subscriber 和 publisher 会使用同一个内存地址,为什么打印出来的地址不同?

在程序里打印的是不同进程的虚拟地址,实际的物理地址是一样的,可以用 这个工具 查看。 [3]

1
2
3
4
5
6
7
$ sudo ./src/v2p 57649 0x7fffed6671cc 0x4000
pid: 57649:
virt:0x7fffed667000, phys:0xa6b59000

$ sudo ./src/v2p 57544 0x7f42280831d0 0x4000
pid: 57544:
virt:0x7f4228083000, phys:0xa6b59000

3. ZeroCopy 会分配多少空间,什么时候覆盖旧的样本?

创建 DataWriter 时,Fast DDS 将预先分配 max_samples + extra_samples 个样本池,这些样本位于共享内存映射文件中。当调用 loan_sample() 函数时,该池将用于借出样本。

此文档 所述,在写入 resource_limits().max_samples + resource_limits().extra_samples 次后,样本将被覆盖。

可以在 DataReader 上使用方法 is_sample_valid 来检查样本是否已被覆盖。

4. qos.history().depth 与 qos.resource_limits().max_samples/extra_samples 什么关系?

history() 的设置会覆盖 resource_limits(),具体的,ResourceLimitsQosPolicy::allocated_samples/max_samples 通过 HistoryQosPolicy::depthResourceLimitsQosPolicy::max_instances 重新计算,公式如下:

1
2
max_samples = depth * allocated_samples
initial_samples = min(allocated_samples, max_samples)

0xFF References