Un ghjornu aghju scontru accidentalmente codice chì un utilizatore provava di monitorà u rendiment di RAM in a so macchina virtuale. Ùn daraghju micca stu codice (ci hè un "footcloth" quì) è lasciaraghju solu u più essenziale. Allora, u ghjattu hè in u studiu!
#include <sys/time.h>
#include <string.h>
#include <iostream>
#define CNT 1024
#define SIZE (1024*1024)
int main() {
struct timeval start;
struct timeval end;
long millis;
double gbs;
char ** buffers;
buffers = new char*[CNT];
for (int i=0;i<CNT;i++) {
buffers[i] = new char[SIZE];
}
gettimeofday(&start, NULL);
for (int i=0;i<CNT;i++) {
memset(buffers[i], 0, SIZE);
}
gettimeofday(&end, NULL);
millis = (end.tv_sec - start.tv_sec) * 1000 +
(end.tv_usec - start.tv_usec) / 1000;
gbs = 1000.0 / millis;
std::cout << gbs << " GB/sn";
for (int i=0;i<CNT;i++) {
delete buffers[i];
}
delete buffers;
return 0;
}
Hè simplice - allocate memoria è scrivite un gigabyte in questu. È chì mostra sta prova?
$ ./memtest
4.06504 GB / s
Circa 4 GB/s.
chì?!?!
Cumu?!?!?
Questu hè Core i7 (ancu ùn hè micca u più novu), DDR4, u processatore ùn hè quasi micca carricu - PERCHÈ ?!?!
A risposta, cum'è sempre, hè inusualmente ordinaria.
U novu operatore (cum'è a funzione malloc, per via) ùn hè micca veramente attribuitu memoria. Cù sta chjama, l'allocatore guarda a lista di lochi liberi in u pool di memoria, è s'ellu ùn ci hè nimu, chjama sbrk () per aumentà u segmentu di dati, è poi torna à u prugramma una riferenza à l'indirizzu da u novu locu solu. attribuitu.
U prublema hè chì l'area attribuita hè interamente virtuale. Nisuna pagina di memoria reale hè attribuita.
È quandu u primu accessu à ogni pagina da stu segmentu attribuitu si trova, u MMU "spara" un difettu di pagina, dopu chì a pagina virtuale accede hè attribuita una vera.
Dunque, in fattu, ùn avemu micca pruvatu a prestazione di i moduli di bus è RAM, ma a prestazione di u MMU è VMM di u sistema operatore. È per pruvà a vera prestazione di a RAM, avemu solu bisognu di inizializza una volta i spazii assignati. Per esempiu cusì:
#include <sys/time.h>
#include <string.h>
#include <iostream>
#define CNT 1024
#define SIZE (1024*1024)
int main() {
struct timeval start;
struct timeval end;
long millis;
double gbs;
char ** buffers;
buffers = new char*[CNT];
for (int i=0;i<CNT;i++) {
// FIXED HERE!!!
buffers[i] = new char[SIZE](); // Add brackets, &$# !!!
}
gettimeofday(&start, NULL);
for (int i=0;i<CNT;i++) {
memset(buffers[i], 0, SIZE);
}
gettimeofday(&end, NULL);
millis = (end.tv_sec - start.tv_sec) * 1000 +
(end.tv_usec - start.tv_usec) / 1000;
gbs = 1000.0 / millis;
std::cout << gbs << " GB/sn";
for (int i=0;i<CNT;i++) {
delete buffers[i];
}
delete buffers;
return 0;
}
Questu hè, simpricimenti inizializzamu i buffers assignati cù u valore predeterminatu (char 0).
Verificate:
$ ./memtest
28.5714 GB / s
Un'altra cosa.
Morale di a storia - se avete bisognu di grandi buffers per travaglià rapidamente, ùn vi scurdate di inizializzalli.
Source: www.habr.com