提高 3d 阵列的性能

Posted

技术标签:

【中文标题】提高 3d 阵列的性能【英文标题】:Improve performance of 3d array 【发布时间】:2014-02-08 08:35:39 【问题描述】:

我尝试遍历大型 3D 结构数组,但它的运行速度非常慢。 然后我用 1D 数组代替 3D,但没有成功。

我使用下面的结构来描述 3D 网格的一个单元格的参数:

struct cellStruct

    double v1;
    // more variables here
    double v15;
    double v16;
    double v17;
    double v18;
;

请看一下两种使用过的方法。

    3D 数组

    #define Nx 500
    #define Ny 500
    #define Nz 500
    
    cellStruct ***cell;
    cell = new cellStruct **[Nx];
    for(int i=0;i<Nx;i++)
    
        cell[i]=new cellStruct *[Ny];
        for(int j=0;j<Ny;j++)
            cell[i][j]=new cellStruct [Nz];
    
    
    for (i = 0; i< Nx; ++i)
        for (j = 0; j< Ny; ++j)
            for (k = 0; k< Nz; ++k)
            
                // big algorithm that uses array like in string below
                cell[i][j][k+1].v1 = cell[i][j+1][k-1].v2 *
                                     cell[i+1][Ny-1][k+1].v5;
            
    

    一维数组

    #define cell(i,j,k) (cells[(i)*Ny*Nz + (j)*Ny + (k)])
    cellStruct *cells = new cellStruct [Nx*Ny*Nz];
    for (i = 1; i< Nx-1; ++i)
        for (j = 1; j< Ny-1; ++j)
            for (k = 1; k< Nz-1; ++k)
            
                cell(i,j,k+1).v1 = cell(i,j+1,k-1).v2 * cell(i+1,Ny-1,k+1).v5;
            
    

在情况 2 中程序运行得更慢。 我还能如何改进使用大型 3D 阵列的方法? 使用浮点变量可以将计算速度提高两倍,但我希望获得更高的准确性。 使用带有指向内部变量的指针的结构可能会更好,如下所示?

struct cells

    double ***v1;
    // ...
    double ***v15;
    double ***v16;
    double ***v17;
    double ***v18;
;

【问题讨论】:

***.com/questions/9951603/… ***.com/questions/7734693/… 如果你的大小都是预处理器定义的,那么你不妨声明cellStruct[Nx][Ny][Nz]。另外请注意,在第一个示例中,您的程序可能会因为 for (k=0; k&lt;Nz; ++k) 而不是 for (k=0; k&lt;Nz-1; ++k) 而崩溃。 您是否编译过优化代码?这可能会提高性能。另外,当你的结构单元只包含双精度时,你也可以尝试将它写成数组,这样cell[i][j+1][k-1].v2 就变成了cell[i][j+1][k-1][2],也许这有更多的优化潜力...... 最近正在帮助解决类似的性能问题,因此请查看我的答案以获取见解。切换到浮点数会使处理数据减半,因此第 3 条更适合您。 PS。指针魔术不会为您带来任何有用的东西 【参考方案1】:

500^3 是一个相当大的尺寸 -> 125M 个细胞

所以静态分配是不可能的 每个双精度为 8 字节,因此对于 8B x 125M = 1G 字节内的每个双精度(在这种情况下,G 是 1000^3 而不是 1024^3 !!!) 所以单元格内的每个双变量约为 1GB 那么定义 n[GB] 数据处理的慢运行时意味着什么?

你只能这样做:

1.重写计算以提高效率

所以计算出的数据至少适合 L1 缓存 这意味着以块的形式计算所有内容 当然,如果您没有重复使用单元格,那么您没有什么可以改进的

2.使用多线程

尝试并行化您的计算 但是您的数据非常庞大,因此这种方法甚至会减慢速度,所以要小心!!! 当您的数据无法放入缓存中时,您的计算能力就像更强大的 386 机器!!!

3.打包输入数据

对您来说最好的选择是一些细胞包装算法 它们是否属于体素? 因此相邻单元格应该相似(区域内) 我强烈推荐 RLE(游程编码) 对于此类数据(至少对于我假设您使用的数据)而言,它既快速又非常高效 如果您的数据不适合 RLE,则将单元格划分为区域并使用 DCT/iDCT(如 jpg 压缩) 打包/解包数据应该会大大缩短您的计算时间 因为打包后您的数据集可能会变得非常非常小

【讨论】:

【参考方案2】:

既然你想提高你的缓存效率,那么将结构数组转换成数组结构会对你有所帮助。

我几乎可以肯定,您也必须将三重间接指针转换为一维数组,以使 struct-of-arrays 的想法有效。

struct cellStruct

    double* v1; // you can use std::vector<double> instead of double*
    // more variables here
    double* v15;
    double* v16;
    double* v17;
    double* v18;
;

由于您的计算仅使用v1v2v5,因此最好禁用缓存所有其他变量。使用 struct-of-arrays 布局为v1v2v3 等分配不同的内存区域——因此您不会强制缓存加载这些无用的v3v4v6 , ...

一些语法调整:

#define CELL_ACCESS(cells,vn,i,j,k) (cells.vn[(i)*Ny*Nz + (j)*Ny + (k)])
cellStruct cells;
cells.v1 = new double[Nx*Ny*Nz]; // if you use std::vector, adjust code accordingly
cells.v2 = new double[Nx*Ny*Nz];
...
for (i = 1; i< Nx-1; ++i)
    for (j = 1; j< Ny-1; ++j)
        for (k = 1; k< Nz-1; ++k)
        
            CELL_ACCESS(     cells, v1, i,   j,    k+1) =
                CELL_ACCESS( cells, v2, i,   j+1,  k-1) *
                CELL_ACCESS( cells, v5, i+1, Ny-1, k+1);
        

【讨论】:

以上是关于提高 3d 阵列的性能的主要内容,如果未能解决你的问题,请参考以下文章

RAID磁盘阵列笔记

RAID磁盘阵列的原理

RAID阵列

延伸的3D阵列

RAID (廉价冗余磁盘阵列)

linux磁盘冗余阵列