文章摘要
文章指出,随着磁盘带宽的指数级增长,而内存访问延迟却停滞不前,直接从磁盘获取数据可能比从内存缓存更快。作者通过实验证明,传统观念认为内存比磁盘快的观点已不再完全适用,需要新的工具来利用正在扩展的技术,避免不再适用的旧方法。
文章总结
标题:内存慢,磁盘快 - 第二部分
主要内容:
在本文中,作者通过一系列实验和代码示例,挑战了传统计算机科学中“内存快,磁盘慢”的观念。文章的核心观点是,随着硬件的发展,磁盘带宽呈指数级增长,而内存访问延迟却停滞不前,因此直接从磁盘读取数据在某些情况下可能比从内存缓存中读取更快。
实验设置: 作者使用了一台配置较为陈旧的服务器,搭载了AMD EPYC 7551P处理器、96GB DDR4内存和两块三星PM983a PCIe 3.0 SSD。通过创建一个RAID 0卷,并使用50GB的数据集进行基准测试,作者展示了如何通过优化代码和IO管道来提升性能。
简单循环与展开循环:
作者首先编写了一个简单的C语言程序,通过mmap()将文件映射到内存中,并统计其中值为10的整数数量。初始测试结果显示,从磁盘读取数据的速度仅为0.61 GB/s,而从内存缓存中读取的速度为3.71 GB/s。随后,作者通过展开循环和使用向量化指令,将性能提升至5.51 GB/s。
磁盘IO优化:
为了进一步优化,作者编写了一个基于io_uring的IO引擎,通过多线程和队列管理,直接从磁盘读取数据并进行处理。最终,磁盘读取速度达到了5.81 GB/s,超过了从内存缓存中读取的速度。
内存与磁盘的瓶颈分析:
作者指出,mmap()在访问内存时存在较高的延迟,尤其是在处理大文件时,每次访问4KB页面都会触发内核的页面错误处理,导致性能下降。相比之下,直接使用磁盘IO的流式处理方式能够更好地隐藏延迟,充分利用磁盘带宽。
扩展与未来展望: 作者认为,随着硬件的发展,磁盘带宽和CPU核心数量将继续增长,而内存带宽的增长相对有限。通过优化IO管道和内存访问方式,可以进一步提升性能。作者还提到,现代服务器允许将数据直接传输到CPU的L3缓存,绕过内存,从而可能实现比内存更高的带宽。
总结: 文章最后强调,虽然优化代码和IO管道需要额外的努力,但随着AI技术的发展,这些工作可以变得更加高效。作者鼓励读者挑战传统观念,充分利用硬件性能,避免不必要的资源浪费。
关键点:
- 内存访问的延迟瓶颈使得在某些情况下,直接从磁盘读取数据更快。
- 通过展开循环和向量化指令,可以显著提升内存访问性能。
- 使用io_uring等现代IO技术,可以优化磁盘读取速度,甚至超过内存缓存。
- 未来的硬件设计需要更多地考虑流式处理和带宽优化,以应对不断增长的数据需求。
结论: 内存和磁盘的性能瓶颈并非绝对,通过合理的优化和硬件利用,可以突破传统观念的限制,实现更高的数据处理效率。
评论总结
评论主要围绕作者对mmap和io_uring的性能测试展开,讨论集中在以下几个方面:
mmap与io_uring的性能对比:- 评论3(hsn915)认为标题应改为“
io_uring比mmap更快”,并指出这可能不会引起太多关注。- 引用:“Shouldn't this be 'io_uring is faster than mmap'? I guess that would not get much engagement though!”
- 评论5(bawolff)认为标题有些“点击诱饵”,并指出两种方法本质上都是从内存中读取数据,只是使用了不同的I/O方法。
- 引用:“Respectfully, the title feels a little clickbaity to me. Both methods are still ultimately reading out of memory, they are just using different i/o methods.”
- 评论3(hsn915)认为标题应改为“
mmap的优化建议:- 评论2(inetknght)建议使用
MAP_POPULATE和MAP_HUGETLB等标志来优化mmap的性能,特别是在处理大文件时。- 引用:“See several of the flags, but if you're doing sequential reading you can use MAPPOPULATE [0] which tells the OS to start prefetching pages.”
- 引用:“I fixed it by using (MAPHUGETLB | MAPHUGE1GB) [0] which drastically reduces the number of page tables needed to memory map huge files.”
- 评论9(themafia)提到可以使用
madvise()调用MADV_SEQUENTIAL来优化顺序读取。- 引用:“no madvise() call with MADV_SEQUENTIAL?”
- 评论2(inetknght)建议使用
向量指令和编译器优化:
- 评论4(titanomachy)质疑手动循环展开是否必要,认为编译器的高级优化应该能够自动生成向量化代码。
- 引用:“Is the manual loop unrolling really necessary to get vectorized machine code? I would have guessed that the highest optimization levels in LLVM would be able to figure it out from the basic code.”
- 评论2(inetknght)提到AVX2和AVX512指令可能导致CPU热节流,特别是在较旧的CPU上。
- 引用:“Also note that AVX2 and/or AVX512 instructions are notorious for causing thermal throttling on certain (older by now?) CPUs.”
- 评论4(titanomachy)质疑手动循环展开是否必要,认为编译器的高级优化应该能够自动生成向量化代码。
PCIe与内存带宽的讨论:
- 评论7(juancn)和评论8(modeless)讨论了PCIe带宽是否真的高于内存带宽,指出这取决于具体的硬件配置和访问模式。
- 引用:“This doesn't sound right, a PCIe 5.0 x16 slot offers up to 64 GB/s. That's fully saturated, a fairly old Xeon server can sustain >100 GB/s memory reads per numa node without much trouble.”
- 引用:“Wait, PCIe bandwidth is higher than memory bandwidth now? That's bonkers, when did that happen?”
- 评论7(juancn)和评论8(modeless)讨论了PCIe带宽是否真的高于内存带宽,指出这取决于具体的硬件配置和访问模式。
io_uring的异步优化:- 评论10(lowbloodsugar)指出
io_uring代码针对异步操作进行了优化,而mmap代码没有进行预取,导致性能瓶颈。- 引用:“it looks like the uring code is optimized for async, while the mmap code doesn’t do any prefetching so just chokes when the OS has to do work?”
- 评论10(lowbloodsugar)指出
总结:评论者对mmap和io_uring的性能测试提出了多种优化建议,特别是针对mmap的预取和大文件处理。同时,对标题的准确性、向量指令的使用以及PCIe与内存带宽的对比也展开了讨论。