【问题标题】:Optimizing C code with loop unrolling/code motion使用循环展开/代码运动优化 C 代码
【发布时间】:2013-02-01 04:08:35
【问题描述】:

我有一项任务是优化一段 C 代码(一种我相当讨厌的语言),旨在模拟图像中的旋转像素:

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

pixelRIDX 的定义如下:

typedef struct {
    unsigned short red;
    unsigned short green;
    unsigned short blue;
} pixel;

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

作业说明包含注释:“您的任务是重写此代码,使其使用代码移动、循环展开等技术尽可能快地运行 并阻止。”

我想我对如何解决这个问题有一些想法。但是,我尝试循环展开:

void rotate_unroll(int dim, pixel *src, pixel *dst) {
    int i, j;
    for (i = 0; i < dim; i++) {
        for (j = 0; j < dim; j+=4) {
            dst[RIDX(dim-1-j, i, dim)] = src[RIDX(i, j, dim)];
            dst[RIDX(dim-1-(j+1), i, dim)] = src[RIDX(i, j+1, dim)];
            dst[RIDX(dim-1-(j+2), i, dim)] = src[RIDX(i, j+2, dim)];
            dst[RIDX(dim-1-(j+3), i, dim)] = src[RIDX(i, j+3, dim)];
        }
    }
}

和代码运动(或至少重新组织 RIDX 并将一些计算移出内部循环):

void rotate_motion(int dim, pixel *src, pixel *dst) {
    int i, j;
    int dimsquared = dim * dim;
    for (i = 0; i < dim; i++) {
        int dst_temp = dimsquared - dim + i;
        int src_temp = i * dim;
        for (j = 0; j < dim; j++) {
            dst[dst_temp - (dim * j)] = src[src_temp + j];
        }
    }
}
//   dst[RIDX(dim-1-j, i, dim)] 
// = dst[(dim-1-j)dim + i] 
// = dst[(dim * dim) - dim - (dim)j + i]
//   src[RIDX(i, j, dim)]
// = src[(dim)i + j]

似乎没有工作;与作业打包在一起的计时器声称我的解决方案对程序的 CPE 没有任何影响。我怀疑我可能错误地使用了这两种方法,并且非常感谢任何正确方向的指导。 (这是一个家庭作业,所以我不是要求一个完整的解决方案,只是一些指针。)

我的另一个想法是尝试添加一个累加器——类似于以下内容:

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

但是我的语法非常错误,我不确定如何构建相关结构的临时版本。

非常感谢任何帮助。谢谢!

【问题讨论】:

  • 注意:您通常不需要在现实世界中执行此操作。大多数编译器比你更了解如何做这些事情。但是,了解这是如何发生的很有用
  • 当你编译它时,确保禁用所有优化 - 不要让编译器“智取”你 :D 另外,检查生成的“汇编”代码。

标签: c optimization


【解决方案1】:

您需要对 C 中的指针有一个透彻的了解。简单地说:指针表示数据在内存中的存储地址(在您的情况下为像素结构)。

在您的代码中,函数rotate_acc 将像素指针作为参数:pixel *dst。一开始你可能会说pixel *tmp = dst,但请记住,这就是所谓的浅拷贝——只复制地址,而不是它指向的数据——因此如果你修改tmp 说tmp-&gt;red = 0,它也会修改原始数据

如果你需要深拷贝,你需要说pixel tmp = *dst

【讨论】:

  • 嗯。我认为这是沿着这些思路。访问 tmp 中的值并将 tmp 重新分配回 dst 的语法是什么?我现在的问题是抛出错误。 (“下标值既不是数组也不是指针”和“从类型‘pixel’分配给类型‘struct pixel *’时不兼容的类型”)。谢谢!
【解决方案2】:

试试这个:

void naive_rotate(int dim, pixel *src, pixel *dst) {
    int dimSq = dim * dim;
    int dstdIxStart = dimSq - dim;
    int endIdx = dimSq - 2 * dim - 2;
    int dstIdx = dimSq - dim;
    for (int i = 0; int < endIdx; ++i)
    {
       dst[dstIdx--] = src[i];
       if (0 == dstIdx)
       {
          dstdIxStart -= dim;
          dstIdx = dstdIxStart;
       }
    }
}

你必须仔细检查数学,但我希望你能明白。

它删除了所有的乘法。此外,由于src 是按顺序访问的,因此对缓存也有好处。

【讨论】:

  • 感谢您将这些放在一起...您能否解释一下您用来获得此结果的中间步骤?根据与作业一起打包的测试,这里的数学不太好,我不确定你是如何从初始函数到这个的。谢谢:)
猜你喜欢
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多