Ancora un po' di discussione sui test errati.

Un giorno mi sono casualmente imbattuto in un codice in cui un utente cercava di monitorare le prestazioni della RAM nella sua macchina virtuale. Non fornirò il codice (era una «lista lunga») e mi limiterò a dare solo le informazioni essenziali. Ecco qui, un gatto in 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;
}

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

$ ./memtest
4.06504 GB/s

Circa 4GB/s.

Cosa?!?!

Come?!?!?

È un Core i7 (anche se non è il più recente), 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. In questo richiamo, l'allocatore controlla la lista delle aree libere nel pool di memoria, e se non ce ne sono, chiama sbrk() per aumentare il segmento dati, e poi restituisce al programma un link all'indirizzo del nuovo segmento appena allocato.

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

E quando avviene il primo accesso a ciascuna pagina di questo segmento allocato, l'MMU fa scattare un page fault, dopo di che alla pagina virtuale a cui si accede viene assegnata una reale.

Pertanto, in realtà stiamo testando non le prestazioni del bus e dei moduli RAM, ma le prestazioni dell'MMU e della VMM del sistema operativo. E per testare le reali prestazioni della memoria RAM, dobbiamo semplicemente inizializzare una volta per tutte 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 il valore di default (char 0).

Controllando:

$ ./memtest
28.5714 GB/s

Questo è un altro discorso.

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, server VPS VDS 🔥 Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS | ProHoster