Apur bat gehiago proba txarrei buruz

Egun batean, ustekabean, erabiltzaile bat RAMaren errendimendua bere makina birtualean kontrolatzen saiatzen ari zen kodea topatu nuen. Ez dut kode hau emango (hor "oinetako bat" dago) eta ezinbestekoena baino ez dut utziko. Beraz, katua estudioan dago!

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

Erraza da: esleitu memoria eta idatzi gigabyte bat. Eta zer erakusten du proba honek?

$ ./memtest
4.06504 GB / s

Gutxi gorabehera 4 GB/s.

Zer?!?!

Nola?!?!?

Hau Core i7 da (berriena ez bada ere), DDR4, prozesadorea ia ez dago kargatuta - ZERGATIK?!?!

Erantzuna, beti bezala, ohikoa da.

Operadore berriak (malloc funtzioa bezala, bide batez) ez du benetan memoria esleitzen. Dei honekin, esleitzaileak memoria multzoko kokapen libreen zerrenda begiratzen du, eta ez badago, sbrk() deitzen du datu-segmentua handitzeko, eta, ondoren, programara itzultzen du kokapen berriko helbidearen erreferentzia. esleitu.

Arazoa da esleitutako eremua guztiz birtuala dela. Ez da benetako memoria-orririk esleitzen.

Eta esleitutako segmentu horretatik orrialde bakoitzerako lehen sarbidea gertatzen denean, MMU-k orri-akats bat "tiro" egiten du, eta ondoren sartzen den orrialde birtuala benetako bat esleitzen zaio.

Horregatik, hain zuzen ere, ez dugu bus eta RAM moduluen errendimendua probatzen ari, sistema eragilearen MMU eta VMMren errendimendua baizik. Eta RAM-aren errendimendu erreala probatzeko, esleitutako eremuak behin hasi behar ditugu. Adibidez, honela:

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

Hau da, esleitutako buffer-ak balio lehenetsiarekin (char 0) hasieratzen ditugu.

Egiaztatzen dugu:

$ ./memtest
28.5714 GB / s

Beste gauza bat.

Istorioaren morala - Buffer handiak behar badituzu azkar lan egiteko, ez ahaztu hasieratzea.

Iturria: www.habr.com

Gehitu iruzkin berria