Lidt mere om dårlig test

En dag stødte jeg ved et uheld på kode, som en bruger forsøgte at overvåge RAM-ydeevne i sin virtuelle maskine. Jeg vil ikke give denne kode (der er en "fodklud"), og jeg vil kun efterlade det mest væsentlige. Så katten er i studiet!

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

Det er enkelt - alloker hukommelse og skriv en gigabyte ind i den. Og hvad viser denne test?

$ ./memtest
4.06504 GB / s

Cirka 4 GB/s.

Hvad?!?!

Hvordan?!?!?

Dette er Core i7 (omend ikke den nyeste), DDR4, processoren er næsten ikke indlæst - HVORFOR?!?!

Svaret er som altid usædvanligt.

Den nye operatør (som malloc-funktionen i øvrigt) tildeler faktisk ikke hukommelse. Med dette kald ser allokatoren på listen over ledige steder i hukommelsespuljen, og hvis der ikke er nogen, kalder sbrk() for at øge datasegmentet, og returnerer derefter til programmet en reference til adressen fra den nye placering. tildelt.

Problemet er, at det tildelte areal er helt virtuelt. Ingen reelle hukommelsessider tildeles.

Og når den første adgang til hver side fra dette tildelte segment indtræffer, "skyder" MMU en sidefejl, hvorefter den virtuelle side, der tilgås, tildeles en rigtig.

Derfor tester vi faktisk ikke ydelsen af ​​bus- og RAM-modulerne, men ydelsen af ​​MMU og VMM i operativsystemet. Og for at teste den reelle ydeevne af RAM, skal vi blot initialisere de tildelte områder én gang. For eksempel sådan her:

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

Det vil sige, at vi simpelthen initialiserer de tildelte buffere med standardværdien (char 0).

Vi tjekker:

$ ./memtest
28.5714 GB / s

En anden ting.

Historiens moral - hvis du har brug for store buffere for at arbejde hurtigt, så glem ikke at initialisere dem.

Kilde: www.habr.com

Tilføj en kommentar