这是cachegrind输出的一部分。这部分代码已经执行了1224次。 elmg1是一个无符号长度为16 x 20的数组。我的机器L1高速缓存大小为32KB,64B高速缓存行大小和8路组关联。
一个。我把它放在这里的原因是,在for循环内的第3行,我看到了一些I1未命中(一次L2未命中)。这有点令人困惑,我无法猜出原因?
B中。我正在尝试优化(时间)一部分代码。以上只是一个小片段。我认为在我的程序内存访问中花费了很多钱。与上面的例子类似,elmg1是一个16 x 20大小的无符号长整数。当我尝试在代码中使用它时,总会有一些未命中,并且在我的程序中这些变量会发生很多。有什么建议吗?
℃。我需要分配和(有时初始化)这些unsigned longs。你能建议我应该选择哪一个,calloc或数组声明然后显式初始化。 那么缓存处理它们的方式会有什么不同吗?
感谢。
答案 0 :(得分:3)
您是否尝试展开循环?
编辑:那种难以阅读的数字并且第一次读错了。
让我们确保我正在阅读第5行的数字:
Ir 146,880
I1mr 1,224
ILmr 1
Dr 48,960
D1mr 0
DLmr 0
Dw 24,480
D1mw 0
DLmw 0
L1缓存分为两个32KByte缓存,一个用于代码I1,另一个用于数据D1。 IL& DL是L2或L3缓存,由数据和指令共享。
大量的I1mr是指令未命中而不是数据未命中,这意味着循环代码正从I1指令高速缓存中弹出。
I1在第1行和第1行未命中5总共3672,这是1224的3倍,因此每次循环运行时,您将获得3个I1缓存未命中的64Byte缓存行,这意味着您的循环代码大小介于128-192字节之间,以覆盖3个缓存行。所以那些I1在第5行未命中的原因是因为这是循环代码穿过最后一个缓存行的地方。
I would recommend using KCachegrind for viewing the results from cachegrind
编辑:有关缓存行的更多信息。
该循环代码本身看起来不像是调用1224次,因此这意味着有更多的代码将此代码推出I1缓存。
您的32Kbyte I1缓存分为512个缓存行(每个64字节)。 “8路组关联”部分意味着每个存储器地址仅映射到512个高速缓存行中的8个。如果您所配置的整个程序是一个32K字节的连续块,那么它将全部适合I1缓存,并且不会弹出任何一个。情况大多不是这样,并且对于相同的8个缓存行,将有超过8个64字节的代码内容块。让我们说你的整个程序有1Mbyte的代码(包括库),然后每组8个缓存行将有大约32(1Mbyte / 32Kbyte)代码内容为这8个缓存行。
Read this lwn.net article for all the gory details about CPU caches
编译器不能总是检测程序的哪些函数将是热点(多次调用),哪些是代码点(即错误处理程序代码,几乎从不运行)。 GCC具有函数属性hot/cold,它允许您将函数标记为热/冷,这将允许编译器将热函数组合在一个内存块中以获得更好的缓存使用(即冷代码不会推送hotcode出了缓存)。
无论如何,那些I1未命中的人真的不值得担心。