在C中遍历多维数组中的列的最快方法
我目前正在做一个程序来解决红色/蓝色的计算;程序是用C语言编写的 问题描述如下: tl;dr你有一个颜色网格(红/蓝/白),首先红细胞根据特定规则向右移动,然后蓝细胞根据其他规则向下移动 我已经让我的程序运行并给出正确的输出,现在我正在尝试看看是否我根本不能加速它 使用Intel的VTune放大器(这是一门并行编程课程,我们在visual studio中使用集成了并行studio的pthreads),我发现代码中最大的热点是移动蓝色单元格 实现细节:网格存储为动态分配的int**,设置如下在C中遍历多维数组中的列的最快方法,c,optimization,multidimensional-array,pointer-arithmetic,C,Optimization,Multidimensional Array,Pointer Arithmetic,我目前正在做一个程序来解决红色/蓝色的计算;程序是用C语言编写的 问题描述如下: tl;dr你有一个颜色网格(红/蓝/白),首先红细胞根据特定规则向右移动,然后蓝细胞根据其他规则向下移动 我已经让我的程序运行并给出正确的输出,现在我正在尝试看看是否我根本不能加速它 使用Intel的VTune放大器(这是一门并行编程课程,我们在visual studio中使用集成了并行studio的pthreads),我发现代码中最大的热点是移动蓝色单元格 实现细节:网格存储为动态分配的int**,设置如下 gl
globalBoard = malloc(sizeof(int *) * size);
for (i = 0; i < size; i++)
{
globalBoard[i] = malloc(sizeof(int) * size);
for (j = 0; j < size; j++)
globalBoard[i][j] = rand() % 3;
}
globalBoard=malloc(sizeof(int*)*size);
对于(i=0;i
经过一些研究,我认为造成热点的原因(CPU时间几乎是移动红细胞的4倍)是逐列遍历时的缓存未命中
我知道在引擎盖下,这个网格将被存储为1d数组,所以当我将红细胞向右移动并逐行移动时,我经常检查连续的值,因此CPU不需要经常将新值加载到缓存中,然而,逐列遍历会导致数组中跳跃的数量只会随着电路板的大小而增加
话虽如此,我还是希望这一部分能发展得更快。以下是目前的代码:
void blueStep(int col)
{
int i;
int local[size];
for (i = 0; i < size; local[i] = globalBoard[i++][col]);
for (i = 0; i < size; i++)
{
if (i < size - 1)
{
if (globalBoard[i][col] == 2 && globalBoard[i + 1][col] == 0)
{
local[i++] = 0;
local[i] = 2;
}
}
else
{
if (globalBoard[i][col] == 2 && globalBoard[0][col] == 0)
{
local[i++] = 0;
local[0] = 2;
}
}
}
for (i = 0; i < size; i++)
globalBoard[i][col] = local[i];
}
void blueStep(int col)
{
int i;
int本地[大小];
对于(i=0;i
这里,col是要处理的列,大小是网格的大小(它总是正方形)
我在想,我也许可以做一些奇特的指针运算来加速这个过程,我正在读这篇文章:
考虑到这一点,我觉得可能需要更改声明网格的方式,以便利用2d数组指针算法,但我仍然不确定如何使用该方法遍历列
欢迎对此提供任何帮助,或提供快速浏览专栏的其他建议
更新:经过更多的研究和讨论,我的假设似乎是错误的。事实证明,由于错误共享,将结果写回全局数组所需的时间几乎是在列上循环所需时间的两倍。话虽如此,我还是有点好奇,想看看是否有更好的方法来进行列遍历。我认为答案是在平铺中处理网格。您可以在16x16或32x32平铺中快速向下或向右移动平铺。这两个动作实际上是相同的,并且以相同的速度运行:将所有值读入XMM寄存器、处理、写入。您可能需要在此处研究MASKMOVDQU指令。如果我理解问题的本质,您可以将分片重叠一行/一列,如果您按照通常的(扫描)顺序处理它们,这将正常工作。如果没有,您必须单独处理缝合瓷砖 在C代码中没有真正快速的方法来实现这一点。但是,您可以尝试(1)将电路板类型更改为unit8_t,(2)如果..则替换所有。。带有算术的语句,如:value=(mask&value)|(^mask&newvalue),以及(3)在编译器选项中启用最大循环展开和自动矢量化。这将给你一个很好的加速-尤其是避免条件 编辑除了可以放入寄存器的磁贴外,还可以进行第二级的磁贴大小调整,以适合缓存。我认为这种组合将以大约你的内存带宽运行
编辑或,使电路板类型为两位:将四个单元打包为一个字节。用算术思想替换if语句非常好:)为什么不在单个连续块中分配数组?我建议回答一个类似的问题: