【问题标题】:Code Optimization, C code not Responding to Cache Blocking代码优化,C 代码不响应缓存阻塞
【发布时间】:2014-05-04 02:06:02
【问题描述】:

我正在处理一个让我们优化 C 代码的类的项目。但是,我们运行代码的服务器似乎对通常的优化技术或至少对我们所学的优化技术没有很好的响应。该作业建议使用代码移动、循环展开和阻塞。 以下是一些结构定义:

#ifndef _DEFS_H_
#define _DEFS_H_

#include <stdlib.h>

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

typedef struct {
  char *team;
  char *name1, *email1;
  char *name2, *email2;
} team_t;

extern team_t team;

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

typedef void (*lab_test_func) (int, pixel*, pixel*);

void smooth(int, pixel *, pixel *);
void rotate(int, pixel *, pixel *);

void register_rotate_functions(void);
void register_smooth_functions(void);
void add_smooth_function(lab_test_func, char*);
void add_rotate_function(lab_test_func, char*);

#endif /* _DEFS_H_ */

这是我目前正在处理的功能,它将图像旋转 90 度:

char naive_rotate_descr[] = "naive_rotate: Naive baseline implementation";
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)];
}

这是低效的基线实现。

char rotate_descr[] = "rotate: Current working version";
void rotate(int dim, pixel *src, pixel *dst) 
{
    int i, j;
    int ii, jj;
    int dim_min_one = dim - 1;

    for (i = 0; i < dim; i+=8){
        for (j = 0; j < dim; j+=8){
            for(ii = 0; ii < 8; ii++){
                for(jj = 0; jj < 8; jj+=8){
                    dst[RIDX(dim_min_one-(jj+j), (i+ii), dim)] = src[RIDX((i+ii), (j+jj), dim)];
                    dst[RIDX(dim_min_one-(jj+j+1), (i+ii), dim)] = src[RIDX((i+ii), (j+jj+1), dim)];
                    dst[RIDX(dim_min_one-(jj+j+2), (i+ii), dim)] = src[RIDX((i+ii), (j+jj+2), dim)];
                    dst[RIDX(dim_min_one-(jj+j+3), (i+ii), dim)] = src[RIDX((i+ii), (j+jj+3), dim)];
                    dst[RIDX(dim_min_one-(jj+j+4), (i+ii), dim)] = src[RIDX((i+ii), (j+jj+4), dim)];
                    dst[RIDX(dim_min_one-(jj+j+5), (i+ii), dim)] = src[RIDX((i+ii), (j+jj+5), dim)];
                    dst[RIDX(dim_min_one-(jj+j+6), (i+ii), dim)] = src[RIDX((i+ii), (j+jj+6), dim)];
                    dst[RIDX(dim_min_one-(jj+j+7), (i+ii), dim)] = src[RIDX((i+ii), (j+jj+7), dim)];

                }
            }
        }
    }
}

这是阻塞和展开的组合。

char rotate1_descr[] = "rotate1: Simple 16 blocking";
void rotate1(int dim, pixel *src, pixel *dst) 
{
    int i, j;
    int ii, jj;
    int dim_min_one = dim - 1;

    for (i = 0; i < dim; i+=16){
        for (j = 0; j < dim; j+=16){
            for(ii = 0; ii < 16; ii++){
                for(jj = 0; jj < 16; jj++){
                    dst[RIDX(dim_min_one-(jj+j), (i+ii), dim)] = src[RIDX((i+ii), (j+jj), dim)];
                }
            }
        }
    }
}

这只是阻塞。 现在正在测试代码的服务器中有 24 个 Intel(R) Xeon(R) X5660 @ 2.80GHz CPU。测试代码为阻塞和展开循环提供了 1.2 的加速,为简单阻塞提供了 1.4 的加速。

在我自己的计算机(Core i7 2.7GHz)和另一台学校服务器(24 Intel® Xeon® Processor E5-2420 at 1.9GHz)上,阻塞和展开以及仅阻塞的速度为 1.9。

在所有系统上,8 与 16 的块大小似乎在性能上没有差异,但是,32 会降低性能。

现在另一个 ES-2420 有 15mb 的缓存,而 X5660 有 12mb,但我觉得这应该不足以使阻塞的效果相形见绌,或者使展开会降低性能。我真的无法在网上找到任何关于优化 X5660 及其响应良好的技术的内容。所以我的问题是处理器的哪些差异会导致对缓存阻塞的响应产生如此大的差异,以及我可以从这种差异中获得什么来编写可以更好地运行的代码。教科书和讲座并没有真正为我提供解决此问题的工具,因为他们建议的所有技术都不适用于我们必须运行它的服务器。

【问题讨论】:

  • 您遗漏了最重要的信息,即RIDX 的定义。由于RIDX 每个像素被调用两次,这就是您开始调查的地方,如果我是正确的,您可以重写算法以完全消除RIDX
  • “dim”的值是多少? “像素”是什么类型?
  • 我在定义中添加了,dim 将是方形图片尺寸的 int,并且始终是 32 的倍数。

标签: c performance caching optimization processor


【解决方案1】:

如果您可以在每台机器上安装oprofile,您可以测量缓存未命中率和其他有趣的参数,以确定为什么您在每台机器上获得不同的加速。

【讨论】:

  • 很遗憾,我无法在服务器上安装软件。
猜你喜欢
  • 2011-05-19
  • 2016-01-18
  • 1970-01-01
  • 2016-08-31
  • 2018-01-08
  • 2012-11-13
  • 1970-01-01
  • 2013-01-17
  • 1970-01-01
相关资源
最近更新 更多