4

我想编写一个内核模块,我可以在其中获得接近 8 mbps 的 TCP/IP 数据包。我必须将这些数据包存储 500 毫秒。稍后这些数据包应按顺序转发。这些应该为 30 名成员完成。最好的实施方法应该是什么?我应该使用kmalloc一次(kmalloc(64000000, GFP_ATOMIC)吗?因为每次如果我这样做kmallockfree都需要时间,导致性能问题。另外,如果我一次性在内核中分配内存,linux内核会允许我这样做吗?

4

2 回答 2

6

我曾经写过一个内核模块处理 10Gbs 链路上的数据包。我曾经vmalloc分配大约 1GByte 的连续(虚拟)内存来将静态大小的哈希表放入其中以执行连接跟踪(代码)。

如果你知道你需要多少内存,我建议预先分配它。这有两个好处

  • 它很快(在运行时没有 mallocing/freeing)
  • kmalloc(_, GFP_ATOMIC)如果不能恢复记忆,你不必想一个策略。这实际上可能在重负载下经常发生。

坏处

  • 您可能需要分配更多的内存。

所以,为了编写一个特殊用途的内核模块,请预先分配尽可能多的内存;)

如果您为许多新手用户使用的商品硬件编写内核模块,那么按需分配内存(并且浪费更少的内存)会很好。


你在哪里分配内存?GFP_ATOMIC只能返回非常少量的内存,并且只应在您的内存分配无法休眠时使用。您可以GFP_KERNEL在可以安全睡眠时使用,例如,不在中断上下文中。有关更多信息,请参阅此问题vmalloc在模块初始化期间使用预分配所有内存是安全的。

于 2013-03-26T08:22:33.217 回答
1

由于内核更改,在Linux 内核 5.22019 年第三季度发布vmalloc)中使用老生常谈答案 会更快。

来自迈克尔·拉拉贝尔

Linux 内核的vmalloc代码有可能在 Linux 5.2 上执行得更快,尤其是在嵌入式设备上。
Vmalloc 用于在虚拟地址空间中分配连续内存,并在 Linux 5.2 合并窗口的预期最后一天看到了一个很好的优化。

作为Andrew Morton几分钟前合并的pull (commit cb6f873)的一部分,是“对 vmalloc 的重大更改,产生了巨大的性能优势”。

vmalloc 代码的主要变化是跟踪分配的空闲块
目前,新 VA 区域的分配是通过繁忙列表迭代完成的,直到在两个繁忙区域之间找到合适的空洞。因此,每个新分配都会导致列表增长。由于长列表和不同的许可参数,在嵌入式设备上分配可能需要很长时间(毫秒)。

此补丁将 vmalloc 内存布局组织到VMALLOC_START-VMALLOC_END范围的空闲区域中。它使用红黑树保持块按它们的偏移量排序,链表保持可用空间按地址递增的顺序排列。

使用来自Uladzislau Rezki的这个补丁,与 Linux 5.1 和之前的行为相比,调用vmalloc()最多可以减少 67% 的时间,至少在开发人员在 QEMU 下完成的测试中是这样。

提交,如GitHub 上的镜像,在这里

引入了一个红黑树

/*
 * This augment red-black tree represents the free vmap space.
 * All vmap_area objects in this tree are sorted by va->va_start
 * address. It is used for allocation and merging when a vmap
 * object is released.
 *
 * Each vmap_area node contains a maximum available free block
 * of its sub-tree, right or left. Therefore it is possible to
 * find a lowest match of free area.
 */

具有以下功能

/*
 * Merge de-allocated chunk of VA memory with previous
 * and next free blocks. If coalesce is not done a new
 * free area is inserted. If VA has been merged, it is
 * freed.
 */
static __always_inline void
merge_or_add_vmap_area(struct vmap_area *va,
    struct rb_root *root, struct list_head *head)

/*
 * Find a place in the tree where VA potentially will be
 * inserted, unless it is merged with its sibling/siblings.
 */

/*
 * Get next node of VA to check if merging can be done.
 */

/*
 * start            end
 * |                |
 * |<------VA------>|<-----Next----->|
 *                  |                |
 *                  start            end
 */
...
/*
 * start            end
 * |                |
 * |<-----Prev----->|<------VA------>|
 *                  |                |
 *                  start            end
 */
于 2019-05-20T16:04:07.950 回答