关注了就能看到更多这么棒的文章哦~
Two performance-oriented patches: epoll and NUMA balancing
By Jonathan Corbet
November 4, 2022
DeepL assisted translation
https://lwn.net/Articles/913291/
人们一直致力于在内核中找到更多的提升性能的方法。最近,出现了很多小 patch,至少对于某些类型的应用程序来说,据说会得到性能提升。请继续阅读本文了解其中两个 patch,它们分别对 epoll 系统调用和 NUMA balancing 进行了修改。这些工作显示了开发人员正在哪些地方想办法进行性能改进,并且不是每个人都在以同样的方式来衡量性能。
An epoll optimization
epoll 这一系列的系统调用是用在那种处理大量文件描述符的 event-loop 类型的应用程序里的。与 poll()或 select()不同,epoll 可以对 每个 file descriptor 进行一次设置(使用 epoll_ctl()),然后就可以多次使用 epoll_wait() 来轮询新的 event。这大大降低了系统轮询的整体开销,尤其是在被监控的文件描述符的数量增加了的时候。epoll 系统调用增加了一些复杂性,但是对于那些非常关注每一个 event 的性能的应用程序来说,这个麻烦是值得的。
通常情况下,epoll_wait()会阻塞这个调用进程(calling process),直到 polling 的文件描述符中至少有一个准备好进行 I/O 的情况才会唤醒进程。不过,这里有一个 timeout 参数,可以用来限制应用程序被 block 的时长。然而,这里没有办法指定 epoll_wait() 调用返回前的至少要 block 多久时间。这其实也不令人意外;一般来说,没有人希望没有必要地增加应用程序的延迟,所以 epoll_wait() 在设计上就会看到有事情要做时就马上返回。
不过,Jens Axboe 的这组 patch set 还是增加了这个最小等待时间。其中创建了一个新的 epoll_ctl()操作,也就是 EPOLL_CTL_MIN_WAIT,用来指定后续的 epoll_wait() 调用在返回用户空间之前应该阻塞的最短时间。这个功能看似违反直觉,但是背后的原因是希望增加每个 epoll_wait()调用所能返回的 event 的数量。即使去除了大部分的 setup 工作,每次系统调用仍然是有开销的。在短时间内预计会有许多 event 到来的情况下,值得等一下,等到出现几个事件之后只进行一次系统调用来节省开销。
换句话说,应用程序可能想用一点延迟,来换取更好的整体吞吐量。这似乎是一个常见的用例;正如 Axboe 所说:
为了获得中等的工作负载效率(medium workload efficiency),一些 production 场景下在调用 epoll_wait()之前先在代码中加上了一个定时器或睡眠,从而得到更好的批处理效果以及更高的效率。虽然这确实有帮助,但这种做法的效率却不尽如人意。
他说,使用这个功能之后,可以减少 6-7%的 CPU 使用率。Axboe 正在征求大家对这个 API 的意见;尤其是应不应该用 epoll_ctl()来一次性地设置最小超时,还是应该在每次 epoll_wait()调用时都提供。所以潜在用户目前最应该表达一下他们的倾向性了。
Control over NUMA balancing
非统一内存访问(NUMA,Non-uniform memory access)系统有一个特点, RAM 访问时间不固定。某个线程访问那些属于当前线程所运行的 node 中的内存时,速度比访问系统中其他 node 的内存要快。因此,在这样的系统中,如果应用程序的内存位于它们所运行的 node 上,性能会更好。为了实现这一点,内核需要进行 NUMA balancing 操作,也就是在系统中移动 page,使它们驻留在实际使用它的 node 上。
NUMA balancing,如果实现地很完美,就可以提高内存速度,进而改善系统的吞吐量。但是,NUMA balancing 也会给应用程序带来短时间的高延迟现象,主要是因为在内核在 node 之间迁移 page 时,这些 page 会产生 page fault。这里的罪魁祸首,通常是由于竞争进程的 mmap_lock 锁。对于一些对 latency 很敏感的应用程序来说这就是一个问题了;似乎有一些应用程序为了避免在 NUMA balancing 过程中被拖慢,宁愿让内存的位置不是最优化。
对于这样的应用程序,Gang Li 发布了一组 patch set,增加了一个新的 prctl()操作,也就是 PR_NUMA_BALANCING,可以用来控制是否为调用它的进程来执行 NUMA balancing。如果该进程禁用了 NUMA balancing,那么 page 会被留在原地,哪怕需要更长的访问时间。在附上的基准测试中可以看到,禁用 NUMA balancing 之后带来的性能影响会根据不同的工作负载而有很大差异。这个功能对很多应用来说都没有用,但似乎有一些应用会从中受益。
内核开发社区总是在竭力减少添加到内核中的调节开关(tuning knobs)。因为每一个可以调整的参数都是社区的维护负担,但更重要的是,这些调节开关对应用程序开发人员和系统管理员来说也是一个负担。这些用户甚至很难了解到所有可供使用的参数,更不用说将它们设置对,从而获得最佳性能。对于内核来说,最好是尽可能地自己调整,从而获得最佳效果。
上面的 patch 就说明,这种自我调整并不是永远可行的,至少在目前的技术状态下可能做不到。当不同的应用程序需要优化不同的指标时,为所有的应用程序实现最好的性能就变得更加困难。因此,其中一个 patch 允许开发人员优先优化吞吐量而损害延迟,另一个 patch 则相反。这些多样的需求似乎说明,那些想要从他们的应用程序中进一步获取一些性能的人都得继续调整这些调节开关了。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~