2014-03-25 166 views
4

我需要访问一个带有C++代码的二维矩阵。如果矩阵是mat[n][m],我要访问(在for循环)这些位置:快速访问矩阵

mat[x][y], mat[x-1][y-m-1], mat[x-1][y], mat[x][y-1] 

下一轮迭代我必须做的:

x=x+1 

,然后再:

mat[x][y], mat[x-1][y-m-1], mat[x-1][y], mat[x][y-1] 

什么可能是这些位置最接近内存加速我的代码的最佳方式?

+5

您的矩阵将会变得多大(包括维度和元素的类型)?如果它足够小以适应L1缓存,<16KB,那么访问模式并不重要。 – Michael

+0

矩阵是一个int矩阵(258x258或258x129),所以它在130和160 Kb之间。 – cheip

+2

您的分析器是否告诉您访问矩阵是您的应用程序的瓶颈?你有尝试过并行循环吗? –

回答

0

由于您没有提供足够的信息,因此很难说哪种方法更好。

你可以尝试展开你的循环来连续访问内存。

例如,从mat[x][y]读取4次,然后mat[x-1][y-m-1] 4次,然后mat[x-1][y] 4次,然后mat[x][y-1] 4次。之后,您在一次迭代中处理加载的4组数据。

我敢打赌,瓶颈不是内存访问本身。它应该是内存地址的计算。这种内存访问方法可以写入SIMD加载,因此可以减少内存地址计算的3/4时间成本。

如果您必须按顺序处理您的任务,则可以尝试不使用多维订阅。例如:

for(x=0; x<n; x++) 
    doSomething(mat[x][y]); 

可以用做:

for(x=y; x<n*m; x+=m) 
    doSomething(mat[0][x]); 

在你避免一个lea指令第二种方式。

+0

不幸的是我不能在这种情况下使用SIMD:如果我没有完成前面的“工作”,我不能在随后的四组单元上做“工作”。 – cheip

+0

我并不是说你必须使用SIMD。你需要以更有效的方式计算你的地址。正如我对分析的经验,在关键的例程中这样的二维阵列订阅了加法和减法就是在杀死性能。 – Aean

1

如果你正在水平迭代,将矩阵排列为mat [y] [x],特别是如果它是一个数组数组(矩阵的布局在你的回答中不清晰)。

0

如果我得到这个正确的结果,你会遍历整个阵列,尽管你只提到x = x + 1作为更新(y没有)。然后我会看到阵列为一维,单个计数器i0变为总阵列长度。然后四个值在每个循环访问将

mat[i], mat[i-S-m-1], mat[i-S], mat[i-1] 

其中S是步幅(行或根据你的表现列)。无论内存布局如何,这都需要较少的地址计算。它也需要较少的索引检查/更新,因为只有一个计数器i。另外,S+m+1是不变的,所以你可以这样定义它。