我需要将大量数据读入缓冲区(大约 20gig)。我有 192gb 的非常快的 DDram 可用,所以内存大小没有问题。但是,我发现以下代码进入缓冲区越远,运行速度就越慢。 Visual C 探查器告诉我 12 分钟执行时间的 68% 是在 myFunc() 循环内的 2 条语句中。我在一个非常快的戴尔上运行 win7,64 位,有 2 个 cpu,每个 6 个物理内核(24 个逻辑内核),并且所有 24 个内核在运行时都完全用完了。
#define TREAM_COUNT 9000
#define ARRAY_SIZE ONE_BILLION
#define offSet(a,b,c,d) ( ((size_t) ARRAY_SIZE * (a)) + ((size_t) TREAM_COUNT * 800 * (b)) + ((size_t) 800 * (c)) + (d) )
void myFunc(int dogex, int ptxIndex, int xtreamIndex, int carIndex)
{
short *ptx = (short *) calloc(ARRAY_SIZE * 20, sizeof(short));
#pragma omp parallel for
for (int bIndex = 0; bIndex < 800; ++bIndex)
doWork(dogex, ptxIndex, carIndex);
}
void doWork(int dogex, int ptxIndex, int carIndex)
{
for (int treamIndex = 0; treamIndex < ONE_BILLION; ++treamIndex)
{
short ptxValue = ptx[ offSet(dogex, ptxIndex, treamIndex, carIndex) ];
short lastPtxValue = ptx[ offSet(dogex, ptxIndex-1, treamIndex, carIndex) ];
// ....
}
}
最佳答案
代码分配了 20 个 block ,每 block 10 亿个短整数。在 64 位 Windows 机器上,short int 是 2 个字节。因此分配约为 40 GB。
你说有 24 个内核,它们都已用完了。代码本身似乎没有显示任何并行性。代码并行化的方式可能会对性能产生深远的影响。您可能需要提供更多信息。
--
我怀疑您的基本问题与缓存行为和内存访问限制有关。
首先,使用两个各有六个内核的物理 CPU,您的内存总线将完全饱和。无论如何,您可能拥有 NUMA 架构,但代码中无法控制您的 calloc() 分配位置(例如,您可能将大量代码存储在内存中,需要多次跳转才能到达)。
超线程已开启。这有效地将缓存大小减半。鉴于代码是内存总线绑定(bind),而不是计算绑定(bind),超线程是有害的。 (话虽如此,如果计算始终在缓存边界之外,这不会有太大变化)。
目前尚不清楚(因为一些/很多?)代码被删除,如何访问数组以及访问模式和该模式的优化以实现缓存优化是性能的关键。
我在 offset() 的计算方式中看到的是,代码不断需要生成新的虚拟到物理地址查找 - 每个查找都需要四到五次内存访问。这本身就是扼杀性能。
我的基本建议是将数组分解为 2 级缓存大小的 block ,为每个 CPU 分配一个 block 并让它处理该 block 。您可以并行执行此操作。实际上,您可以使用超线程来预加载缓存,但这是一种更高级的技术。
关于c - 使用 64 位 Visual C 的巨大 C 数组的速度问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9989567/