Sedikit lagi tentang pengujian yang tidak tepat

Suatu hari saya tidak sengaja melihat kode bahwa seorang pengguna mencoba untuk memantau kinerja RAM di mesin virtualnya. Saya tidak akan memberikan kode ini (ada "alas kaki") dan hanya meninggalkan yang paling penting. Jadi, kucingnya ada di 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/s\n";
	for (int i=0;i<CNT;i++) {
		delete buffers[i];
	}
	delete buffers;
	return 0;
}

Semuanya sederhana - kami mengalokasikan memori dan menulis satu gigabyte ke dalamnya. Dan apa yang ditunjukkan oleh tes ini?

$ ./memtest
4.06504 GB / s


Sekitar 4GB / s.

Apa?!?!

Bagaimana?!?!?

Ini adalah Core i7 (meskipun bukan yang terbaru), DDR4, prosesornya hampir tidak dimuat - MENGAPA?!?!

Jawabannya, seperti biasa, luar biasa biasa.

Operator baru (seperti fungsi malloc, omong-omong) sebenarnya tidak mengalokasikan memori. Dengan panggilan ini, pengalokasi melihat daftar bagian bebas di kumpulan memori, dan jika tidak ada, panggilan sbrk () untuk memperbesar segmen data, dan kemudian mengembalikan program tautan ke alamat dari bagian yang baru dipilih.

Masalahnya adalah area yang dipilih benar-benar virtual. Halaman memori nyata tidak dialokasikan.

Dan ketika akses pertama ke setiap halaman dari segmen yang dipilih ini terjadi, MMU "menembak" kesalahan halaman, setelah itu halaman virtual dimana akses dibuat ditugaskan ke yang asli.

Oleh karena itu, pada kenyataannya, kami menguji bukan kinerja modul bus dan RAM, tetapi kinerja MMU dan VMM dari sistem operasi. Dan untuk menguji kinerja RAM yang sebenarnya, kita hanya perlu menginisialisasi bagian yang dialokasikan sekali. Misalnya, seperti ini:

#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/s\n";
	for (int i=0;i<CNT;i++) {
		delete buffers[i];
	}
	delete buffers;
	return 0;
}

Artinya, kita cukup menginisialisasi buffer yang dialokasikan dengan nilai default (char 0).

Memeriksa:

$ ./memtest
28,5714 GB / s


Hal lain.

Moral - jika Anda membutuhkan buffer besar untuk bekerja dengan cepat dan cepat, jangan lupa untuk menginisialisasi mereka.

Source: https://habr.com/ru/post/undefined/


All Articles