Un pocu di più nantu à e mala prova

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

Add a comment