NjĂ«herĂ« mu rastĂ«sisht mĂ« ra nĂ« sy njĂ« kod, me tĂ« cilin pĂ«rdoruesi po pĂ«rpiqej tĂ« monitoronte performancĂ«n e RAM nĂ« makinĂ« virtuale. Nuk do ta sjell kĂ«tĂ« kod (Ă«shtĂ« njĂ« âportanjkĂ«â) dhe do tĂ« lĂ« vetĂ«m thelbin. Pra, maca nĂ« studio!
#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;
}E gjitha Ă«shtĂ« e thjeshtĂ« â ndajnĂ« memorie dhe shkruajmĂ« nĂ« tĂ« njĂ« gigabajt. Dhe çfarĂ« tregon ky test?
$ ./memtest
4.06504 GB/s
Rreth 4GB/s.
Ăfar?!?!
Si?!?!?
Ky Ă«shtĂ« njĂ« Core i7 (edhe nĂ«se nuk Ă«shtĂ« mĂ« i ri), DDR4, procesori pothuajse nuk Ă«shtĂ« i ngarkuar â PSE?!?!
Përgjigjja, si gjithmonë, është jashtëzakonisht e zakonshme.
Operatori new (ashtu si funksioni malloc, për ta thënë) në të vërtetë nuk ndan memorie. Gjatë këtij thirrjeje, alokatori shikon listën e vendeve të lira në pool-in e memories, dhe nëse nuk ka, thërret sbrk() për të rritur segmentin e të dhënave, e pastaj i kthen programit një referencë në adresën e vendit të ri të sapo ndarë.
Problemi është se vendi i ndarë është krejtësisht virtual. Falet e vërteta të memories nuk janë ndarë.
Dhe kur ndodh firma e parë në secilën faqe të këtij segmenti të ndarë, MMU "shpërthente" page fault, pas së cilës faqeve virtuale, të cilës i qaset, i caktohet një e vërtetë.
Prandaj, në të vërtetë ne po testojmë jo performancën e busit dhe moduleve të RAM, por performancën e MMU dhe VMM të sistemit operativ. Dhe për të testuar performancën reale të memories operative, na nevojitet thjesht ta inicojmë një herë të vetme segmentet e ndara. Për shembull kështu:
#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;
}Pra, ne thjesht inicializojmë bufferat e ndarë me vlerën e paracaktuar (char 0).
Po kontrollojmë:
$ ./memtest
28.5714 GB/s
Një çështje tjetër.
Moral â nĂ«se ju nevojiten bufra tĂ« mĂ«dha pĂ«r tĂ« punuar shpejt-shpejt, mos harroni t'i inicializoni ato.
Burimi: habr.com
