在 mbuf 中嵌入缓存对齐的元数据
Embedding cache aligned meta data inside mbuf
我正在开发自己的 dpdk 应用程序,我希望接收到的数据包能够依次通过多个线程。每个单独的线程都有自己的职责来检查数据包并为每个单独的数据包生成一些元数据。在线程之间传输数据包的最简单和最有效的方法似乎是使用 rte rings。但是,我还需要将每个线程生成的元数据传输到下一个线程。我尝试使用元数据结构数组并解析指向下一个线程的指针来执行此操作。然而,这种方法被证明是低效的,因为我有很多缓存未命中。
作为解决方案,我想到了将每个线程生成的元数据放入 mbufs 本身。这似乎可以通过 mbufs 的“动态字段”来实现。但是,此功能的文档似乎非常有限。对于我的应用程序,我希望在这样的动态字段中使用元数据字段,
typedef struct {
uint32_t packet_id;
uint64_t time_stamp;
uint8_t ip_v;
uint32_t length;
.........
.........
} my_metadata_field;
我不明白的是space我可以使用多少动态字段?在 dpdk 文档中唯一提到的是,
"10.6.1. Dynamic fields and flags
The size of the mbuf is constrained and limited; while the amount of
metadata to save for each packet is quite unlimited. The most basic
networking information already find their place in the existing mbuf
fields and flags.
If new features need to be added, the new fields and flags should fit
in the “dynamic space”, by registering some room in the mbuf
structure:
dynamic field -
named area in the mbuf structure, with a given size (at least 1 byte) and alignment constraint."
这对我来说意义不大。我对这个字段有多少记忆?如果它几乎是无限的,如果我使用一个大的元数据字段,我必须权衡什么? (性能方面)
我用的是dpdk 20.08
编辑:
经过一些挖掘,我放弃了使用动态字段作为元数据的想法,因为缺少文档而且它似乎不能容纳超过 64 位。
我正在寻找一种简单的方法将我的元数据嵌入到缓存对齐的 mbufs 中(最好使用上面的结构),这样我就可以使用 rte rings 在线程之间共享它们。我正在寻找适合我的文档或参考项目。
有几种方法可以将元数据与 MBUF 一起携带。以下是执行相同操作的选项
- 在函数
rte_mempool_create
中而不是将 private_data_size 作为 0 传递大小作为 custom metadata size
.
- 在函数
rte_pktmbuf_pool_create
中而不是将 priv_size 作为 0 传递大小作为 custom metadata size
- 如果元数据的大小小于 128 字节,则在 rte_mbuf
之后使用类型转换访问内存区域
- 如果DPDK应用中没有使用外部缓冲区,更新rte_mbuf
shinfo or next
解决方案 1:rte_mempool_create("FIPS_SESS_PRIV_MEMPOOL", 16, sess_sz, 0, sizeof(my_metadata_field), NULL, NULL, NULL, NULL, rte_socket_id(), 0);
解决方案 2:rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, sizeof(my_metadata_field), RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
解决方案 3:
struct rte_mbuf *bufs[BURST_SIZE];
const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
if (unlikely(nb_rx == 0))
continue;
for (int index = 0; index < nb_rx; index++)
{
assert(sizeof(my_metadata_field) <= RTE_CACHE_LINE_SIZE);
my_metadata_field *ptr = bufs[index] + 1;
...
...
...
}
解决方案 4:
privdata_ptr = rte_mempool_create("METADATA_POOL", 16 * 1024, sizeof(my_metadata_field), 0, 0,
NULL, NULL, NULL, NULL, rte_socket_id(), 0);
struct rte_mbuf *bufs[BURST_SIZE];
const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
if (unlikely(nb_rx == 0))
continue;
for (int index = 0; index < nb_rx; index++)
{
void *msg = NULL;
if (0 == rte_mempool_get(privdata_ptr, &msg))
{
assert(msg != NULL);
bufs[index]->shinfo = msg;
continue;
}
/* free the mbuf as we are not able to retrieve the private data */
}
/* before transmit or pkt free ensure to release object back to mempool via rte_mempool_put */
我正在开发自己的 dpdk 应用程序,我希望接收到的数据包能够依次通过多个线程。每个单独的线程都有自己的职责来检查数据包并为每个单独的数据包生成一些元数据。在线程之间传输数据包的最简单和最有效的方法似乎是使用 rte rings。但是,我还需要将每个线程生成的元数据传输到下一个线程。我尝试使用元数据结构数组并解析指向下一个线程的指针来执行此操作。然而,这种方法被证明是低效的,因为我有很多缓存未命中。
作为解决方案,我想到了将每个线程生成的元数据放入 mbufs 本身。这似乎可以通过 mbufs 的“动态字段”来实现。但是,此功能的文档似乎非常有限。对于我的应用程序,我希望在这样的动态字段中使用元数据字段,
typedef struct {
uint32_t packet_id;
uint64_t time_stamp;
uint8_t ip_v;
uint32_t length;
.........
.........
} my_metadata_field;
我不明白的是space我可以使用多少动态字段?在 dpdk 文档中唯一提到的是,
"10.6.1. Dynamic fields and flags
The size of the mbuf is constrained and limited; while the amount of metadata to save for each packet is quite unlimited. The most basic networking information already find their place in the existing mbuf fields and flags.
If new features need to be added, the new fields and flags should fit in the “dynamic space”, by registering some room in the mbuf structure:
dynamic field - named area in the mbuf structure, with a given size (at least 1 byte) and alignment constraint."
这对我来说意义不大。我对这个字段有多少记忆?如果它几乎是无限的,如果我使用一个大的元数据字段,我必须权衡什么? (性能方面)
我用的是dpdk 20.08
编辑:
经过一些挖掘,我放弃了使用动态字段作为元数据的想法,因为缺少文档而且它似乎不能容纳超过 64 位。 我正在寻找一种简单的方法将我的元数据嵌入到缓存对齐的 mbufs 中(最好使用上面的结构),这样我就可以使用 rte rings 在线程之间共享它们。我正在寻找适合我的文档或参考项目。
有几种方法可以将元数据与 MBUF 一起携带。以下是执行相同操作的选项
- 在函数
rte_mempool_create
中而不是将 private_data_size 作为 0 传递大小作为custom metadata size
. - 在函数
rte_pktmbuf_pool_create
中而不是将 priv_size 作为 0 传递大小作为custom metadata size
- 如果元数据的大小小于 128 字节,则在 rte_mbuf 之后使用类型转换访问内存区域
- 如果DPDK应用中没有使用外部缓冲区,更新rte_mbuf
shinfo or next
解决方案 1:rte_mempool_create("FIPS_SESS_PRIV_MEMPOOL", 16, sess_sz, 0, sizeof(my_metadata_field), NULL, NULL, NULL, NULL, rte_socket_id(), 0);
解决方案 2:rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, sizeof(my_metadata_field), RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
解决方案 3:
struct rte_mbuf *bufs[BURST_SIZE];
const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
if (unlikely(nb_rx == 0))
continue;
for (int index = 0; index < nb_rx; index++)
{
assert(sizeof(my_metadata_field) <= RTE_CACHE_LINE_SIZE);
my_metadata_field *ptr = bufs[index] + 1;
...
...
...
}
解决方案 4:
privdata_ptr = rte_mempool_create("METADATA_POOL", 16 * 1024, sizeof(my_metadata_field), 0, 0,
NULL, NULL, NULL, NULL, rte_socket_id(), 0);
struct rte_mbuf *bufs[BURST_SIZE];
const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
if (unlikely(nb_rx == 0))
continue;
for (int index = 0; index < nb_rx; index++)
{
void *msg = NULL;
if (0 == rte_mempool_get(privdata_ptr, &msg))
{
assert(msg != NULL);
bufs[index]->shinfo = msg;
continue;
}
/* free the mbuf as we are not able to retrieve the private data */
}
/* before transmit or pkt free ensure to release object back to mempool via rte_mempool_put */