2012-03-15 1 views
3

Я пытаюсь отменить, если временные накладные расходы, введенные boost::function для оценки математических функций, неоценимы по сравнению с использованием function templates.llvm g ++ и boost function

Код для теста, который я использую, приведен ниже.

С g++ традиционными французским, накладным расходами с boost::function является negligeable:

$ g++ -O3 main.cxx 
$ ./a.out 
METHOD    INTEGRAL TIME TO COMPUTE (SEC)   
Direct    0.379885 3.360000      
Function template 0.379885 3.380000      
Boost function  0.379885 3.400000 

С llvm-g++, есть прирост скорости в 1,5 раза для templates function, но не для усиления boost::function.

$ llvm-g++ -O3 main.cxx 
METHOD    INTEGRAL TIME TO COMPUTE (SEC)   
Direct    0.379885 2.170000      
Function template 0.379885 2.160000      
Boost function  0.379885 3.360000  

Можно ли получить 1,5 усиления для boost::function и llvm-g++?

#include <boost/function.hpp> 
#include <math.h> 
#include <stdio.h> 

typedef unsigned int UInt; 

using namespace std; 

//============================================================================= 
// chrono 
//============================================================================= 
class Chrono 
{ 
    clock_t t1_,t2_,dt_; 
    public: 
     Chrono(){} 
     void start() { t1_=clock(); }; 
     void stop() { t2_=clock(); }; 
     double diff() { return ((double)(t2_ - t1_))/CLOCKS_PER_SEC; }; 
}; 

//============================================================================= 
// function to integrate 
//============================================================================= 
inline double fct(double x) 
{ 
    return 1./(1.+exp(x)); 
} 

//============================================================================= 
// using direct method 
//============================================================================= 
double direct(double a, double b, UInt numSamplePoints) 
{ 
    double delta = (b-a)/(numSamplePoints-1); 
    double sum = 0.; 
    for (UInt i=0; i < numSamplePoints-1; ++i) 
     sum += 1./(1. + exp(a + i*delta)); 
    return sum * delta; 
} 

//============================================================================= 
// using function template 
//============================================================================= 
template<double functionToIntegrate(double)> 
double integrate(double a, double b, UInt numSamplePoints) 
{ 
    double delta = (b-a)/(numSamplePoints-1); 
    double sum = 0.; 
    for (UInt i=0; i < numSamplePoints-1; ++i) 
     sum += functionToIntegrate(a + i*delta); 
    return sum * delta; 
} 

//============================================================================= 
// using Boost function 
//============================================================================= 
typedef boost::function<double (double)> fct_type; 

class IntegratorBoost { 
    public: 
    fct_type functionToIntegrate; 
    IntegratorBoost(fct_type fct): functionToIntegrate(fct){} 
    double integrate(double a, double b, UInt numSamplePoints) 
    { 
     double delta = (b-a)/(numSamplePoints-1); 
     double sum = 0.; 
     for (UInt i=0; i < numSamplePoints-1; ++i) 
     sum += functionToIntegrate(a + i*delta); 
     return sum * (b-a)/numSamplePoints; 
    } 
}; 

//============================================================================= 
// main 
//============================================================================= 
int main() 
{ 
    double integral; 
    UInt numSamplePoints = 5E07; 
    Chrono chrono; 

    printf("%-20s%-10s%-30s\n","METHOD","INTEGRAL","TIME TO COMPUTE (SEC)"); 

    // Direct 
    chrono.start(); 
    integral = direct(0., 1., numSamplePoints); 
    chrono.stop(); 
    printf("%-20s%-10f%-30f\n","Direct",integral,chrono.diff()); 

    // Function template 
    chrono.start(); 
    integral = integrate<fct>(0., 1.,numSamplePoints); 
    chrono.stop(); 
    printf("%-20s%-10f%-30f\n","Function template",integral,chrono.diff()); 

    // Boost function 
    chrono.start(); 
    IntegratorBoost intboost(fct); 
    integral = intboost.integrate(0.,1.,numSamplePoints); 
    chrono.stop(); 
    printf("%-20s%-10f%-30f\n","Boost function",integral,chrono.diff()); 
} 
+1

Использование 'clock' для эталонных тестов не так уж и надежно. Я подозреваю, что это может исказить ваши результаты, чтобы сделать их бессмысленными. –

+1

В Linux я бы рекомендовал 'gettimeofday' для более точного таймера. Кроме того, llvm-g ++ устарел (и был основан на g ++ 4.2), я бы рекомендовал переключиться на Clang 3.0 для лучшего соответствия и нового и блестящего C++ 11. –

+0

У меня также есть функция лямбда, чтобы увидеть, как она складывается. Он обладает всеми преимуществами функции boost :: function и более низкого уровня. – StilesCrisis

ответ

0

фактически не измерить, я буду рисковать и утверждать, что использование boost::function (или std::function от C++ 11) не может быть столь же эффективным, как и двух других вариантов.

Причина заключается в том, что function использует тип стирание, чтобы удалить тип фактического функтора используется, а это означает, что function потребность для хранения фактического объекта, который делает вызов через указатель и функцию использования вызовов. С другой стороны, в двух других методах компилятор может использовать inline логику и удалить стоимость отправки.

Это на самом деле очень похоже на много раз упомянутых разницы в производительности библиотеки C qsort по сравнению с C++ sort, где с помощью функтора компилятора имеет лучшие шансы на встраивание и оптимизацию.

Тогда возникает вопрос, повлияет ли это на ваше приложение, и для этого вам нужно измерить. Возможно, в общем случае стоимость ввода-вывода или любая другая операция доминируют над вашим приложением, и это не будет иметь никакого значения.