Yomon sinov haqida bir oz ko'proq

Bir kuni men tasodifan foydalanuvchi o'zining virtual mashinasida RAM ishlashini nazorat qilmoqchi bo'lgan kodga duch keldim. Men bu kodni bermayman (u erda "oyoq kiyimi" bor) va men faqat eng zarurini qoldiraman. Demak, mushuk studiyada!

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

Hammasi oddiy - xotirani ajrating va unga bir gigabayt yozing. Va bu test nimani ko'rsatadi?

$ ./memtest
4.06504 G / s

Taxminan 4 GB/s.

Nima?!?!

Qanaqasiga?!?!?

Bu Core i7 (eng yangi bo'lmasa ham), DDR4, protsessor deyarli yuklanmagan - NEGA?!?!

Javob, har doimgidek, g'ayrioddiy.

Yangi operator (masalan, malloc funktsiyasi kabi) aslida xotirani ajratmaydi. Ushbu qo'ng'iroq bilan ajratuvchi xotira hovuzidagi bo'sh joylar ro'yxatini ko'rib chiqadi va agar ular bo'lmasa, ma'lumotlar segmentini oshirish uchun sbrk() ni chaqiradi va keyin dasturga yangi joydan manzilga havolani qaytaradi. ajratilgan.

Muammo shundaki, ajratilgan maydon butunlay virtualdir. Haqiqiy xotira sahifalari ajratilmagan.

Va ushbu ajratilgan segmentdan har bir sahifaga birinchi marta kirish sodir bo'lganda, MMU sahifa xatosini "otib tashlaydi", shundan so'ng kirish virtual sahifasiga haqiqiy sahifa tayinlanadi.

Shuning uchun, aslida, biz avtobus va RAM modullarining ishlashini emas, balki operatsion tizimning MMU va VMM ishlashini sinab ko'rmoqdamiz. Va RAMning haqiqiy ishlashini sinab ko'rish uchun biz ajratilgan maydonlarni bir marta ishga tushirishimiz kerak. Masalan, shunday:

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

Ya'ni, biz ajratilgan buferlarni oddiy qiymat bilan ishga tushiramiz (char 0).

Biz tekshiramiz:

$ ./memtest
28.5714 G / s

Yana bir narsa.

Hikoyaning axloqi - agar sizga tez ishlash uchun katta buferlar kerak bo'lsa, ularni ishga tushirishni unutmang.

Manba: www.habr.com

a Izoh qo'shish