Elo*_*off 26 optimization x86 caching intel cpu-cache
我正在尝试在两种算法之间做出决定.一个写入8个字节(两个对齐的4字节字)到2个高速缓存行,另一个写入3个整个高速缓存行.
如果CPU只将更改的8个字节写回内存,则第一个算法使用的内存带宽要少得多:8个字节对192个字节.如果CPU写入整个高速缓存行,则128和192字节之间的差异不那么显着.
那么Intel Xeon CPU如何写回内存?你会惊讶地发现在谷歌找到一个应该众所周知的答案是多么困难.
据我了解,写入进入存储缓冲区,然后进入缓存.当脏缓存行从缓存中逐出时,它们可能只被写入内存,但是英特尔是否跟踪缓存行的哪些部分是脏的,或者只是转储整个内容?我更怀疑他们跟踪缓存行粒度以下的事情.如果在高速缓存行被驱逐之前有任何事情进入内存,我也会感到非常惊讶.
Pet*_*des 17
即使对于DRAM本身来说,局部性也很重要,甚至可以忽略缓存.对于脏缓存行的64B连续字节的突发写入比从4B到16个不同地址的16次写入快得多.换句话说,写回整个缓存行并不比写回缓存行中的几个更改字节慢得多.
每个程序员应该了解的关于内存的内容,由Ulrich Drepper解释了很多关于在编程时避免内存瓶颈的内容.他介绍了DRAM寻址的一些细节.DRAM控制器必须选择一行,然后选择一列.访问另一个虚拟内存页面也会导致TLB未命中.
DRAM确实具有用于传输顺序数据块的突发传输命令.(显然是为了回写缓存行的CPU而设计的).现代计算机中的存储器系统针对编写整个高速缓存行的使用模式进行了优化,因为这几乎总是发生.
缓存行是 CPU跟踪脏或不跟踪的单位.可以使用比现有或未高速缓存行更小的线路大小来跟踪脏度,但这将需要额外的晶体管并且不值得.设置多级缓存以传输整个缓存行,因此当需要读取整个缓存行时,它们可以尽可能快.
存在movnti/movntdqa
绕过缓存的所谓非时间读/写().这些用于数据,直到它无论如何都要从缓存中逐出(因此是非时间的)之前不会被再次触摸.对于可以从缓存中受益的数据来说,它们是个坏主意,但是可以让你将4个字节写入内存,而不是整个缓存行.根据该存储器范围的MTRR,写入可能会或可能不会写入组合.(这与存储器映射的I/O区域相关,其中两个相邻的4B写入与一个8B写入不同.)
只接触两个缓存行的算法肯定具有该分数的优势,除非需要更多的计算,或者特别是分支,以确定要写入哪个内存.如果你想要帮助决定,也许会问一个不同的问题.(请参阅https://stackoverflow.com/tags/x86/info上的链接,esp Agner Fog的指南,以获取有助于您自行决定的信息.)
请参阅Cornstalks的回答,了解有关在不同CPU上触摸同一内存时存在多个线程的危险的警告.这可能导致比单线程程序的额外写入更大的减速.
为了使CPU只将脏字节写回内存,需要为缓存中的每个字节存储一个脏位.这是不可行的,并没有在现代CPU上完成(据我所知).CPU只有一个脏位用于缓存行.写入高速缓存行中的任何字节会导致整行被标记为脏.
当需要刷新脏缓存行时,需要写入整行,因为CPU不知道哪个字节发生了变化.
这可以在高速缓存失效策略中看到,其中写入核心中的一个高速缓存行可以使不同核心中的高速缓存行无效(因为两个高速缓存行映射到相同的地址),即使第一个核心正在使用lo-高速缓存行的一半和第二个核心使用高速缓存行的一半.也就是说,如果核心1写入字节N,核心2使用字节N + 1,则核心2仍然必须刷新其缓存行,即使您和我知道它没有必要.