Nedaudz vairāk par sliktu testēšanu

Kādu dienu es nejauši uzgāju kodu, ar kuru lietotājs mēģināja pārraudzīt RAM veiktspēju savā virtuālajā mašīnā. Es nedošu šo kodu (tur ir "kādu lupatiņa") un atstāšu tikai vissvarīgāko. Tātad, kaķis ir studijā!

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

Tas ir vienkārši - piešķiriet atmiņu un ierakstiet tajā vienu gigabaitu. Un ko šis tests parāda?

$ ./memtest
4.06504 GB / s

Aptuveni 4GB/s.

Kas?!?!

Kā?!?!?

Šis ir Core i7 (lai gan ne jaunākais), DDR4, procesors gandrīz nav ielādēts - KĀPĒC?!?!

Atbilde, kā vienmēr, ir neparasti parasta.

Jaunais operators (tāpat kā malloc funkcija, starp citu) faktiski nepiešķir atmiņu. Izmantojot šo zvanu, sadalītājs apskata brīvo vietu sarakstu atmiņas pūlā un, ja tādu nav, izsauc sbrk(), lai palielinātu datu segmentu, un pēc tam atgriež programmā atsauci uz adresi no jaunās vietas. piešķirts.

Problēma ir tā, ka piešķirtā platība ir pilnībā virtuāla. Reālas atmiņas lapas netiek piešķirtas.

Un, kad notiek pirmā piekļuve katrai lapai no šī piešķirtā segmenta, MMU “izšauj” lapas kļūdu, pēc kuras virtuālajai lapai, kurai tiek piekļūts, tiek piešķirta reāla.

Tāpēc faktiski mēs pārbaudām nevis kopnes un RAM moduļu veiktspēju, bet gan operētājsistēmas MMU un VMM veiktspēju. Un, lai pārbaudītu RAM reālo veiktspēju, mums tikai vienu reizi jāinicializē piešķirtās zonas. Piemēram, šādi:

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

Tas ir, mēs vienkārši inicializējam piešķirtos buferus ar noklusējuma vērtību (char 0).

Pārbaude:

$ ./memtest
28.5714 GB / s

Cita lieta.

Stāsta morāle - ja jums ir nepieciešami lieli buferi, lai ātri strādātu, neaizmirstiet tos inicializēt.

Avots: www.habr.com

Pievieno komentāru