2012-05-05 9 views
5

Napisałem operator niestandardowy new i operator delete dla klasy MyOrder. Przydzielam pamięć za pomocą boost :: singleton pool. Oto program testowania wydajności,Niestandardowe przydzielanie przy użyciu boost singleton_pool wolniej niż domyślnie

#include <boost/pool/singleton_pool.hpp> 
#include <boost/progress.hpp> 
#include <iostream> 
#include <new> 
#include <vector> 


class MyOrder{ 
    std::vector<int> v1_; 
    std::vector<double> v2_; 

    std::string s1_; 
    std::string s2_; 

public: 
    MyOrder(std::string s1, std::string s2): s1_(s1), s2_(s2) {} 

    ~MyOrder(){} 

    static void * operator new(size_t size); 
    static void operator delete(void * rawMemory) throw(); 
}; 

struct MyOrderTag{}; 
typedef boost::singleton_pool<MyOrderTag, sizeof(MyOrder)> MyOrderPool; 

void* MyOrder:: operator new(size_t size) 
{ 
    if (size != sizeof(MyOrder)) 
     return ::operator new(size); 

    while(true){ 
     void * ptr = MyOrderPool::malloc(); 
     if (ptr != NULL) return ptr; 

     std::new_handler globalNewHandler = std::set_new_handler(0); 
     std::set_new_handler(globalNewHandler); 

     if(globalNewHandler) globalNewHandler(); 
     else throw std::bad_alloc(); 

    } 
} 

void MyOrder::operator delete(void * rawMemory) throw() 
{ 
    if(rawMemory == 0) return; 
    MyOrderPool::free(rawMemory); 
} 

int main() 
{ 
    MyOrder* mo = NULL; 
    std::vector<MyOrder*> v; 
    v.reserve(100000); 

    boost::progress_timer howlong; 
    for(int i = 0; i< 100000; ++i) 
    { 
     mo = new MyOrder("Sanket", "Sharma"); 
     v.push_back(mo); 
    } 

    for (std::vector<MyOrder*>::const_iterator it = v.begin(); it != v.end(); ++it) 
    { 
     delete *it; 
    } 
    return 0; 
} 

Skompilowałem powyższy program używając -O2 flagę i pobiegł na moim Macbook z 2,26 GHz Intel Core 2 Duo i zajęło 0.16 sekund. Następnie skomentowałem linie, w których zadeklarowałem i zdefiniowałem operatora niestandardowego new i operator delete, zrekompilowałem je z flagami -O2 i uruchomiłem na tej samej maszynie, która zajęła 0,13 sekundy.

Przydzielanie i zwalnianie pamięci za pomocą singleton_pool dla obiektów tego samego rozmiaru powinno przyspieszyć jej działanie. Dlaczego robi to powoli? Czy też narzut związany z tworzeniem puli niweluje korzyści wydajnościowe uzyskane w tym małym programie?

Aktualizacja:

Wymieniłem dwie zmienne std :: string z int i podwójne, a tym razem prowadził dwa programy z 100000000 (czyli 1000 razy wcześniej) iteracji każdy na 3,0 GHz AMD Phenom (tm) Procesor II X4 945. Ten używający niestandardowej alokacji pamięci zajmuje 3,2 sekundy, podczas gdy ten, który używa domyślnej alokacji pamięci, zajmuje 8,26 sekundy. Więc tym razem wygrywa alokacja pamięci niestandardowej.

+1

Skoro bierzesz sobie trud, aby zadzwonić * jeden * nowy handler, powinieneś napisać pętlę, aby spróbować * wszystkie * nowe procedury obsługi. –

+1

Twój test zawiera alokacje według 'std :: string', które nie są zarządzane przez Twój niestandardowy program przydzielania, więc wszelkie wyniki, które otrzymujesz, są mylące _at best_. – Chad

+0

@Chad I zastąpił std :: string przez podwójne i int. Tym razem powtarzam je 10000000 razy. Wyniki to 1,95 dla domyślnie vs 2,29 dla niestandardowych. Nadal alokacja/dealokacja przy użyciu puli jest wolniejsza. – sank

Odpowiedz

5

Myślę, że twoje liczby są bez znaczenia. Jeśli tylko raz sprawdziłeś środowisko wykonawcze i znalazłeś 0.13 vs 0.16 sekund niż to jest całkowicie pozbawione sensu i zdominowane przez narzut.

Musisz uruchomić fragment, który chcesz przetestować tysiące razy, a następnie porównać dane, aby wykluczyć narzut.

No naprawdę, że różnica 0.03 sekund można łatwo wytłumaczyć procesu coraz wyłączana, itp

Powiązane problemy