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

时间:2013-10-28 23:31:00

标签: c optimization multidimensional-array pointer-arithmetic

我正在研究解决红/蓝计算的程序;程序是用C语言编写的。

问题描述如下:http://www.cs.utah.edu/~mhall/cs4961f10/CS4961-L9.pdf

tl; dr你有一个颜色网格(红色/蓝色/白色),第一个红色单元格按照一定的规则向右移动,然后蓝色单元格按照其他规则向下移动。

我的程序正在运行并提供正确的输出,我现在正试图看看我是否无法加速它。

使用英特尔的VTune放大器(这是一个并行编程课程,我们正在使用并行工作室集成的visual studio中进行pthread),我发现我的代码中最大的热点是移动蓝色单元格时。

实现细节:网格存储为动态分配的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;
    }

经过一番研究,我认为热点的原因(几乎是移动红细胞的4倍CPU时间)是逐列遍历时的缓存未命中。

据我所知,在引擎盖下,这个网格将被存储为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];

}

在这里,col是要处理的列,大小是网格的大小(它总是正方形)。

我在想我可能会做一些花哨的指针算术来加快速度,并且正在读这个:http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html

考虑到这一点,我觉得我可能需要更改声明网格的方式以利用2d数组指针算法,但我仍然不确定如何使用该方法遍历列。< / p>

欢迎任何有关这方面的帮助,或任何其他快速通过专栏的建议。

更新:经过一番研究和讨论后,似乎我的假设是不正确的。事实证明,由于错误共享,将结果写回全局数组的时间几乎是循环列的两倍。也就是说,我仍然有点好奇,看看是否有更好的方法进行列遍历。

1 个答案:

答案 0 :(得分:0)

我认为答案是处理瓷砖中的网格。您可以在16x16或32x32磁贴中向下或向右快速移动磁贴。它们的两个动作将实际相同,并以相同的速度运行:将所有值读入XMM寄存器,进行处理,写入。您可能需要在此处调查MASKMOVDQU指令。如果我理解问题的性质,您可以将磁贴重叠一行/列,如果按照通常(扫描)顺序处理它们,这将正常工作。如果没有,您必须单独处理拼接瓷砖。

在C代码中没有真正的快速方法。但是,您可以尝试(1)将您的电路板类型更改为unit8_t,(2)用算术替换所有if ...语句,如下所示:value =(mask&amp; value)| (^ mask&amp; newvalue),以及(3)在编译器选项中启用最大循环展开和自动矢量化。这将给你一个很好的加速 - 特别是避免条件。

编辑除了可以放入寄存器的图块之外,您还可以执行第二级图块,以适合您的缓存。我认为这种组合将大致以你的内存带宽运行。

EDIT 或者,使您的电路板类型为两位:将四个单元格打包到一个字节。与带有算术思想的替换if语句完美匹配:)