Memory 使用memset、memcpy测量内存带宽

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

我试图了解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: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的数量级)。