Hieman lisää huonoista testeistä

Eräänä päivänä törmäsin vahingossa koodiin, jolla käyttäjä yritti seurata RAM-muistin suorituskykyä virtuaalikoneessaan. En anna tätä koodia (siellä on "jalkaliina") ja jätän vain tärkeimmän. Eli kissa on studiossa!

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

Se on yksinkertaista - varaa muistia ja kirjoita siihen yksi gigatavu. Ja mitä tämä testi osoittaa?

$ ./memtest
4.06504 GB / s

Noin 4GB/s.

Mitä?!?!

Miten?!?!?

Tämä on Core i7 (tosin ei uusin), DDR4, prosessoria ei juuri ole ladattu - MIKSI?!?!

Vastaus, kuten aina, on epätavallisen tavallinen.

Uusi operaattori (kuten malloc-funktio muuten) ei varsinaisesti varaa muistia. Tällä kutsulla allokaattori tarkastelee luetteloa muistivaraston vapaista sijainneista, ja jos niitä ei ole, kutsuu sbrk() datasegmentin lisäämiseksi ja palauttaa sitten ohjelmaan viittauksen osoitteeseen uudesta sijainnista. myönnetty.

Ongelmana on, että varattu alue on täysin virtuaalinen. Varsinaisia ​​muistisivuja ei varata.

Ja kun ensimmäinen pääsy kullekin sivulle tästä varatusta segmentistä tapahtuu, MMU "ammuu" sivuvirheen, jonka jälkeen avattavalle virtuaaliselle sivulle osoitetaan todellinen.

Siksi itse asiassa emme testaa väylä- ja RAM-moduulien, vaan käyttöjärjestelmän MMU:n ja VMM:n suorituskykyä. Ja jotta voimme testata RAM:n todellista suorituskykyä, meidän on vain alustettava allokoidut alueet kerran. Esimerkiksi näin:

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

Eli yksinkertaisesti alustamme varatut puskurit oletusarvolla (char 0).

tarkista:

$ ./memtest
28.5714 GB / s

Toinen asia.

Tarinan moraali - jos tarvitset suuria puskureita toimiaksesi nopeasti, älä unohda alustaa niitä.

Lähde: will.com

Lisää kommentti