Ancora un po' di informazioni sui test errati

Una volta mi è capitato di vedere per caso un codice che un utente stava usando per monitorare le prestazioni della RAM nella sua macchina virtuale. Non fornirò questo codice (è una "sopportazione") e lascerò solo la parte più essenziale. Quindi, un gatto nello studio!

#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;
}

È tutto semplice: allochiamo la memoria e scriviamo un gigabyte in essa. E cosa mostra questo test?

$ ./memtest
4.06504 GB/s

Circa 4GB/s.

Cosa?!?!

Come?!?!?

Questa è una Core i7 (anche se non la più nuova), DDR4, il processore è quasi inattivo — PERCHÉ?!?!

La risposta, come sempre, è straordinariamente ordinaria.

L'operatore new (come la funzione malloc, peraltro) in realtà non alloca memoria. Durante questa chiamata, l'allocatore guarda la lista delle aree libere nel pool di memoria e, se non ci sono, chiama sbrk() per aumentare il segmento di dati, e poi restituisce al programma un riferimento all'indirizzo della nuova area appena allocata.

Il problema è che l'area allocata è completamente virtuale. Le pagine di memoria reali non sono allocate.

E quando avviene la prima richiesta a ciascuna pagina di questo segmento allocato, il MMU genera un page fault, dopo di che alla pagina virtuale a cui si accede viene assegnata una reale.

Quindi in realtà stiamo testando non le prestazioni del bus e dei moduli RAM, ma le prestazioni del MMU e del VMM del sistema operativo. E per testare le prestazioni reali della memoria RAM, dobbiamo semplicemente inizializzare una volta le aree allocate. Ad esempio, così:

#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;
}

Cioè, inizializziamo semplicemente i buffer allocati con un valore di default (char 0).

Controlliamo:

$ ./memtest
28.5714 GB/s

Un'altra cosa.

La morale è: se hai bisogno di grandi buffer per lavorare rapidamente, non dimenticare di inizializzarli.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster