我有一个流过 250 MB 数据的应用程序,对数据块(每个只有 2 个 32 位字)应用一个简单而快速的神经网络阈值函数。基于(非常简单的)计算的结果,该块不可预测地被推入 64 个 bin 之一。所以它是一个大流输入和 64 个较短(可变长度)的流输出。
使用不同的检测功能重复多次。
计算受内存带宽限制。我可以这么说,因为即使我使用计算量更大的判别函数,速度也没有变化。
构建新流的写入以优化我的内存带宽的最佳方法是什么?我特别认为了解缓存使用和缓存行大小可能在其中发挥重要作用。想象一下最坏的情况,我有 64 个输出流,运气不好,许多都映射到同一个缓存行。然后,当我将接下来的 64 位数据写入流时,CPU 必须将过时的缓存行刷新到主内存,并加载到正确的缓存行中。每个都使用 64 字节的带宽......所以我的带宽受限应用程序可能会浪费 95% 的内存带宽(不过,在这个假设的最坏情况下)。
甚至很难衡量效果,因此围绕它设计的方法更加模糊。还是我什至在追逐一个幽灵瓶颈,以某种方式硬件优化得比我好?
如果这有什么不同,我正在使用 Core II x86 处理器。
编辑:这是一些示例代码。它流过一个数组并将其元素复制到伪随机挑选的各种输出数组。使用不同数量的目标箱运行相同的程序会产生不同的运行时间,即使完成了相同数量的计算和内存读取和写入:
2 个输出流:13 秒
8 个输出流:13 秒
32 个输出流:19 秒
128 个输出流:29 秒
512 个输出流:47 秒
使用 512 与 2 个输出流之间的差异是 4 倍,(可能??)由缓存行驱逐开销引起。
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
int main()
{
const int size=1<<19;
int streambits=3;
int streamcount=1UL<<streambits; // # of output bins
int *instore=(int *)malloc(size*sizeof(int));
int **outstore=(int **)malloc(streamcount*sizeof(int *));
int **out=(int **)malloc(streamcount*sizeof(int));
unsigned int seed=0;
for (int j=0; j<size; j++) instore[j]=j;
for (int i=0; i< streamcount; ++i)
outstore[i]=(int *)malloc(size*sizeof(int));
int startTime=time(NULL);
for (int k=0; k<10000; k++) {
for (int i=0; i<streamcount; i++) out[i]=outstore[i];
int *in=instore;
for (int j=0; j<size/2; j++) {
seed=seed*0x1234567+0x7162521;
int bin=seed>>(32-streambits); // pseudorandom destination bin
*(out[bin]++)=*(in++);
*(out[bin]++)=*(in++);
}
}
int endTime=time(NULL);
printf("Eval time=%ld\n", endTime-startTime);
}