Einn daginn rakst ég óvart á kóða sem notandi var að reyna að fylgjast með vinnsluminni í sýndarvélinni sinni. Ég mun ekki gefa þennan kóða (það er „fótaklútur“ þar) og ég mun aðeins skilja eftir það mikilvægasta. Svo, kötturinn er í vinnustofunni!
#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;
}
Það er einfalt - úthlutaðu minni og skrifaðu eitt gígabæt inn í það. Og hvað sýnir þetta próf?
$ ./memtest
4.06504 GB / s
Um það bil 4GB/s.
Hvað?!?!
Hvernig?!?!?
Þetta er Core i7 (þó ekki það nýjasta), DDR4, örgjörvinn er nánast ekki hlaðinn - AFHVERJU?!?!
Svarið, eins og alltaf, er óvenjulega venjulegt.
Nýi rekstraraðilinn (eins og malloc aðgerðin, við the vegur) úthlutar í raun ekki minni. Með þessu símtali lítur úthlutunaraðilinn á listann yfir lausar staðsetningar í minnisafninu og ef þær eru engar kallar hann sbrk() til að auka gagnahlutann og skilar síðan tilvísun í slóðina frá nýja staðsetningunni í forritið. úthlutað.
Vandamálið er að úthlutað svæði er algjörlega raunverulegt. Engum raunverulegum minnissíðum er úthlutað.
Og þegar fyrsti aðgangurinn að hverri síðu frá þessum úthlutaða hluta á sér stað, „skýtur“ MMU síðuvillu, eftir það er sýndarsíðunni sem verið er að opna á úthlutað raunverulegri.
Þess vegna erum við í raun ekki að prófa frammistöðu strætó- og vinnsluminni eininganna, heldur frammistöðu MMU og VMM stýrikerfisins. Og til þess að prófa raunverulegan árangur vinnsluminni, þurfum við bara að frumstilla úthlutað svæði einu sinni. Til dæmis svona:
#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;
}
Það er, við frumstillum einfaldlega úthlutaða biðminni með sjálfgefna gildinu (char 0).
Við athugum:
$ ./memtest
28.5714 GB / s
Annar hlutur.
Mórall sögunnar - ef þú þarft stóra biðminni til að vinna hratt, ekki gleyma að frumstilla þá.
Heimild: www.habr.com