C: szybkość memcpy na dynamicznie przydzielanych tablicach

Potrzebuję pomocy przy wykonywaniu następującego kodu. Robi memcpy na dwóch dynamicznie przydzielanych tablicach o dowolnym rozmiarze:

int main()
{
  double *a, *b;
  unsigned n = 10000000, i;
  a = malloc(n*sizeof(double));
  b = malloc(n*sizeof(double));
  for(i=0; i<n; i++) {
    a[i] = 1.0;
    /* b[i] = 0.0; */
  }

  tic();
  bzero(b, n*sizeof(double));
  toc("bzero1");

  tic();
  bzero(b, n*sizeof(double));
  toc("bzero2");

  tic();
  memcpy(b, a, n*sizeof(double));
  toc("memcpy");
}

tic / toc mierzą czas wykonania.

Na moim komputerze zajmuje 0,035s do memcpy (Linux, gcc wersja 4.4.6). Jeśli teraz odkomentuję linię inicjującą tablicę docelową b, kod jest trzy razy szybszy (!) - 0,011s.

Obserwowałem podobne zachowanie podczas używania pętli zamiast memcpy. Zwykle nie przejmuję się tym, ponieważ wystarczy „zainicjować” pamięć przed jej użyciem. Jednak teraz muszę wykonać prostą kopię pamięci i zrobić to jak najszybciej. Inicjowanie danych wymaga napisania np. 0 do pamięci, co nie jest konieczne i wymaga czasu. Chciałbym wykonać kopię pamięci z całą dostępną przepustowością pamięci.

Czy istnieje rozwiązanie tego problemu? Czy jest to związane ze sposobem, w jaki Linux obsługuje pamięć dynamiczną (jakiś rodzaj leniwej alokacji stron?) I nie można go obejść? Jak to jest w innych systemach?

Edytować: Takie same wyniki uzyskuje się z gcc 4.6. Użyłem -O3 do kompilacji.

Edytować: Dziękuję wszystkim za komentarze. Rozumiem, że mapowanie pamięci wymaga czasu. Myślę, że po prostu trudno mi zaakceptować, że trwa to tak długo, znacznie dłużej niż rzeczywisty dostęp do pamięci. Kod został zmodyfikowany tak, aby zawierał benchmark inicjalizacji tablicy b przy użyciu dwóch kolejnych wywołań bzero. Czas pokazuje teraz

bzero1 0.273981
bzero2 0,056803
memcpy 0,117934

Oczywiście pierwsze wywołanie bzero to robidużo więcej niż tylko zera strumieni do pamięci - czyli mapowanie pamięci i zerowanie pamięci. Drugie wywołanie bzero z drugiej strony zajmuje połowę czasu wymaganego do wykonania memcpy, co jest dokładnie takie, jak oczekiwano - tylko czas zapisu i czas odczytu i zapisu. Rozumiem, że koszty drugiego połączenia bzero muszą tam być ze względu na bezpieczeństwo systemu operacyjnego. Co z resztą? Czy nie mogę go jakoś zmniejszyć, np. używać większych stron pamięci? Różne ustawienia jądra?

Powinienem wspomnieć, że uruchamiam to na Ubuntu wheeze.

questionAnswers(3)

yourAnswerToTheQuestion