Још мало о лошем тестирању

Једног дана сам случајно наишао на код да корисник покушава да прати перформансе РАМ-а у својој виртуелној машини. Нећу давати ову шифру (ту је „крпа за ноге“) и оставићу само оно најбитније. Дакле, мачка је у студију!

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

Једноставно је - доделите меморију и упишите један гигабајт у њу. И шта показује овај тест?

$ ./мемтест
КСНУМКС ГБ / с

Приближно 4ГБ/с.

Шта?!?!

Како?!?!?

Ово је Цоре и7 (иако не најновији), ДДР4, процесор скоро да није напуњен - ЗАШТО?!?!

Одговор је, као и увек, необично обичан.

Нови оператор (као и маллоц функција, иначе) заправо не додељује меморију. Са овим позивом, алокатор гледа листу слободних локација у меморијском базену, и ако их нема, позива сбрк() да повећа сегмент података, а затим враћа програму референцу на адресу са нове локације само Издвојено.

Проблем је у томе што је додељено подручје потпуно виртуелно. Не додељују се праве меморијске странице.

А када дође до првог приступа свакој страници из овог додељеног сегмента, ММУ „пуца“ грешку странице, након чега виртуелној страници којој се приступа се додељује стварна.

Стога, у ствари, не тестирамо перформансе магистрале и РАМ модула, већ перформансе ММУ и ВММ оперативног система. А да бисмо тестирали стварне перформансе РАМ-а, потребно је само једном да иницијализујемо додељене области. На пример овако:

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

То јест, ми једноставно иницијализујемо додељене бафере са подразумеваном вредношћу (цхар 0).

Проверавамо:

$ ./мемтест
КСНУМКС ГБ / с

Друга ствар.

Морал приче - ако су вам потребни велики бафери за брз рад, не заборавите да их иницијализујете.

Извор: ввв.хабр.цом

Додај коментар