有关不正确测试的更多信息

有一天,我不小心注意到了一个代码,该代码是用户试图监视其虚拟机中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/s\n";
	for (int i=0;i<CNT;i++) {
		delete buffers[i];
	}
	delete buffers;
	return 0;
}

一切都很简单-我们分配内存并向其中写入1 GB。这项测试显示了什么?

$ ./memtest
4.06504 GB /秒


约4GB /秒

什么?!?!

怎么样?!?!?

这是Core i7(虽然不是最新的)DDR4,但处理器几乎未加载-为什么?!?!

一如既往,答案很普通。

new运算符(顺便说一句,类似于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/s\n";
	for (int i=0;i<CNT;i++) {
		delete buffers[i];
	}
	delete buffers;
	return 0;
}

也就是说,我们只需使用默认值(字符0)初始化分配的缓冲区即可。

检查:

$ ./memtest
28.5714 GB /秒


另一件事。

道德-如果您需要大的缓冲区才能快速工作,请不要忘记初始化它们。

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


All Articles