c++ - 通过循环展开和阻塞进行优化

标签 c++ optimization

我不确定我还能如何优化这段代码以使其高效。到目前为止,我已经将关于 j 的内部 for 循环展开 16,它产生的平均 CPE 为 1.4。我需要通过优化技术使平均 CPE 达到 2.5 左右。我已经阅读了与此相关的其他问题,与涉及的代码问题相比,它们有些不同。代码的第一部分显示了我给出的内容,然后是我尝试展开循环。给定的代码将扫描源图像矩阵的行并复制到目标图像矩阵的翻转行。任何帮助将不胜感激!

RIDX 宏:

#define RIDX(i,j,n) ((i)*(n)+(j))

给定:

 void naive_rotate(int dim, struct pixel_t *src, struct pixel_t *dst)
 {
 int i, j;
 for(i = 0; i < dim; i++)
     {
             for(j = 0; j < dim; j++)
             {
                dst[RIDX(dim-1-i, j, dim)] = src[RIDX(i, j, dim)];
            }
    }
}

我的尝试:这确实优化了它,但随着平均 CPE 从 1.0 上升到 1.4 而只优化了一点。我希望它在 2.5 左右,我尝试了各种类型的阻塞和我在网上阅读过的东西,但没有设法对其进行更多优化。

 for(i = 0; i < dim; i++){                                                                                                                                                  
 for(j = 0; j < dim; j+=16){                                                                                                                                                      

  dst[RIDX(dim-1-i,j, dim)] = src[RIDX(i,j,dim)];                                                                                                                                
  dst[RIDX(dim-1-i,j+1, dim)] = src[RIDX(i,j+1,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+2, dim)] = src[RIDX(i,j+2,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+3, dim)] = src[RIDX(i,j+3,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+4, dim)] = src[RIDX(i,j+4,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+5, dim)] = src[RIDX(i,j+5,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+6, dim)] = src[RIDX(i,j+6,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+7, dim)] = src[RIDX(i,j+7,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+8, dim)] = src[RIDX(i,j+8,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+9, dim)] = src[RIDX(i,j+9,dim)];                                                                                                                            
  dst[RIDX(dim-1-i,j+10, dim)] = src[RIDX(i,j+10,dim)];                                                                                                                          
  dst[RIDX(dim-1-i,j+11, dim)] = src[RIDX(i,j+11,dim)];                                                                                                                          
  dst[RIDX(dim-1-i,j+12, dim)] = src[RIDX(i,j+12,dim)];                                                                                                                          
  dst[RIDX(dim-1-i,j+13, dim)] = src[RIDX(i,j+13,dim)];                                                                                                                          
  dst[RIDX(dim-1-i,j+14, dim)] = src[RIDX(i,j+14,dim)];                                                                                                                          
  dst[RIDX(dim-1-i,j+15, dim)] = src[RIDX(i,j+15,dim)];   

最佳答案

这是一个快速的老式 memcpy 优化。这通常非常有效。应该不需要展开。

来自 RIDX:

#define RIDX(i,j,n) ((i)*(n)+(j))

我们知道递增“j”组件转化为简单的指针递增。

struct pixel_t* s = src[RIDX(0, 0, dim)];
struct pixel_t* d = dst[RIDX[dim - 1, 0, dim];

for (int i = 0; i < dim; ++i, d -= (2 * dim))
{
   for (int j = 0; j < dim; ++j, ++s, ++d)
   {
       //dst[RIDX(dim-1-i, j, dim)] = src[RIDX(i, j, dim)];
       *d = *s;  

       // you could do it the hard way and start loop unrolling from here
   }
}

在上面代码的内部循环中,++s,++d 提示可以进行 memcpy 优化。请注意,只有当我们正在复制的类型可以安全移动时,才可能进行 memcpy 优化。大多数类型是。但这是必须考虑的事情。使用 memcpy 确实稍微改变了 c++ 的严格规则,但 memcpy 很快。

然后循环变成:

struct pixel_t* s = src[RIDX(0, 0, dim)];
struct pixel_t* d = dst[RIDX[dim - 1, 0, dim];

for (int i = 0; i < dim; ++i, d -= dim, s += dim)
{
   memcpy(d, s, dim * sizeof(pixel_t));
   // or...
   std::copy(s, s + dim, d);  // which is 'safer' but could be slower...
}

在大多数现代 STL 实现中,std::copy 在大多数情况下将转换为 memcpy。 memcpy 使用书中的所有技巧来加快复制速度 - 循环展开、缓存前瞻等...

关于c++ - 通过循环展开和阻塞进行优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45226742/

相关文章:

c - 我的服务器通过网络每秒的请求非常低

c - 在计算按位运算之前,我应该将整数截短为短裤吗?

c++ - Ncurses和ostream类方法?

c++ - 字符指针比较错误

c# - 需要帮助设计进程间通信层

c - 比 fgets 更快地读取一行输入?

c++ - 按升序合并两个数组(两个数组大小相同)

c++ - 将 unsigned char 数组的元素作为整数访问

arrays - 在 MATLAB 中预分配数组的替代方法是什么?

python - 在 Python 中计算低阶近似