Z 192 GB pamięci RAM zainstalowanej na moim komputerze, mam 188 GB pamięci RAM powyżej 4 GB (pod adresem sprzętowym 0x100000000) zarezerwowane przez jądro Linux podczas startu systemu (mem = 4G memmap = 188G 4G). Moduły jądra gromadzące dane gromadzą dane w tym dużym obszarze, używanym jako bufor pierścieniowy przy użyciu DMA. Aplikacja przestrzeni użytkownika mmap przekształca ten bufor pierścieniowy w przestrzeń użytkownika, a następnie kopiuje bloki z bufora pierścieniowego w bieżącej lokalizacji w celu przetworzenia, gdy będą gotowe.Słaba wydajność nagrywania w przestrzeni użytkownika dla mmap'ed pamięci fizycznej w systemie Linux
Kopiowanie tych bloków 16 MB z obszaru mmap'ed za pomocą memcpy nie działa zgodnie z oczekiwaniami. Wydaje się, że wydajność zależy od wielkości pamięci zarezerwowanej w czasie rozruchu (i późniejszej mmap'ed w przestrzeni użytkownika). http://www.wurmsdobler.org/files/resmem.zip zawiera kod źródłowy moduł jądra, która nie wykonuje operację pliku mmap:
module_param(resmem_hwaddr, ulong, S_IRUSR);
module_param(resmem_length, ulong, S_IRUSR);
//...
static int resmem_mmap(struct file *filp, struct vm_area_struct *vma) {
remap_pfn_range(vma, vma->vm_start,
resmem_hwaddr >> PAGE_SHIFT,
resmem_length, vma->vm_page_prot);
return 0;
}
i stosowania testów, które wykonuje w zasadzie (z usuniętą kontrole):
#define BLOCKSIZE ((size_t)16*1024*1024)
int resMemFd = ::open(RESMEM_DEV, O_RDWR | O_SYNC);
unsigned long resMemLength = 0;
::ioctl(resMemFd, RESMEM_IOC_LENGTH, &resMemLength);
void* resMemBase = ::mmap(0, resMemLength, PROT_READ | PROT_WRITE, MAP_SHARED, resMemFd, 4096);
char* source = ((char*)resMemBase) + RESMEM_HEADER_SIZE;
char* destination = new char[BLOCKSIZE];
struct timeval start, end;
gettimeofday(&start, NULL);
memcpy(destination, source, BLOCKSIZE);
gettimeofday(&end, NULL);
float time = (end.tv_sec - start.tv_sec)*1000.0f + (end.tv_usec - start.tv_usec)/1000.0f;
std::cout << "memcpy from mmap'ed to malloc'ed: " << time << "ms (" << BLOCKSIZE/1000.0f/time << "MB/s)" << std::endl;
I prowadzone z memcpy testów bloku danych 16 MB dla różnych rozmiarów przeznaczonym RAM (resmem_length) Ubuntu 10.04.4, Linux 2.6.32, na SuperMicro 1026GT-TF-FM109:
| | 1GB | 4GB | 16GB | 64GB | 128GB | 188GB
|run 1 | 9.274ms (1809.06MB/s) | 11.503ms (1458.51MB/s) | 11.333ms (1480.39MB/s) | 9.326ms (1798.97MB/s) | 213.892ms ( 78.43MB/s) | 206.476ms ( 81.25MB/s)
|run 2 | 4.255ms (3942.94MB/s) | 4.249ms (3948.51MB/s) | 4.257ms (3941.09MB/s) | 4.298ms (3903.49MB/s) | 208.269ms ( 80.55MB/s) | 200.627ms ( 83.62MB/s)
Moje spostrzeżenia są następujące:
Od pierwszego do drugiego biegu, memcpy z mmap-owany do malloc'ed wydaje się korzystne, że zawartość może już być przechowywane gdzieś.
Występuje znaczny spadek wydajności od> 64 GB, co można zauważyć zarówno podczas korzystania z memcpy.
Chciałbym zrozumieć, dlaczego tak jest. Może ktoś w grupie programistów jądra Linux myśli: 64GB powinno wystarczyć każdemu (robi to pierścień dzwon?)
poważaniem, peter
Witam Ignacio, może mieć rację. Komputer jest wyposażony w dwa procesory Intel Xeon E5620 2.Czterordzeniowy procesor 4GHz z pamięcią podręczną 12MB L3 i prędkością 1066 MHz. – PeterW
Mój uproszczony widok jest taki, że dla pierwszej operacji odczytu zawartość pamięci RAM byłaby buforowana, a drugie żądanie byłoby podawane bezpośrednio z pamięci podręcznej, o ile wielkość mieści się w pamięci podręcznej. Sądziłem, że ilość przesłanych danych będzie miała wpływ na memcpy, w moim przypadku <12 MB, ale nie na całkowity rozmiar pamięci zainstalowanej lub gdzie w pamięci RAM są dane. – PeterW
Dalsze testy wykazały, że ta sama degradacja wydajności dotyczy mniejszych bloków danych, np. 1 MB. Wydaje mi się, że zależy to tylko od ilości pamięci zarezerwowanej podczas rozruchu, czyli nie więcej niż 64 GB. – PeterW