C 如何管理硬件缓存使用

C 如何管理硬件缓存使用,c,caching,memory,hardware,C,Caching,Memory,Hardware,我想知道是否有一种方法可以直接管理内存的哪些部分被加载(并保存在)缓存中。我知道gcc中有内置的prefetch(),但我需要更多(至少我想我会…) 我的问题是: 我有一个循环,其中我更新了一个向量v(非常伪代码): v的长度以百万计。这个循环运行了1亿次,它以v的形式跳跃。因此,我的缓存命中率非常差,并且无法将所有的v都放入一级缓存 我可以像这样重新组织代码: for (i=0; i < length_of_v; i+=1024) { while (1) { up

我想知道是否有一种方法可以直接管理内存的哪些部分被加载(并保存在)缓存中。我知道gcc中有内置的prefetch(),但我需要更多(至少我想我会…)

我的问题是: 我有一个循环,其中我更新了一个向量v(非常伪代码):

v的长度以百万计。这个循环运行了1亿次,它以v的形式跳跃。因此,我的缓存命中率非常差,并且无法将所有的v都放入一级缓存

我可以像这样重新组织代码:

for (i=0; i < length_of_v; i+=1024) {
    while (1) {
        update_an_entry_in_v[i:i+1023];
    }
}
for(i=0;i
也就是说,首先只处理那些我知道将只更新v[0:1023]中的条目的更新,处理所有这些,然后转到下一个块,以此类推

现在,这可能会有一个更好的缓存行为,但我想知道是否有可能使它更好。让我们关注v[0:1023]块。我仍然会在v[0:1023]内跳转,因此硬件可能认为不再需要将该内存块的一部分保留在一级缓存中,然后,砰!,我又回到那一块

所以问题变成了:有没有办法标记整个v[0:1023],以便在内部while循环之前将其加载到L1中,然后在while循环完成后将其“取消标记”


(显然,1024是一个应该调整的方便数字。使用双倍即8K内存,并且考虑到目前大多数机器至少有32-64K的一级数据缓存,应该为其他所有事情留出足够的空间。)

显然,我不知道你在做什么,这有点回避了这个问题,但是,如果你知道这些标记,你能对这些标记进行基数排序,然后按照缓存效率的顺序遍历整个过程吗?也许是因为它们被更新了,但是从我猜测的关于重新组织代码的评论来看,很可能没有,我会提到它。[由于基数排序是稳定的,但只有当它是相同的索引时,这样做在某种程度上保留了顺序]。

在哪个处理器(CPU)和编译器上?任意和全部:-)。但主要是linux上带有gcc的英特尔CPU,以及windows和linux上的icc。电力系统也会很有趣。你对此进行过基准测试吗?一般来说,您描述的问题不应该是太大的问题。好吧,我可以对blockupdate代码进行基准测试,但看看是否还有什么进一步的收获,我需要首先知道如何处理缓存…当我进行更新时,我会流式处理其他有序阵列。因此,如果我更改顺序以使v受益,那么其他阵列上也会面临同样的缓存问题:-(.顺便说一句,你的问题很有道理。毕竟,如果我可以在块中更新,那么为什么我不能将块大小指定为1?原因是我在一个块中更新的块越大,我需要通过的其他数组就越长。在两个极端,我面临着非常糟糕的缓存性能:如果块包含所有内容,那么v“的缓存不好;如果我只使用1个大小的块,那么其他数组就不好了。我正在尝试为块大小找到一个合适的媒介,而v的任何部分适合L1似乎都是最好的。如果我知道怎么做,将该块全部保留在L1中……可以提供更多的好处。我的意思是,这可能是一个愚蠢的想法,但你能将过程分解为t吗?”两个步骤允许您以缓存效率高的顺序执行流程的一部分,将中间步骤中的数据重新排序为下半部分的正确顺序,然后以第二个数组的正确顺序完成操作?显然,这将占用更多的空间(甚至可能是您现在使用的内存的两倍),但如果重新排序是缓存有效的,它可能会更快。[我不确定这是否偏离主题,您可能已经了解了这些想法,如果是这样,很抱歉]。
for (i=0; i < length_of_v; i+=1024) {
    while (1) {
        update_an_entry_in_v[i:i+1023];
    }
}