Пользовательское распределение с использованием boost singleton_pool медленнее, чем по умолчанию

Я написал собственный оператор new и оператор удаления для класса MyOrder. Я выделяю память, используя пул boost::singleton. Вот программа, тестирующая производительность,

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

Я скомпилировал приведенную выше программу с флагом -O2 и запустил на своем Macbook с процессором Intel Core 2 Duo 2,26 ГГц, и это заняло 0,16 секунды. Затем я прокомментировал строки, где я объявил и определил пользовательский оператор new и оператор удаления, перекомпилировал с флагами -O2 и запустил на той же машине, что заняло 0,13 секунды.

Выделение и освобождение памяти с использованием singleton_pool для объектов одинакового размера должно ускорить это. Почему это делает его медленным? Или накладные расходы на создание пула сводят на нет выигрыш в производительности, полученный в этой небольшой программе?

Обновлять:

Я заменил две переменные std::string на int и double и на этот раз запустил две программы с 100000000 (т.е. 1000 раз раньше) итерациями каждая на процессоре AMD Phenom(tm) II X4 945 с тактовой частотой 3,0 ГГц. Тот, который использует пользовательское выделение памяти, занимает 3,2 секунды, а тот, который использует выделение памяти по умолчанию, занимает 8,26 секунды. Так что на этот раз побеждает пользовательское выделение памяти.


person sank    schedule 05.05.2012    source источник
comment
Поскольку вы пытаетесь вызвать один новый обработчик, вам, вероятно, следует написать цикл для проверки всех новых обработчиков.   -  person Kerrek SB    schedule 06.05.2012
comment
Ваш тест включает распределения std::string, которые не регулируются вашим настраиваемым распределителем, поэтому любые полученные вами результаты в лучшем случае вводят в заблуждение.   -  person Chad    schedule 06.05.2012
comment
@Chad Я заменил std::string на double и int. На этот раз я повторяю их 10000000 раз. Результаты: 1,95 с по умолчанию против 2,29 с по индивидуальному заказу. Тем не менее, выделение/освобождение с использованием пула происходит медленнее.   -  person sank    schedule 06.05.2012
comment
@KerrekSB Я следую подходу, упомянутому в Эффективном C++. Я не уверен, что вы имеете в виду, когда говорите все новые обработчики. Пожалуйста, расскажите мне об этом.   -  person sank    schedule 06.05.2012
comment
@sanket: пример реализации приведен в качестве примечания в самом стандартном документе C++. По сути, новый обработчик может установить новый новый обработчик, поэтому вам нужно зацикливаться, пока вы не получите нулевой указатель. Если вам нужно полное описание, возможно, задайте отдельный вопрос, хотя это не очень важно.   -  person Kerrek SB    schedule 06.05.2012
comment
См. 18.6.1/4 для описания поведения по умолчанию ::operator new.   -  person Kerrek SB    schedule 06.05.2012


Ответы (1)


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

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

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

person orlp    schedule 05.05.2012