Как мне оптимизировать - PullRequest
2 голосов
/ 03 октября 2009

Что я пытаюсь сделать, это взять этот код:

char naive_smooth_descr[] = "naive_smooth: Naive baseline implementation";

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);
}

и замените вызов функции avg(dim, i, j, src); фактическим кодом в самом низу страницы. Затем возьмите этот код и замените все вызовы функций в этом коде фактическим кодом и т. Д.

Если вы спрашиваете, зачем все это делать, причина проста: когда вы избавляетесь от вызовов функций, программа запускается быстрее, а я пытаюсь достичь самых быстрых циклов на элемент, когда приведенный выше код выполняется, избавляя всех вызовов функций и замены их на фактический код.

Теперь у меня действительно большие проблемы с этим. Должен ли я взять код в скобках, а затем просто скопировать и вставить? Я опускаю скобки? Нужно ли включать начало кода, например, static pixel avg(int dim, int i, int j, pixel *src), а затем скобки, а затем код для замены вызова функции?

Я собираюсь вставить весь код здесь:

/* A struct used to compute averaged pixel value */

typedef struct {

    int red;
    int green;
    int blue;
    int num;

}  pixel_sum;

/* Compute min and max of two integers, respectively */


static int min(int a, int b) { return (a < b ? a : b); }

static int max(int a, int b) { return (a > b ? a : b); }



/* 
 * initialize_ pixel_ sum - Initializes all fields of sum to 0 
 */


static void initialize_ pixel_ sum (pixel_sum *sum) 

{

    sum->red = sum->green = sum->blue = 0;
    sum->num = 0;
    return;

}

/* 
 * accumulate_sum - Accumulates field values of p in corresponding 
 * fields of sum 
 */

static void accumulate_ sum (pixel_sum *sum, pixel p) 

{

    sum->red += (int) p.red;
    sum->green += (int) p.green;
    sum->blue += (int) p.blue;
    sum->num++;
    return;

}


/* 
 * assign_ sum_ to_ pixel - Computes averaged pixel value in current_pixel 
 */

static void assign_ sum_ to_ pixel (pixel *current_ pixel, pixel_ sum sum) 

{

    current_pixel->red = (unsigned short) (sum.red/sum.num);
    current_pixel->green = (unsigned short) (sum.green/sum.num);
    current_pixel->blue = (unsigned short) (sum.blue/sum.num);
    return;

}

/* 
 * avg - Returns averaged pixel value at (i,j) 
 */

Это код, который я хочу заменить вызовом функции avg(dim, i, j, src); на:

static pixel avg (int dim, int i, int j, pixel *src) 

{

    int ii, jj;
    pixel_sum sum;
    pixel current_pixel;

    initialize_pixel_sum(&sum);
    for(ii = max(i-1, 0); ii <= min(i+1, dim-1); ii++) 
    for(jj = max(j-1, 0); jj <= min(j+1, dim-1); jj++) 
         accumulate_sum(&sum, src[RIDX(ii, jj, dim)]);

    assign_sum_to_pixel(&current_pixel, sum);
    return current_pixel;


}

/*
 * mysmooth - my smooth 
 */

char mysmooth_ descr[] = "my smooth: My smooth";

void mysmooth (int dim, pixel *src, pixel *dst) 

{    

int i, j;
int ii, jj;
pixel_sum sum;
pixel current_pixel;

for (i = 0; i < dim; i++)
for (j = 0; j < dim; j++)
{
initialize_pixel_sum(&sum);
for(ii = max(i-1, 0); ii <= min(i+1, dim-1); ii++) 
for(jj = max(j-1, 0); jj <= min(j+1, dim-1); jj++) 
    accumulate_sum(&sum, src[RIDX(ii, jj, dim)]);

assign_sum_to_pixel(&current_pixel, sum);
dst[RIDX(i, j, dim)] = current_pixel;
}

Так вот как должен выглядеть мой код после того, как я закончу брать код из avg () и заменять его функцией?

Ответы [ 5 ]

8 голосов
/ 03 октября 2009

Если ваша кодовая база небольшая, включает в себя около 10-12 функций, вы можете попробовать использовать ключевое слово inline перед каждой из функций.

Второй вариант, используйте параметр компилятора, который вставляет все вызовы функций, не делайте этого вручную (поэтому существуют компиляторы). Какой компилятор вы используете? Вы можете посмотреть в Интернете его опцию, которая включает все вызовы функций (если они есть).

В-третьих, если вы используете GCC для компиляции кода, вы можете указать атрибут always_inline для функции. Вот как это использовать:

static pixel avg (int dim, int i, int j, pixel *src) __attribute__((always_inline));
4 голосов
/ 03 октября 2009
  1. Если вы используете компилятор C99 или C ++, вы можете использовать ключевое слово inline. Однако это не гарантирует, что вызов будет заменен реальным кодом, только если компилятор посчитает его более эффективным.
  2. В противном случае, если вы используете чистый C89, avg() должен быть макросом. Тогда вы гарантированно замените функцию «вызов» фактическим кодом.
2 голосов
/ 03 октября 2009

Должен сказать, что я согласен с подходом, который заключается в том, чтобы убедиться, что вы используете оптимизацию компилятора и встроенный метод ... но если вы все еще хотите получить ответ на свой конкретный вопрос, я думаю, что вы получите что-то вроде:

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

    /* ...avg() code body except for the return... */ 

    dst[RIDX(i, j, dim)] = current_pixel;
}
2 голосов
/ 03 октября 2009

Использование встроенных и макросов : http://gcc.gnu.org/onlinedocs/cpp/Macros.html

0 голосов
/ 23 октября 2009

Я развернул начало и конец циклов, чтобы исключить min () и max () из кода:

void smooth_B(int dim, struct pixel src[dim][dim], struct pixel dst[dim][dim]){
  dst[0][0].red  =(src[0][0].red  +src[1][0].red  +src[0][1].red  +src[1][1].red  )/4;
  dst[0][0].green=(src[0][0].green+src[1][0].green+src[0][1].green+src[1][1].green)/4;
  dst[0][0].blue =(src[0][0].blue +src[1][0].blue +src[0][1].blue +src[1][1].blue )/4;
  for( int j=1; j<dim-1; j++){
    dst[0][j].red  =(src[0][j-1].red  +src[1][j-1].red  +src[0][j].red  +src[1][j].red  +src[0][j+1].red  +src[1][j+1].red  )/6;
    dst[0][j].green=(src[0][j-1].green+src[1][j-1].green+src[0][j].green+src[1][j].green+src[0][j+1].green+src[1][j+1].green)/6;
    dst[0][j].blue =(src[0][j-1].blue +src[1][j-1].blue +src[0][j].blue +src[1][j].blue +src[0][j+1].blue +src[1][j+1].blue )/6;
  }
  dst[0][dim-1].red  =(src[0][dim-2].red  +src[1][dim-2].red  +src[0][dim-1].red  +src[1][dim-1].red  )/4;
  dst[0][dim-1].green=(src[0][dim-2].green+src[1][dim-2].green+src[0][dim-1].green+src[1][dim-1].green)/4;
  dst[0][dim-1].blue =(src[0][dim-2].blue +src[1][dim-2].blue +src[0][dim-1].blue +src[1][dim-1].blue )/4;

  for( int i=1; i<dim-1; i++){
    dst[i][0].red  =(src[i-1][0].red  +src[i-1][1].red  +src[i][0].red  +src[i][1].red  +src[i+1][0].red  +src[i+1][1].red  )/6;
    dst[i][0].green=(src[i-1][0].green+src[i-1][1].green+src[i][0].green+src[i][1].green+src[i+1][0].green+src[i+1][1].green)/6;
    dst[i][0].blue =(src[i-1][0].blue +src[i-1][1].blue +src[i][0].blue +src[i][1].blue +src[i+1][0].blue +src[i+1][1].blue )/6;
    for( int j=1; j<dim; j++){
      dst[i][j].red  =(src[i-1][j-1].red  +src[i][j-1].red  +src[i+1][j-1].red  +src[i-1][j].red  +src[i][j].red  +src[i+1][j].red  +src[i-1][j+1].red  +src[i][j+1].red  +src[i+1][j+1].red  )/9;
      dst[i][j].green=(src[i-1][j-1].green+src[i][j-1].green+src[i+1][j-1].green+src[i-1][j].green+src[i][j].green+src[i+1][j].green+src[i-1][j+1].green+src[i][j+1].green+src[i+1][j+1].green)/9;
      dst[i][j].blue =(src[i-1][j-1].blue +src[i][j-1].blue +src[i+1][j-1].blue +src[i-1][j].blue +src[i][j].blue +src[i+1][j].blue +src[i-1][j+1].blue +src[i][j+1].blue +src[i+1][j+1].blue )/9;
    }
    dst[i][dim-1].red  =(src[i-1][dim-2].red  +src[i][dim-2].red  +src[i+1][dim-2].red  +src[i-1][dim-1].red  +src[i][dim-1].red  +src[i+1][dim-1].red  )/6;
    dst[i][dim-1].green=(src[i-1][dim-2].green+src[i][dim-2].green+src[i+1][dim-2].green+src[i-1][dim-1].green+src[i][dim-1].green+src[i+1][dim-1].green)/6;
    dst[i][dim-1].blue =(src[i-1][dim-2].blue +src[i][dim-2].blue +src[i+1][dim-2].blue +src[i-1][dim-1].blue +src[i][dim-1].blue +src[i+1][dim-1].blue )/6;
  }
  dst[dim-1][0].red  =(src[dim-2][0].red  +src[dim-2][1].red  +src[dim-1][0].red  +src[dim-1][1].red  )/4;
  dst[dim-1][0].green=(src[dim-2][0].green+src[dim-2][1].green+src[dim-1][0].green+src[dim-1][1].green)/4;
  dst[dim-1][0].blue =(src[dim-2][0].blue +src[dim-2][1].blue +src[dim-1][0].blue +src[dim-1][1].blue )/4;
  for( int j=1; j<dim; j++){
    dst[dim-1][j].red  =(src[dim-2][j-1].red  +src[dim-1][j-1].red  +src[dim-2][j].red  +src[dim-1][j].red  +src[dim-2][j+1].red  +src[dim-1][j+1].red  )/6;
    dst[dim-1][j].green=(src[dim-2][j-1].green+src[dim-1][j-1].green+src[dim-2][j].green+src[dim-1][j].green+src[dim-2][j+1].green+src[dim-1][j+1].green)/6;
    dst[dim-1][j].blue =(src[dim-2][j-1].blue +src[dim-1][j-1].blue +src[dim-2][j].blue +src[dim-1][j].blue +src[dim-2][j+1].blue +src[dim-1][j+1].blue )/6;
  }
  dst[dim-1][dim-1].red  =(src[dim-2][dim-2].red  +src[dim-1][dim-2].red  +src[dim-2][dim-1].red  +src[dim-1][dim-1].red  )/4;
  dst[dim-1][dim-1].green=(src[dim-2][dim-2].green+src[dim-1][dim-2].green+src[dim-2][dim-1].green+src[dim-1][dim-1].green)/4;
  dst[dim-1][dim-1].blue =(src[dim-2][dim-2].blue +src[dim-1][dim-2].blue +src[dim-2][dim-1].blue +src[dim-1][dim-1].blue )/4;
}

Как я измерил, он быстрее на ~ 50%, чем исходный код. Следующим этапом является устранение повторных расчетов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...