Kötü testler hakkında biraz daha

Bir gün yanlışlıkla bir kullanıcının sanal makinesindeki RAM performansını izlemeye çalıştığı kodla karşılaştım. Bu kodu vermeyeceğim (orada bir “ayak örtüsü” var) ve sadece en gerekli olanı bırakacağım. Demek kedi stüdyoda!

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

Çok basit - belleği ayırın ve içine bir gigabayt yazın. Peki bu test neyi gösteriyor?

$ ./memtesti
4.06504 GB / sn

Yaklaşık 4 GB/sn.

Ne?!?!

Nasıl?!?!?

Bu Core i7 (en yenisi olmasa da), DDR4, işlemci neredeyse yüklü değil - NEDEN?!?!

Cevap her zaman olduğu gibi alışılmadık derecede sıradan.

New operatörü (bu arada malloc işlevi gibi) aslında bellek ayırmaz. Bu çağrı ile ayırıcı, bellek havuzundaki boş konumların listesine bakar ve eğer yoksa, veri bölümünü artırmak için sbrk()'ı çağırır ve ardından programa, yeni konumdan adrese bir referans döndürür. tahsis edilmiştir.

Sorun, tahsis edilen alanın tamamen sanal olmasıdır. Hiçbir gerçek hafıza sayfası tahsis edilmemiştir.

Ve bu tahsis edilmiş segmentten her sayfaya ilk erişim gerçekleştiğinde, MMU bir sayfa hatası "yatırır" ve ardından erişilen sanal sayfaya gerçek bir sayfa atanır.

Bu nedenle aslında veri yolu ve RAM modüllerinin performansını değil, işletim sisteminin MMU ve VMM performansını test ediyoruz. Ve RAM'in gerçek performansını test etmek için tahsis edilen alanları bir kez başlatmamız yeterli. Örneğin şöyle:

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

Yani, tahsis edilen arabellekleri varsayılan değerle (karakter 0) başlatırız.

Kontrol ediyoruz:

$ ./memtesti
28.5714 GB / sn

Başka bir şey.

Hikayenin ana fikri - hızlı çalışmak için büyük tamponlara ihtiyacınız varsa, bunları başlatmayı unutmayın.

Kaynak: habr.com

Yorum ekle