Bir gün təsadüfən istifadəçinin virtual maşınında RAM performansını izləmək üçün istifadə etdiyi kod mənə gözümə dəydi. Mən bu kodu təqdim etməyəcəyəm (orada "portyanka" var) və yalnız ən vacib şeyləri buraxacağam. Beləliklə, studiyada pişik var!
#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;
}Hər şey sadədir - yaddaş ayırırıq və ona bir gigabayt yazırıq. Və bu test nə göstərir?
$ ./memtest
4.06504 GB/s
Təxminən 4GB/s.
Nə?!?!
Necə?!?!?
Bu, Core i7 (qoy elə də yeni olmasın), DDR4, prosessor demək olar ki, yüklənməmişdir — NİYƏ?!?!
Cavab, həmişəki kimi, qeyri-adi dərəcədə adi.
New operatoru (məsələn, malloc funksiyası da) əslində yaddaş ayırmır. Bu çağırış zamanı allocator sərbəst blokların siyahısına baxır, və əgər onlar yoxdursa, sbrk() çağırır ki, məlumat seqmentini artırsın, və sonra proqramın yeni ayrılmış blokun ünvanına istinadını qaytarır.
Problemi odur ki, ayrılmış blok tamamilə virtualdır. Əsl yaddaş səhifələri ayrılmamışdır.
Və bu ayrılmış seqmentdə hər səhifəyə ilk müraciət zamanı, MMU "səhifə hatası" atır, bundan sonra həmin virtual səhifəyə real olanın ünvanı təyin edilir.
Buna görə də, əslində biz RAM modulları və şininin performansını deyil, sistemin MMU və VMM-in performansını test edirik. Və əsl RAM performansını test etmək üçün ayrılan blokları yalnız bir dəfə başlatmalıyıq. Məsələn:
#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;
}Yəni, biz sadəcə ayrılan buffer-ları standart bir dəyərlə (char 0) başlatırıq.
Yoxlayırıq:
$ ./memtest
28.5714 GB/s
Başqa bir məsələ.
Mora - əgər sizə böyük buferlər lazım olsa, tez işləmək üçün, onları başlatmağı unudmayın.
Mənbə: habr.com
