在每种情况下,最后一次访问内存是获取请求的数据,而其他访问是为了获取页面转换信息的各个部分。
我看到的最好的描述是在AMD的《AMD64体系结构程序员手册第2卷:系统编程》(出版物24593)的第5.3节中。 http://support.amd.com/us/Embedded_TechDocs/24593.pdf
注1:上述数字实际上并不是最糟糕的情况。在虚拟机下运行会使这些数字变得更糟。在导致包含各级页表的内存被交换到磁盘的环境下运行会使性能变得非常糟糕。
注2:不幸的是,即使知道这个细节层面也是不够的,因为所有现代处理器都有额外的缓存用于页转换层次结构的上层。就我所知,这些缓存在公共文档中记录非常少。
我试图编写一些代码,以最大化使用4k页面的TLB交换,以检查从大页面中可能获得的收益。当libhugetlbfs的malloc提供2M字节页面时,下面的内容运行快2.6倍(比4K页面快)(Intel i7,64位Debian Lenny);希望scoped_timer
和random0n
的作用很明显。
volatile char force_result;
const size_t mb=512;
const size_t stride=4096;
std::vector<char> src(mb<<20,0xff);
std::vector<size_t> idx;
for (size_t i=0;i<src.size();i+=stride) idx.push_back(i);
random0n r0n(/*seed=*/23);
std::random_shuffle(idx.begin(),idx.end(),r0n);
{
scoped_timer t
("TLB thrash random",mb/static_cast<float>(stride),"MegaAccess");
char hash=0;
for (size_t i=0;i<idx.size();++i)
hash=(hash^src[idx[i]]);
force_result=hash;
}
一种更简单的“直线”版本只使用 hash=hash^src[i]
在大页面上仅获得了16%的性能提升,但(纯属猜测)Intel的高级预取硬件可能在访问可预测时有助于4K情况(我想我可以禁用预取以调查是否如此)。
我看到了在一些HPC/Grid场景下的改善 - 特别是在具有大量RAM的机器上运行非常大的物理模型的情况下。此外,运行该模型的进程是该机器上唯一活动的程序。我怀疑,并没有进行过测量,某些DB函数(例如批量导入)也会受益。
个人认为,除非您拥有非常好的分析/理解内存访问配置文件并且它会进行大量的大内存访问,否则您不太可能看到任何显著的改进。
启用巨大的TLB页面(2MB)后,数据传输速率继续增加,对于512 MB的DMA传输速度可达5 GB/s以上。
在拥有大量内存(≥64GB)运行大型进程的服务器上,我可以获得约5%的加速。例如,对于一个16GB的Java进程,它有4M x 4kB页面,但只有4k x 4MB页面。