繁体   English   中英

C代码优化,功能流畅

[英]C Code Optimization, smooth function

对于作业,我们被要求优化代码以获得“平滑”功能,描述如下:

平滑函数将源图像src作为输入,并将平滑后的结果返回到目标图像dst中。 这是实现的一部分:

void naive_smooth(int dim, pixel *src, pixel *dst) { 
  int i, j;
  for(i=0; i < dim; i++)
    for(j=0; j < dim; j++)
      dst[RIDX(i,j,dim)] = avg(dim, i, j, src); /* Smooth the (i,j)th pixel */
  return; }

结构像素存储红色,绿色和蓝色值(整数)。 函数avg返回第(i,j)像素周围的所有像素的平均值。 您的任务是优化平滑(和平均)以尽可能快地运行。 (注意:函数avg是一个本地函数,您可以完全摆脱它以其他方式实现平滑。)此代码(以及avg的实现)位于kernels.c文件中。

任何人都知道如何优化这个?

您可以通过在矩形图块中划分矩阵/图像并一次平滑一个图块来执行循环的循环平铺/循环条带挖掘。 这样可以提高缓存利用率。

考虑当前版本。 它遍历图像,一次访问三行,写入中间一行。

a[i-1][0], a[i-1][1], ..., a[i-1][dim-1]
a[i  ][0], a[i  ][1], ..., a[i  ][dim-1]
a[i+1][0], a[i+1][1], ..., a[i+1][dim-1]

当它到达图像的最右边时,很可能会从缓存中删除前几列。 但是,当您移至下一行时,访问将非常需要以下内容:

a[i  ][0], a[i  ][1], ..., a[i  ][dim-1]
a[i+1][0], a[i+1][1], ..., a[i+1][dim-1]
a[i+2][0], a[i+2][1], ..., a[i+2][dim-1]

相反,您可以在图块中处理图像,例如:

a[i  ][B], a[i  ][B+1], ..., a[i  ][B+B-1]
a[i+1][B], a[i+1][B+1], ..., a[i+1][B+B-1]
a[i+2][B], a[i+2][B+1], ..., a[i+2][B+B-1]

其中B是瓷砖尺寸。

或带有图片,使其更清晰:

000111222
000111222
000111222
333444555
333444555
333444555
666777888
666777888
666777888

这里我们有一个9x9图像,分为9个图块,编号从0到8,你的目标是以这样的方式编写循环:首先平滑图块0中的所有像素,然后平铺图块1中的所有像素,然后全部瓦片2中的像素等。顺序并不重要,您甚至可以并行运行每个瓦片。

当然,这对于大图像和相对较大的图块是有利的,您可以尝试使用图块大小,例如,从跨越一个或两个缓存行的图块行开始。

有关此方法的更多信息,请检查循环平铺


尽管如此,值得注意的是你的编译器本身应该这样做。

根据编译器的优化可以提供的内容,这通常会受益于标准优化,例如循环展开,显式矢量化,循环阻塞以及可能的循环交换,具体取决于映像的布局方向。 这些都应包含在您的教科书或课程笔记中。 如果不是,这些就是要在线搜索的关键字。

图像平滑是结构化网格应用程序的常见示例: 结构化网格

您的应用程序肯定会从循环展开和循环重新排序技术(尤其是循环切片)中受益,您可以在此处进行研究: 优化

请注意,有效地优化结构化网格计算,尤其是在单个时间步上并不是一件容易的事,人们会因此获得博士学位: 模板探测无论如何,您的计算都非常容易,因此您应该实现显着的加速。 但是,实现循环切片可能很麻烦,并且在某些情况下适得其反,您可能需要尝试使用多面体编译器(例如Pluto) ,该编译器能够快速生成具有任意切片尺寸的切片代码。 为了获得良好的性能,在当前的体系结构中,选择正确的切片尺寸是至关重要的,因为存在硬件预取矩形切片效果更好: 缓存优化

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM