Pak më shumë rreth testimit të gabuar

NjĂ« herĂ«, aksidentalisht, m’u shfaq njĂ« kod qĂ« pĂ«rdoruesi po pĂ«rpiqej tĂ« monitoronte performancĂ«n e RAM-it nĂ« makinĂ«n e tij virtuale. Nuk do ta sjell kĂ«tĂ« kod (Ă«shtĂ« njĂ« «bllok i gjatë») dhe do tĂ« lĂ« vetĂ«m tĂ« rĂ«ndĂ«sishmen. Pra, macja nĂ« 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;
}

E gjithĂ« çështja Ă«shtĂ« e thjeshtĂ« — ndajnĂ« kujtesĂ«n dhe shkruajmĂ« nĂ« tĂ« njĂ« gigabajt. Dhe çfarĂ« tregon ky test?

$ ./memtest
4.06504 GB/s

Aproximativ 4GB/s.

Çfar?!?!

Si?!?!?

Kjo Ă«shtĂ« njĂ« Core i7 (edhe pse jo mĂ« e reja), DDR4, procesori gati nuk Ă«shtĂ« i ngarkuar — PSE?!?!

Përgjigjja, si gjithmonë, është jashtëzakonisht e zakonshme.

Operatori new (si dhe funksioni malloc, për ta thënë të vërtetën) në realitet nuk ndan kujtesë. Në këtë thirrje, alokuesi shikon listën e segmenteve të lira në pool-in e kujtesës, dhe nëse nuk ka, thërret sbrk() për të rritur segmentin e të dhënave, dhe pastaj i kthen programit një referencë në adresën nga segmenti që sapo u ndal.

Problemi është se segmenti i ndarë është tërësisht virtual. Fletët e vërteta të kujtesës nuk janë ndarë.

Dhe kur ndodh kĂ«rkesa e parĂ« pĂ«r çdo fletĂ« nga ky segment i ndarĂ«, MMU „gjuaj“ page fault, pas sĂ« cilĂ«s fletĂ«s virtuale, e cila po kĂ«rkohet, i caktohet njĂ« e vĂ«rtetĂ«.

Prandaj, në të vërtetë, ne po testojmë jo performancën e autobusit dhe modulit të RAM-it, por performancën e MMU dhe VMM të sistemit operativ. Dhe për të testuar performancën reale të kujtesës operuese, na nevojitet thjesht ta inicializojmë një herë të vetme segmentin e ndarë. Për shembull kështu:

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

Pra, thjesht inicializojmë buffer-at e ndarë me një vlerë default (char 0).

Po kontrollojmë:

$ ./memtest
28.5714 GB/s

Një tjetër gjë.

Morrali — nĂ«se ju nevojiten buffer-a tĂ« mĂ«dhenj pĂ«r tĂ« punuar shpejt, mos harroni t'i inicializoni ato.

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster