c语言 - 共享内存的 mmap 性能能否提高?



我正在为Wayland编写一个小程序,该程序使用软件渲染和wl_shm进行显示。这需要我将屏幕缓冲区的文件描述符传递给Wayland服务器,然后Wayland服务器在其上调用mmap(),即屏幕缓冲区必须可在进程之间共享。

在这个程序中,启动延迟是关键。目前,只剩下一个瓶颈:屏幕缓冲区的初始绘制,整个缓冲区都被覆盖。下面的代码显示了这个的简化版本:

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
/* Fullscreen buffers are around 10-30 MiB for common resolutions. */
const size_t size = 2880 * 1800 * 4;
int fd = memfd_create("shm", 0);
ftruncate(fd, size);
void *pool = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
/* Ideally, we could just malloc, but this memory needs to be shared. */
//void *pool = malloc(size);
/* In reality this is a cairo_paint() call. */
memset(pool, 0xCF, size);
/* Subsequent paints (or memsets) after the first take negligible time. */
}

在我的笔记本电脑上,上面的memset()大约需要21-28毫秒。切换到malloc()的内存会将其降至12毫秒,但问题是需要在进程之间共享内存。在我的桌面上的行为类似:mmap()为7毫秒,malloc()为3毫秒。

我的问题是:我是否缺少一些可以提高Linux上共享内存性能的东西?我尝试过madvise()MADV_WILLNEEDMADV_SEQUENTIAL,以及使用mlock(),但都没有什么不同。我也考虑过2MB的巨大页面是否会有帮助,因为缓冲区大小约为10-30MB,但这通常不可用。

编辑:我试过mmap()MAP_ANONYMOUS | MAP_SHARED,它和以前一样慢。MAP_ANONYMOUS | MAP_PRIVATE产生与malloc()相同的速度,但这违背了目的。

malloc()mmap()之间的性能差异似乎是由于透明护肩的不同应用。

默认情况下,在x86_64上,页面大小为4KiB,大页面大小为2MiB。透明的Hugepages允许不了解Hugepages的程序仍然使用它们,从而减少页面错误。然而,这在默认情况下仅对私有匿名内存启用,因此对于设置了MAP_ANONYMOUS | MAP_PRIVATEmalloc()mmap(),这解释了为什么它们的性能相同。对于共享内存映射,这将被禁用,从而导致更多的页面处理开销(对于我需要的10-30MiB缓冲区(,并导致速度减慢。

可以通过/sys/kernel/mm/transparent_hugepage/shmem_enabled旋钮为共享内存映射启用Hugepages,如内核文档页面中所述。这默认为never,但将其设置为always(或advise,并添加相应的madvise(..., MADV_HUGEPAGE)调用(允许使用MAP_SHARED映射的内存使用hugepage,并且性能与malloc()的内存匹配。

我不确定为什么共享内存的默认值是never。虽然不是很令人满意,但目前看来,唯一的解决方案是使用madvise(MADV_HUGEPAGE)来提高任何碰巧将shmem_enabled设置为至少advise的系统的性能(或者如果将来默认启用(。

最新更新