Kord, millega kasutaja üritas oma virtuaalmasinas RAM-i jõudlust jälgida, sattus mulle ühel päeval juhuslikult silma. Ma ei hakka seda koodi tooma (seal on „portjanka”), vaid jätan vaid kõige olulisema. Nii et, kass stuudios!
#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;
}Kõik on lihtne — eraldame mälu ja kirjutame sellesse ühe gigabaidi. Ja mida näitab see test?
$ ./memtest
4.06504 GB/s
Umbes 4GB/s.
Mis?!?!
Kuidas?!?!?
See on Core i7 (kuigi mitte kõige uuem), DDR4, protsessor on peaaegu koormamata — MIKS?!?!
Vastus on, nagu alati, imelikult tavaline.
Operaatore new (nagu ka funktsioon malloc, muide) ei eralda tegelikult mälu. Selle kutsumise ajal vaatab allokaator vaba jagunemiste loendit mälu puulus, ja kui neid pole, kutsub ta sbrk(), et andmeosa suurendada, ja seejärel tagastab programmile viite just äsja eraldatud ala aadressile.
Probleem on selles, et eraldatud ala on täielikult virtuaalne. Reaalsed mälulehed ei ole eraldatud.
Ja kui toimub esimene päring igasse lehte sellest eraldatud segmentist, „tulistab” MMU page fault, pärast mida määratakse virtuaalsele lehele, millele pääsemiseks üritatakse, reaalsed.
Seega testime tegelikult mitte bussi ja RAM-moodulite jõudlust, vaid operatsioonisüsteemi MMU ja VMM jõudlust. Ja selleks, et testida tegelikku RAM-i jõudlust, peame lihtsalt eraldatud alad kord ühekordselt initsialiseerima. Näiteks nii:
#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;
}See tähendab, et me lihtsalt initsialiseerime eraldatud puuteri vaikimisi väärtusega (char 0).
Kontrollin:
$ ./memtest
28.5714 GB/s
See on midagi muud.
Moraal — kui teil on vaja suuri puutereid, et kiiresti töötada, ärge unustage neid initsialiseerida.
Allikas: habr.com
