Memory 使用memset、memcpy测量内存带宽
我试图了解memcpy/memset的内存操作性能。我测量包含memset,memcpy的循环所需的时间。请参阅附带的代码(在C++11中,但在纯C中,图片是相同的)。可以理解,memset比memcpy快。但这或多或少是我唯一能理解的。。。最大的问题是: 为什么对循环迭代次数有如此强烈的依赖性? 应用程序是单线程的!CPU是:AMD FX(tm)-4100四核处理器 以下是一些数字:Memory 使用memset、memcpy测量内存带宽,memory,bandwidth,memcpy,measurement,Memory,Bandwidth,Memcpy,Measurement,我试图了解memcpy/memset的内存操作性能。我测量包含memset,memcpy的循环所需的时间。请参阅附带的代码(在C++11中,但在纯C中,图片是相同的)。可以理解,memset比memcpy快。但这或多或少是我唯一能理解的。。。最大的问题是: 为什么对循环迭代次数有如此强烈的依赖性? 应用程序是单线程的!CPU是:AMD FX(tm)-4100四核处理器 以下是一些数字: memset:iters=1 0.0625 GB在0.1269秒内:0.4927 GB每秒 memcpy:i
- memset:iters=1 0.0625 GB在0.1269秒内:0.4927 GB每秒
- memcpy:iters=1 0.0625 GB in 0.1287 s:0.4857 GB/秒
- memset:iters=40.25gb/s,0.151s:1.656gb/s
- memcpy:iters=4 0.25 GB in 0.1678秒:每秒1.49 GB
- memset:iters=16.1gb/s 0.2406s:4.156gb/s
- memcpy:iters=16.1 GB in 0.3184秒:每秒3.14 GB
- memset:iters=128 8 GB in 1.074 s:7.447 GB/秒
- memcpy:iters=1288gb/s,1.737s:4.606gb/s
/*
-- Compilation and run:
g++ -O3 -std=c++11 -o mem-speed mem-speed.cc && ./mem-speed
-- Output example:
*/
#include <cstdio>
#include <chrono>
#include <memory>
#include <string.h>
using namespace std;
const uint64_t _KB=1024, _MB=_KB*_KB, _GB=_KB*_KB*_KB;
std::pair<double,char> measure_memory_speed(uint64_t buf_size,int n_iters)
{
// without returning something from the buffers, the compiler will optimize memset() and memcpy() calls
char retval=0;
unique_ptr<char[]> buf1(new char[buf_size]), buf2(new char[buf_size]);
auto time_start = chrono::high_resolution_clock::now();
for( int i=0; i<n_iters; i++ )
{
memset(buf1.get(),123,buf_size);
retval += buf1[0];
}
auto t1 = chrono::duration_cast<std::chrono::nanoseconds>(chrono::high_resolution_clock::now() - time_start);
time_start = chrono::high_resolution_clock::now();
for( int i=0; i<n_iters; i++ )
{
memcpy(buf2.get(),buf1.get(),buf_size);
retval += buf2[0];
}
auto t2 = chrono::duration_cast<std::chrono::nanoseconds>(chrono::high_resolution_clock::now() - time_start);
printf("memset: iters=%d %g GB in %8.4g s : %8.4g GB per second\n",
n_iters,n_iters*buf_size/double(_GB),(double)t1.count()/1e9, n_iters*buf_size/double(_GB) / (t1.count()/1e9) );
printf("memcpy: iters=%d %g GB in %8.4g s : %8.4g GB per second\n",
n_iters,n_iters*buf_size/double(_GB),(double)t2.count()/1e9, n_iters*buf_size/double(_GB) / (t2.count()/1e9) );
printf("\n");
double avr = n_iters*buf_size/_GB * (1e9/t1.count()+1e9/t2.count()) / 2;
retval += buf1[0]+buf2[0];
return std::pair<double,char>(avr,retval);
}
int main(int argc,const char **argv)
{
uint64_t n=64;
if( argc==2 )
n = atoi(argv[1]);
for( int i=0; i<=10; i++ )
measure_memory_speed(n*_MB,1<<i);
return 0;
}
/*
--编译和运行:
g++-O3-std=c++11-o mem speed mem-speed.cc&&./mem speed
--输出示例:
*/
#包括
#包括
#包括
#包括
使用名称空间std;
常数64_t_KB=1024,_MB=_KB*_KB,_GB=_KB*_KB*_KB;
标准:对测量内存速度(uint64大小,整数)
{
//在不从缓冲区返回任何内容的情况下,编译器将优化memset()和memcpy()调用
char-retval=0;
唯一字符ptr buf1(新字符[buf_大小]),buf2(新字符[buf_大小]);
自动计时\u开始=计时::高分辨率\u时钟::现在();
对于(int i=0;i这肯定是由于指令缓存的加载——因此,代码在第一次迭代后运行得更快,数据缓存加快了对memcpy/memcmp的访问,以便进一步迭代。缓存内存位于处理器内部,因此它不必经常提取数据或将数据放入较慢的外部内存——因此运行得更快。好的观点(我错过了)。事实上,一旦我将缓冲区分配移动到循环中,所有传输速率都会下降到0.5 GB/s+/-10%。但这太慢了,不是吗?如果你有一个现代处理器,你可能会尝试自己实现memcpy。看看,标准实现可能没有使用这些技巧。如果你将分配移动到循环中,现在你可以我们也在测量分配时间,所以我不确定这些数字是否有用。此外,我不认为数据缓存正在加速对memcpy的访问。我们谈论的是1GB的数据,远大于处理器缓存(10MB的数量级)。