Veidi veel vale testimise kohta

Kord, millega kasutaja üritas oma virtuaalmachine'i RAMi jõudlust jälgida, sattus mulle kord juhuslikult silma. Ma ei too koodi välja (seal on „portjantka”) ja jätan ainult kõige olulisema. Nii, kass stuudios!

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

Kõik on lihtne — eraldame mälu ja kirjutame sinna ühe gigabaiti. Ja mida see test näitab?

$ ./memtest
4.06504 GB/s

Umbes 4GB/s.

Mis?!?!

Kuidas?!?!?

See on Core i7 (kuigi mitte kõige uuem), DDR4, protsessor on peaaegu mitte koormatud — MIKS?!?!

Vastus on, nagu alati, erakordselt tavaline.

Juhend new (nagu ka funktsioon malloc, muide) ei eralda tegelikult mälu. Selle kutse puhul vaatab allokaator vabade osade loendit mälupools, ja kui neid pole, kutsub ta sbrk() välja, et andmeosa suurendada, ja seejärel tagastab programmile viite just äsja eraldatud osa aadressile.

Probleem on selles, et eraldatud osa on täielikult virtuaalne. Reaalsed mälulehed ei ole eraldatud.

Ja kui toimub esimene pöördumine igasse lehte sellest eraldatud segmendist, „tulistab” MMU page fault'i, pärast mida määratakse virtuaalsele lehele, millele pöördutakse, reaalne.

Seega testime tegelikult mitte bussi ja RAMi moodulite jõudlust, vaid MMU ja OS-i VMM-i jõudlust. Ja et testida operatiivmälu tegelikku jõudlust, peame lihtsalt kord üks kord eraldatud alasid initsialiseerima. Näiteks nii:

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

Selle asemel initsialiseerime lihtsalt eraldatavad puhvrid vaikeväärtusega (char 0).

Kontrollime:

$ ./memtest
28.5714 GB/s

Teine lugu.

Moraal — kui vajate suuri puhvrisid, et kiiresti töötada, ärge unustage neid initsialiseerida.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster