我看到一个简单的存储循环出乎意料地表现不佳,这个存储循环有两个存储:一个具有16字节的正向步长,另一个总是位于同一位置1,如下所示:
volatile uint32_t value;
void weirdo_cpp(size_t iters, uint32_t* output) {
uint32_t x = value;
uint32_t *rdx = output;
volatile uint32_t *rsi = output;
do {
*rdx = x;
*rsi = x;
rdx += 4; // 16 byte stride
} while (--iters > 0);
}
Run Code Online (Sandbox Code Playgroud)
在汇编这个循环可能3看起来像:
weirdo_cpp:
...
align 16
.top:
mov [rdx], eax ; stride 16
mov [rsi], eax ; never changes
add rdx, 16
dec rdi
jne .top
ret
Run Code Online (Sandbox Code Playgroud)
当访问的存储区域在L2中时,我希望每次迭代运行少于3个周期.第二个商店只是一直在同一个位置,应该添加一个周期.第一个商店意味着从L2引入一条线,因此每4次迭代也会驱逐一条线.我不确定你如何评估L2成本,但即使你保守估计L1只能在每个周期中执行以下操作之一:(a)提交商店或(b)从L2接收一行或(c)将一条线驱逐到L2,对于stride-16商店流,你会得到1 + 0.25 + …
我很难理解当翻译旁视缓冲区的前两个级别导致未命中时会发生什么?
我不确定特殊硬件电路中是否出现"页面行走",或者页表是否存储在L2/L3高速缓存中,或者它们是否只存在于主存储器中.
我们有一个简单的内存吞吐量基准.对于大块内存,它所做的只是重复记忆.
在几台不同的机器上查看结果(针对64位编译),Skylake机器的性能明显优于Broadwell-E,保持OS(Win10-64),处理器速度和RAM速度(DDR4-2133)不变.我们不是说几个百分点,而是大约2个因素.Skylake配置为双通道,Broadwell-E的结果不会因双/三/四通道而异.
任何想法为什么会这样?随后的代码在VS2015的Release中编译,并报告完成每个memcpy的平均时间:
64位:Skylake为2.2ms,Broadwell-E为4.5ms
32位:Skylake为2.2ms,Broadwell-E为3.5ms.
通过利用多个线程,我们可以在四通道Broadwell-E构建上获得更大的内存吞吐量,这很不错,但是看到单线程内存访问的这种巨大差异令人沮丧.为什么差异如此显着的任何想法?
我们还使用了各种基准测试软件,他们验证了这个简单示例所展示的内容 - 单线程内存吞吐量在Skylake上更好.
#include <memory>
#include <Windows.h>
#include <iostream>
//Prevent the memcpy from being optimized out of the for loop
_declspec(noinline) void MemoryCopy(void *destinationMemoryBlock, void *sourceMemoryBlock, size_t size)
{
memcpy(destinationMemoryBlock, sourceMemoryBlock, size);
}
int main()
{
const int SIZE_OF_BLOCKS = 25000000;
const int NUMBER_ITERATIONS = 100;
void* sourceMemoryBlock = malloc(SIZE_OF_BLOCKS);
void* destinationMemoryBlock = malloc(SIZE_OF_BLOCKS);
LARGE_INTEGER Frequency;
QueryPerformanceFrequency(&Frequency);
while (true)
{
LONGLONG total = 0;
LONGLONG max = 0;
LARGE_INTEGER StartingTime, …Run Code Online (Sandbox Code Playgroud) 我有一个最近的12核Intel CPU(Haswell架构),它有4个内存通道.机器可以并行执行多少次DRAM内存访问?
例如,如果我有一个使用12个线程的程序,这些线程位于紧密循环中,从一个范围太大而无法容纳缓存的随机存储器地址读取单个字节.我希望所有12个线程将花费几乎所有时间等待内存提取.
线程是否必须轮流使用DRAM总线?
注意:假设我使用的是1 GB的VM页面大小,因此没有TLB缓存未命中.
我需要禁用 gcc 编译的代码中的所有 AVX512 扩展。原因是 Valgrind 在 AVX512 指令上卡住了。有没有办法用一个标志来做到这一点?
我知道如何单独禁用每个扩展(-mno-avx512f等-mno-avx512pf),但这很麻烦,因为不同的 gcc 版本支持这些扩展的不同子集。
我使用CMake。如果有一种方法可以使用 CMake 机器自动化标记,这也对我有用。
较大的高速缓存通常具有较长的位线或字线,因此很可能具有更高的访问延迟和周期时间。
那么,L2 缓存是否与 L1 缓存在同一个域中工作?L3 缓存(切片)如何,因为它们现在是非包容性的并且在所有内核之间共享?
相关问题是:内核中的所有功能单元都在同一个时钟域中吗?非核心部分是否都在同一个时钟域中?多核系统中的内核是否同步?
我相信时钟域交叉会引入额外的延迟。CPU 芯片中的大部分部件是否在同一时钟域上工作?