需要帮助优化函数调用

时间:2012-08-28 07:32:10

标签: c performance optimization function-pointers compiler-optimization

我正在尝试实现图像处理功能。这是:

typedef void (*AgFilter)(int*, int*, int*, float*);

static void filter(AndroidBitmapInfo* info, void* pixels, AgFilter func, void* params){

    for(y = 0; y < height; y++){
        for(x = 0; x < width; x++){
            //initizalie r, g, b

            func(&r, &g, &b, params); //here is the problem
        }
    }
}

我将此功能传递给func

static inline void brightness(int *r, int *g, int *b, float* param){
    float add = param[0];

    *r += add;
    *g += add;
    *b += add;
}

问题是它的工作极其缓慢。好吧,我能理解。 如果不是通过引用传递函数,而是直接在filterfunc调用的实例中)编写我的函数,它的工作速度要快得多。问题在哪里?

P.S。请注意,它不是c++

修改

这个很快:

static void filter(AndroidBitmapInfo* info, void* pixels, int add){

    for(y = 0; y < height; y++){
        for(x = 0; x < width; x++){
            //initizalie r, g, b
            r += add;
            g += add;
            b += add;
        }
    }
}

3 个答案:

答案 0 :(得分:4)

我认为问题是因为你将函数作为指针传递。因为 brightness()没有被编译器内联。

当您将 brightness()的定义复制到过滤器()功能时,您将获得所需的结果 - 您可以内联该功能。

答案 1 :(得分:4)

调用函数需要时间。通常,您没有注意到,但是您将该功能称为一百万次(对于全高清1920x1080图像,大约需要两百万次)。现代相机创造了1600万像素的图像。如果每次调用需要1 us,则调用函数的累计时间(不实际执行正文)将为16

你怎么能让它更快?一些建议:

  1. 使用结构:

    ,而不是传递四个参数
     struct data { int r,g,b; float* param; }
    

    分配一次并重复使用它。现在,您可以使用一个参数调用func

  2. 内存布局可能有问题。 param在记忆中无处不在。将其复制到struct data代替:

     struct data { int r,g,b, add; }
    

    原因是param在内存中的任何位置,这意味着它可能位于不同的缓存行中。如果您可以将所有数据整合到一个64字节结构中,那么所有数据都将适合单个缓存行,从而大大提高性能。

    但可能不在你的情况下,因为你总是访问param[0]。当您以随机方式访问数组时,这是一个更大的问题。

  3. 交换移位和位掩码操作:

     r = (int) ((line[x] & >> 16 ) & 0xFF);
    

    可以给出一个小的提升,因为现在所有三种颜色都会被0xFF掩盖,并且允许编译器将常量移动一次到CPU寄存器。

  4. 调用函数时,需要“保存/恢复”所有CPU寄存器。这需要时间。当内联函数时,编译器知道哪些CPU寄存器被删除并可以相应地进行优化。

    实际上,CPU寄存器没有保存(至少我很久没见过了)。现代编译器假设在调用函数之后,所有这些都已被更改。

  5. 请注意inline无效,因为您通过引用传递函数而不是直接调用它。

  6. 使用线程。这很简单,并行化:在数据的1 / N次上运行N次(每个CPU核心一次)。这将为你提供大约N次性能提升。

答案 2 :(得分:1)

到目前为止,您可以做的最大改进是避免为每个像素调用一次函数。在brightness函数中移动循环是微不足道的。

static inline void brightness(int *r, int *g, int *b, float* param){
    float add = param[0];

    for(y = 0; y < height; y++)
        for(x = 0; x < width; x++){
            //initialize r, g, b
            *r += add;
            *g += add;
            *b += add;
        }
}

现在,我知道您不希望在您可能编写的每个不同的过滤器函数中复制循环迭代代码,因此这是使用宏可以真正发挥作用的情况之一。尝试这样的事情(未经测试)。

#define FOR_EACH_PIXEL for(y = 0; y < height; y++) \
                       for(x = 0; x < width;  x++)

static inline void brightness(int *r, int *g, int *b, float* param){
    float add = param[0];

    FOR_EACH_PIXEL 
    {
            //initialize r, g, b
            *r += add;
            *g += add;
            *b += add;
    }

}