Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C中遍历多维数组中的列的最快方法_C_Optimization_Multidimensional Array_Pointer Arithmetic - Fatal编程技术网

在C中遍历多维数组中的列的最快方法

在C中遍历多维数组中的列的最快方法,c,optimization,multidimensional-array,pointer-arithmetic,C,Optimization,Multidimensional Array,Pointer Arithmetic,我目前正在做一个程序来解决红色/蓝色的计算;程序是用C语言编写的 问题描述如下: tl;dr你有一个颜色网格(红/蓝/白),首先红细胞根据特定规则向右移动,然后蓝细胞根据其他规则向下移动 我已经让我的程序运行并给出正确的输出,现在我正在尝试看看是否我根本不能加速它 使用Intel的VTune放大器(这是一门并行编程课程,我们在visual studio中使用集成了并行studio的pthreads),我发现代码中最大的热点是移动蓝色单元格 实现细节:网格存储为动态分配的int**,设置如下 gl

我目前正在做一个程序来解决红色/蓝色的计算;程序是用C语言编写的

问题描述如下:

tl;dr你有一个颜色网格(红/蓝/白),首先红细胞根据特定规则向右移动,然后蓝细胞根据其他规则向下移动

我已经让我的程序运行并给出正确的输出,现在我正在尝试看看是否我根本不能加速它

使用Intel的VTune放大器(这是一门并行编程课程,我们在visual studio中使用集成了并行studio的pthreads),我发现代码中最大的热点是移动蓝色单元格

实现细节:网格存储为动态分配的int**,设置如下

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语句非常好:)

为什么不在单个连续块中分配数组?我建议回答一个类似的问题: