最小化函数选择和函数调用开销?

时间:2015-03-19 14:26:38

标签: c++ performance branch function-pointers branch-prediction

我有一个大型数组(图像),我需要对该数据进行许多小的可配置计算。 我将在这里发布一个例子。 注意:这不是实际问题,而是我需要做的最小/希望说明的例子。

// different functions that can be called based on the configuration
float func1( float* a )
{
    return (*a) * (*a);
}

float func2( float* a )
{
    return (*a) + (*a);
}

float func3( float* a )
{
    return 2 * (*a) * (*a);
}

// my data
float* data = new float[1024*1024];

// function that manages the configurations
int main(  )
{
    int param1 = 0;
    int param2 = 1;

    for ( int k = 0; k < 1024*1024; k++ )
    {
        if ( param1 == 2 && param2 == 0 )
            data[k] = func1( data + k );
        else if ( param1 == 1 && param2 == 1 )
            data[k] = func2( data + k );            
        else if ( param1 == 0 && param2 == 1 )
            data[k] = func3( data + k );
        else
            continue;

    }
}

在我的代码中,将循环放在每个函数中是有意义的。

但是,param1和param2在循环期间保持不变,它们在编译时是已知的。

有没有办法消除if / elseif语句的影响?

3 个答案:

答案 0 :(得分:2)

你可以移动你的if-else语句来选择适当的函数来使用循环,从而得到:

#include <functional>
// different functions that can be called based on the configuration
float func1( float* a )
{
    return (*a) * (*a);
}

float func2( float* a )
{
    return (*a) + (*a);
}

float func3( float* a )
{
    return 2 * (*a) * (*a);
}

// my data
float* data = new float[1024*1024];

// function that manages the configurations
int main(  )
{
    int param1 = 0;
    int param2 = 1;

    std::function< float( float* )> functionToUse = nullptr;

    if ( param1 == 2 && param2 == 0 )
        functionToUse = std::function<float(float*)>(func1);
    else if ( param1 == 1 && param2 == 1 )
        functionToUse = std::function<float(float*)>(func2);            
    else if ( param1 == 0 && param2 == 1 )
        functionToUse = std::function<float(float*)>(func3);

    if(functionToUse){
        for ( int k = 0; k < 1024*1024; k++ )
        {
            data[k] = functionToUse( data + k );
        }    
    }
}

至于选择在编译期间使用的功能,我建议查看这个问题: if/else at compile time?

此问题可能也很有趣: Is cutting if statements by using function pointers going to be more efficient?

答案 1 :(得分:2)

只要参数为const或者编译器可以100%确定它们的变量没有别名,因此不会改变(编译器更难)我完全希望优化器完全删除运行时分支,并在编译时完成所有工作。

但是,如果您不喜欢依赖优化器,则可以使用模板:

template <int c1, int c2>
float func(float* a)
{
    // No-op.
}

template <>
float func<2, 0>(float* a)
{
    return (*a) * (*a);
}

template <>
float func<1, 1>(float* a)
{
    return (*a) + (*a);
}

template <>
float func<0, 1>(float* a)
{
    return 2 * (*a) * (*a);
}

int main()
{
    const int param1 = 0;
    const int param2 = 1;

    for ( int k = 0; k < 1024*1024; k++ )
    {
        func<param1, param2>(<float ptr>);
    }
}

答案 2 :(得分:0)

也许是这样的

#include <iostream>
#include <map>
#include <functional>
#include <utility>

typedef std::pair<size_t, size_t> pair;
typedef std::map< pair, std::function<float( float* )>> map;

// different functions that can be called based on the configuration
float func1( float* a )
{
    return ( *a ) * ( *a );
}

float func2( float* a )
{
    return ( *a ) + ( *a );
}

float func3( float* a )
{
    return 2 * ( *a ) * ( *a );
}

// my data
float* data = new float[1024 * 1024];

void init( map &myMap )
{
    myMap.insert( pair, std::function<float( float* )>>
                ( pair( 2, 0 ), std::function< float( float* )>( func1 ) ) );
    myMap.insert( pair, std::function<float( float* )>>
                ( pair( 1, 1 ), std::function< float( float* )>( func2 ) ) );
    myMap.insert( pair, std::function<float( float* )>>
                ( pair( 0, 2 ), std::function< float( float* )>( func3 ) ) );
}

// function that manages the configurations
int main( )
{
    int param1 = 0;
    int param2 = 1;

    map myMap;

    init( myMap );

    for( int k = 0; k < 1024 * 1024; k++ )
    {
        data[k] = myMap[pair( param1, param2 )]( data + k );
    }
}