خراب جانچ کے بارے میں تھوڑا سا مزید

ایک دن مجھے اتفاقی طور پر کوڈ ملا کہ ایک صارف اپنی ورچوئل مشین میں رام کی کارکردگی کو مانیٹر کرنے کی کوشش کر رہا ہے۔ میں یہ کوڈ نہیں دوں گا (وہاں ایک "پوش" ہے) اور میں صرف سب سے ضروری چیز چھوڑوں گا۔ تو، بلی سٹوڈیو میں ہے!

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

یہ آسان ہے - میموری مختص کریں اور اس میں ایک گیگا بائٹ لکھیں۔ اور یہ ٹیسٹ کیا ظاہر کرتا ہے؟

$ ./memtest
4.06504 GB / s

تقریباً 4GB/s۔

کیا؟!؟!

کیسے؟!؟!؟

یہ کور i7 ہے (حالانکہ تازہ ترین نہیں)، DDR4، پروسیسر تقریباً لوڈ نہیں ہے - کیوں؟!؟!

جواب، ہمیشہ کی طرح، غیر معمولی طور پر عام ہے۔

نیا آپریٹر (جیسے malloc فنکشن، ویسے) دراصل میموری کو مختص نہیں کرتا ہے۔ اس کال کے ساتھ، مختص کرنے والا میموری پول میں مفت جگہوں کی فہرست کو دیکھتا ہے، اور اگر کوئی نہیں ہے، تو ڈیٹا سیگمنٹ کو بڑھانے کے لیے sbrk() کو کال کرتا ہے، اور پھر پروگرام میں واپس نئے مقام سے ایڈریس کا حوالہ دیتا ہے۔ مختص.

مسئلہ یہ ہے کہ مختص کردہ علاقہ مکمل طور پر ورچوئل ہے۔ کوئی حقیقی میموری صفحات مختص نہیں کیے گئے ہیں۔

اور جب اس مختص حصے سے ہر صفحہ تک پہلی رسائی ہوتی ہے، تو MMU صفحہ کی خرابی کو "شوٹ" کرتا ہے، جس کے بعد مجازی صفحہ تک رسائی حاصل کی جاتی ہے جسے حقیقی تفویض کیا جاتا ہے۔

لہذا، حقیقت میں، ہم بس اور RAM ماڈیولز کی کارکردگی نہیں بلکہ آپریٹنگ سسٹم کے MMU اور VMM کی کارکردگی کو جانچ رہے ہیں۔ اور RAM کی حقیقی کارکردگی کو جانچنے کے لیے، ہمیں صرف ایک بار مختص علاقوں کو شروع کرنے کی ضرورت ہے۔ مثال کے طور پر اس طرح:

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

یعنی، ہم صرف طے شدہ قدر (char 0) کے ساتھ مختص کردہ بفرز کو شروع کرتے ہیں۔

جانچ پڑتال:

$ ./memtest
28.5714 GB / s

ایک اور بات۔

کہانی کا اخلاق - اگر آپ کو تیزی سے کام کرنے کے لیے بڑے بفرز کی ضرورت ہے، تو انہیں شروع کرنا نہ بھولیں۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں