Једног дана сам случајно наишао на код да корисник покушава да прати перформансе РАМ-а у својој виртуелној машини. Нећу давати ову шифру (ту је „крпа за ноге“) и оставићу само оно најбитније. Дакле, мачка је у студију!
#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).
Проверавамо:
$ ./мемтест
КСНУМКС ГБ / с
Друга ствар.
Морал приче - ако су вам потребни велики бафери за брз рад, не заборавите да их иницијализујете.
Извор: ввв.хабр.цом