Сравнение производительности распределения указателей в C / C ++ - PullRequest
0 голосов
/ 08 марта 2019

Каков наилучший способ сравнить распределение / удаление указателей в C / C ++?Пожалуйста, рассматривайте производительность как точку зрения.

Код включает сравнение следующих типов динамического распределения:

  • Malloc/Free
  • New/Delete
  • std::auto_ptr
  • std::shared_ptr
  • std::unique_ptr
  • std::allocator/deallocator

Давайте начнем с этого фрагмента кода:

#include <stdlib.h> // I intended to use C for malloc. Though not cstdlib
#include <sys/time.h>
#include <iostream>
#include <memory>

#define Million 1000000
#define Alls 100 * Million

long calculate_time(struct timeval start, struct timeval end){

    long start_micro = (start.tv_sec * Million) + start.tv_usec;
    long end_micro = (end.tv_sec * Million) + end.tv_usec;
    long elapsed_time = end_micro - start_micro;
    std::cout << "Elapsed time: " << elapsed_time << " usec";
    std::cout << " (" << Alls / elapsed_time << " allocations/microseconds)" << std::endl;
}


/* 
* Version: C
* Allocation: Malloc
* Deallocation: Free
*/
void c_pointer (){


    int counter = 0;
    do{

        int *p = (int *) malloc (sizeof (int));
        *p =5;
        free(p);
        counter ++;
    } while (counter < Alls);
}


/* 
* Version: C++98
* Allocation: New
* Deallocation: Delete
*/
void cpp98_pointer (){

    int counter = 0;
    do{

        int *p = new int (5);
        delete p;
        counter ++;
    } while (counter < Alls);
}


/* 
* Version: C++98 till C++17
* Allocation: std::auto_ptr
* Deallocation: Automatically
*/
void cpp98_auto_ptr (){

    int counter = 0;
    do{
        std::auto_ptr<int> p(new int);
        *p = 5;
        counter ++;
    } while (counter < Alls);
}


/* 
* Version: C++11
* Allocation: std::shared_ptr
* Deallocation: Automatically
*/
void cpp11_shared_ptr (){

    int counter = 0;
    do{
        std::shared_ptr<int> p(new int);
        *p = 5;
        counter ++;
    } while (counter < Alls);
}


/* 
* Version: C++11
* Allocation: std::unique_ptr
* Deallocation: Automatically
*/
void cpp11_unique_ptr (){

    int counter = 0;
    do{
        std::unique_ptr<int> p(new int); 
        *p = 5;
        counter ++;
    } while (counter < Alls);

}


/* 
* Version: C++98
* Allocation: std::allocator
* Deallocation: Deallocate
*/
void cpp98_allocator (){

    int counter = 0;
    do{

        std::allocator<int> a;
        int* p = a.allocate(1);
        a.construct(p, 1);
        *p =5;
        a.deallocate(p, 1);
        counter ++;
    } while (counter < Alls);

}


int main (){

    for (int i= 0 ; i < 6; i++){

        struct timeval t1, t2;
        gettimeofday(&t1, NULL);

        switch(i){
            case 0:
                std::cout << "C - Malloc/Free:" << std::endl;
                c_pointer();
                break;
            case 1:
                std::cout << "C++98 - New/Delete:" << std::endl;
                cpp98_pointer();
                break;
            case 2:
                // From C++98 until C++17 (Removed in C++17)
                std::cout << "C++98 - auto_ptr:" << std::endl;
                cpp98_auto_ptr();
                break;
            case 3:
                // From C++11
                std::cout << "C++11 - shared_ptr:" << std::endl;
                cpp11_shared_ptr();
                break;
            case 4:
                // From C++11
                std::cout << "C++11 - unique_ptr:" << std::endl;
                cpp11_unique_ptr();
                break;
            default:
                // Deprecated in C++98
                std::cout << "C++98 - Default Allocator:" << std::endl;
                cpp98_allocator();
                break;
        }

        gettimeofday(&t2, NULL);
        calculate_time(t1, t2);
    }

    return 0;
}

На моем ноутбуке результаты выглядят следующим образом:

C - Malloc/Free:
Elapsed time: 1519052 usec (65 allocations/microseconds)
C++98 - New/Delete:
Elapsed time: 1718064 usec (58 allocations/microseconds)
C++98 - auto_ptr:
Elapsed time: 2334505 usec (42 allocations/microseconds)
C++11 - shared_ptr:
Elapsed time: 10197285 usec (9 allocations/microseconds)
C++11 - unique_ptr:
Elapsed time: 11785931 usec (8 allocations/microseconds)
C++98 - Default Allocator:
Elapsed time: 3487610 usec (28 allocations/microseconds)

1 Ответ

0 голосов
/ 08 марта 2019

Во-первых, когда вы компилируете с включенными оптимизациями розничной торговли, вы получите совершенно разные результаты. (Мой быстрый порт в Windows и некоторые исправления в вашем коде, включая не измерение времени до окончания инструкции cout):

C - Malloc/Free:
Elapsed time: 469 msec     (21321 allocations/second)
C++98 - New/Delete:
Elapsed time: 500 msec     (20000 allocations/second)
C++11 - auto_ptr:
Elapsed time: 484 msec     (20661 allocations/second)
C++11 - shared_ptr:
Elapsed time: 1157 msec     (8643 allocations/second)
C++11 - unique_ptr:
Elapsed time: 484 msec     (20661 allocations/second)

Все, кроме shared_ptr, имеют одинаковую скорость. shared_ptr должен выделить некоторые блокирующие конструкции (мьютекс), так как он является поточно-ориентированным в отношении назначений ссылок и слабых_птров.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...