เพิ่มเติมเล็กน้อยเกี่ยวกับการทดสอบที่ไม่ดี

วันหนึ่งฉันบังเอิญเจอโค้ดที่ผู้ใช้พยายามตรวจสอบประสิทธิภาพ 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++) {
		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/วินาที

อะไร?!?!

ยังไง?!?!?

นี่คือ Core 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;
}

นั่นคือเราเพียงเริ่มต้นบัฟเฟอร์ที่จัดสรรด้วยค่าเริ่มต้น (อักขระ 0)

เราตรวจสอบ:

$ ./memtest
28.5714 GB / s

อีกสิ่งหนึ่งที่.

คติประจำใจของเรื่องราว - หากคุณต้องการบัฟเฟอร์ขนาดใหญ่เพื่อให้ทำงานได้อย่างรวดเร็ว อย่าลืมเริ่มต้นใช้งานบัฟเฟอร์เหล่านั้น

ที่มา: will.com

เพิ่มความคิดเห็น