Нашар тестілеу туралы аздап

Бір күні мен кездейсоқ пайдаланушы виртуалды машинасында ЖЖҚ өнімділігін бақылауға тырысатын кодты кездестірдім. Мен бұл кодты бермеймін («аяқ киім» бар) және мен тек ең маңыздысын қалдырамын. Сонымен, мысық студияда!

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

Барлығы қарапайым - жадты бөліп, оған бір гигабайт жазыңыз. Ал бұл сынақ нені көрсетеді?

$./memtest
4.06504 Гб / с

Шамамен 4 ГБ/с.

Не?!?!

Қалай?!?!?

Бұл Core i7 (ең жаңасы болмаса да), DDR4, процессор дерлік жүктелмеген - НЕГЕ?!?!

Жауап, әдеттегідей, әдеттен тыс қарапайым.

Жаңа оператор (айтпақшы, malloc функциясы сияқты) жадты нақты бөлмейді. Бұл шақыру арқылы бөлуші жад пулындағы бос орындардың тізімін қарайды, ал егер жоқ болса, деректер сегментін ұлғайту үшін sbrk() функциясын шақырады, содан кейін бағдарламаға жаңа орыннан мекенжайға сілтемені қайтарады. бөлінген.

Мәселе мынада, бөлінген аумақ толығымен виртуалды. Нақты жад беттері бөлінбейді.

Осы бөлінген сегменттен әрбір бетке бірінші рет қол жеткізу орын алғанда, MMU бет ақаулығын «атады», содан кейін қол жеткізілетін виртуалды бетке нақты бет тағайындалады.

Сондықтан, шын мәнінде, біз шина мен жедел жад модульдерінің өнімділігін емес, операциялық жүйенің MMU және VMM өнімділігін тексереміз. ЖЖҚ-ның нақты өнімділігін тексеру үшін бізге бөлінген аумақтарды бір рет инициализациялау жеткілікті. Мысалы, келесідей:

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

Яғни, біз жай ғана бөлінген буферлерді әдепкі мәнмен (char 0) инициализациялаймыз.

Тексеру:

$./memtest
28.5714 Гб / с

Басқа іс.

Әңгіменің моральдық мәні - егер сізге жылдам жұмыс істеу үшін үлкен буфер қажет болса, оларды инициализациялауды ұмытпаңыз.

Ақпарат көзі: www.habr.com

пікір қалдыру