микробеншмар производительности mmap против malloc против calloc: чего ожидать

#memory-management #malloc #mmap #copy-on-write

#управление памятью #malloc #mmap #копирование при записи

Вопрос:

Я создал микробенчмарку для сравнения производительности распределения и использования RSS для malloc и mmap.

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

Мои вопросы заключаются в том, является ли этот вывод правильным, и цифры, которые я привел, имеют какой-либо смысл (подробности см. Ниже).

 #include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/time.h>
int main()
{
#define SIZE 100
  void* allocated[SIZE];
  size_t size[SIZE];
  timeval then, now;
  memset(allocated, 0, sizeof allocated );
  gettimeofday(amp;then, NULL);
  size_t count = 0;
  size_t i = 0;
  for ( ;; )
  {
    if ( allocated[ i ] )
    {
      munmap( allocated[ i ], size[ i ] );
      //free( allocated[ i ] );
    }
    size[ i ] = rand() % 40000000   4096;
    allocated[ i ] =
      mmap( NULL, size[ i ],
          PROT_READ | PROT_WRITE,
          MAP_PRIVATE | MAP_ANONYMOUS
          /* | MAP_POPULATE */
        , -1, 0 );
    //allocated[ i ] = malloc( size[ i ] );
    //allocated[ i ] = calloc( 1, size[ i ] );
    //allocated[ i ] = calloc( size[ i ], 1 );
    i = (i 1) % SIZE;
    if ( !(   count amp; 0xfff ) )
    {
      gettimeofday(amp;now, NULL);
      double timedelta = now.tv_sec-then.tv_sec   1.e-6*( now.tv_usec-then.tv_usec );
      printf( "%f allocations/sn", count/timedelta );
    }
  }
}
  

В моей системе (настольная машина Sandy bridge) я получаю:

  1. mmap: ~ 900 000 выделений в секунду, RSS ~ 0,5 МБ, VSIZE ~ 2 ГБ
  2. mmap MAP_POPULATE: ~ 800 выделений в секунду, RSS и VSIZE ~ 2 ГБ
  3. malloc: ~ 280.000 выделений в секунду, RSS и VSIZE ~ 2 ГБ
  4. calloc: ~ 550 выделений в секунду, RSS и VSIZE ~ 2 ГБ
  5. malloc, MALLOC_PERTURB_ == 1: ~ 260 выделений / с, RSS и VSIZE ~ 2 ГБ

Я немного переписал это.

mmap MAP_POPULATE большую часть времени проводит в clear_page_c_e (2M вызовов / с), вызывается из __mm_populate . Я предположил, что это будет налог на ошибку страницы, который мне придется заплатить, если код действительно что-то делает с mmap’ed памятью, но…

…malloc (без переменной среды MALLOC_PERTURB_, установленной на что угодно) также проводит большую часть своего времени в clear_page_c_e (также 2 млн вызовов / с), но достигает гораздо большего количества выделений / с.

calloc и malloc с MALLOC_PERTURB_ проводят все свое время в memset. Я понимаю, что для malloc. Я думал, что calloc должен сопоставлять все страницы со страницей копирования при записи всех нулей, но мой glibc, по-видимому, этого не делает.

Все, кроме обычного mmap, увеличили RSS, что меня немного удивило. Я думал, что malloc и / или calloc будут делать это только при использовании памяти.

Комментарии:

1. Выделение буферов произвольного размера нереально. Программы имеют характерные шаблоны доступа, и если вы хотите знать, как будет работать ваша программа, вам нужно смоделировать ее шаблон доступа. Если вы просто хотите знать, насколько быстро malloc и mmap , затем запустите этот тест для различных фиксированных размеров выделения.

2. @larsmans Хороший момент. Изменение mmap на использование фиксированного размера выделения ничего не меняет в моей системе, но malloc ведет себя совсем по-другому. количество буферов 40 МБ по-прежнему составляет порядка 280.000 выделений / с, но без растущего RSS. количество буферов 4096 байт достигает ~ 33.000.000 выделений / с и все еще 4.000.000 выделений / с сMALLOC_PERTURB_. Оба эти параметра превосходят mmap / mmap MAP_POPULATE.

3. Интересно. По крайней мере, в системах Linux malloc использование нескольких десятков мегабайт фактически приводит к вызову mmap , в то время как меньшие выделения используют пользовательский распределитель.