производительность memcpy () - Ubuntu x86_64 - PullRequest
4 голосов
/ 23 июля 2011

Я наблюдаю странное поведение, которое не могу объяснить. Ниже приведены подробности: -

#include <sched.h>
#include <sys/resource.h>
#include <time.h>
#include <iostream>

void memcpy_test() {
    int size = 32*4;
    char* src = new char[size];
    char* dest = new char[size];
    general_utility::ProcessTimer tmr;
    unsigned int num_cpy = 1024*1024*16; 
    struct timespec start_time__, end_time__;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time__);
    for(unsigned int i=0; i < num_cpy; ++i) {
        __builtin_memcpy(dest, src, size);
    }
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time__);
    std::cout << "time = " << (double)(end_time__.tv_nsec - start_time__.tv_nsec)/num_cpy << std::endl;
    delete [] src;
    delete [] dest;
}

Когда я указываю -march = native в опциях компилятора, сгенерированный двоичный файл работает в 2,7 раза медленнее. Это почему ? Во всяком случае, я ожидаю, что -march = native создаст оптимизированный код. Есть ли другие функции, которые могли бы показать этот тип поведения?

РЕДАКТИРОВАТЬ 1: Другим интересным моментом является то, что если размер> 32 * 4, то нет разницы между временем выполнения сгенерированных таким образом двоичных файлов

РЕДАКТИРОВАТЬ 2: Ниже приводится подробный анализ производительности (__builtin_memcpy ()): -

размер = 32 * 4, без -march = собственный - 7,5 нс, с -march = собственный - 19,3

размер = 32 * 8, без -march = собственный - 26,3 нс, с -march = собственный - 26,5

РЕДАКТИРОВАТЬ 3:

Это наблюдение не изменится, даже если я выделю int64_t / int32_t.

РЕДАКТИРОВАТЬ 4:

size = 8192, без -march = native ~ 2750 нс, с -march = native ~ 2750 (раньше при сообщении этого числа была ошибка, оно было ошибочно записано как 26.5, теперь оно корректно)

Я выполнял это много раз, и числа одинаковы для каждого прогона.

Ответы [ 2 ]

3 голосов
/ 23 июля 2011

Я скопировал ваши выводы: g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2, Linux 2.6.38-10-generic #46-Ubuntu x86_64 на моем Core 2 Duo.Результаты могут отличаться в зависимости от версии вашего компилятора и процессора.Я получаю ~ 26 и ~ 9.

Когда я указываю -march = native в опциях компилятора, сгенерированный двоичный файл работает в 2,7 раза медленнее.Это почему ?

Поскольку -march = встроенная версия компилируется (можно найти с помощью objdump -D, вы также можете использовать gcc -S -fverbose-asm):

    rep movsq %ds:(%rsi),%es:(%rdi) ; where rcx = 128 / 8

И версия без компилируется в16 пар загрузки / хранения, например:

    mov    0x20(%rbp),%rdx
    mov    %rdx,0x20(%rbx)

Что, по-видимому, быстрее на наших компьютерах.

Во всяком случае, я бы ожидал, что -march = native произведет оптимизированный код.

В этом случае оказалось, что это пессимизация в пользу rep movsq за серию ходов, но это не всегда так.Первая версия короче, что может быть лучше в некоторых (большинстве?) Случаях.Или это может быть ошибка в оптимизаторе.

Существуют ли другие функции, которые могут показывать этот тип поведения?

Любая функция, для которой сгенерированный код отличается, когда вы указываете -march=native, подозревает, что включает функции, реализованные какмакросы или статические заголовки, имя которых начинается с __builtin.Возможно также (с плавающей запятой) математические функции.

Другим интересным моментом является то, что если размер> 32 * 4, то нет разницы между временем выполнения сгенерированных таким образом двоичных файлов

Это потому, что они оба компилируютсядо rep movsq, 128, вероятно, самый большой размер, для которого GCC будет генерировать серию загрузки / хранения (было бы интересно посмотреть, если это также для других платформ).Кстати, когда компилятор не знает размер во время компиляции (например, int size=atoi(argv[1]);), он просто превращается в вызов memcpy с переключателем или без него.

0 голосов
/ 20 февраля 2013

Это довольно известная проблема (и действительно старая).

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43052

посмотрите на нижний комментарий в отчете об ошибке:

"Только к вашему сведению: теперь в mesa по умолчанию используется -fno-builtin-memcmp Проблема "

Похоже, что memcpy в glibc намного лучше, чем встроенный ...

...