C:memcpy的速度上动态分配数组(C: memcpy speed on dynamically

2019-07-31 08:04发布

我需要用下面的代码的性能帮助。 它还对任意大小的两个动态分配的数组a的memcpy:

int main()
{
  double *a, *b;
  unsigned n = 10000000, i;
  a = malloc(n*sizeof(double));
  b = malloc(n*sizeof(double));
  for(i=0; i<n; i++) {
    a[i] = 1.0;
    /* b[i] = 0.0; */
  }

  tic();
  bzero(b, n*sizeof(double));
  toc("bzero1");

  tic();
  bzero(b, n*sizeof(double));
  toc("bzero2");

  tic();
  memcpy(b, a, n*sizeof(double));
  toc("memcpy");
}

TIC / TOC测量的执行时间。

在我的电脑需要0.035s memcpy的(Linux操作系统,gcc版本4.4.6)。 如果我现在取消注释它初始化目标数组b中的行,代码快三倍(!) - 0.011s。

我已经使用循环代替了memcpy时观察到类似的行为。 通常我并不关心这个,因为它是足够使用它之前,“初始化”的记忆。 不过,我现在需要执行一个简单的内存拷贝,并做到这一点尽可能快。 对数据进行初始化需要编写例如0到存储器,这是没有必要的,需要时间。 我愿与所有可用内存带宽进行内存复制。

是否有一个解决这个问题? 或者是它连接到Linux处理动态内存(某种懒页分配?),不能被周围的工作方式? 它是如何在其他系统上?

编辑:同样的结果与GCC 4.6获得。 我用-O3进行编译。

编辑:谢谢大家的意见。 我也明白,内存映射需要时间。 我想我只是有一个很难接受,它需要这么长时间,比实际内存访问更长的时间。 代码已被修改为包括阵列的初始化的基准b。使用两个后续bzero呼叫。 时序现在证明

bzero1 0.273981
bzero2 0.056803
memcpy的0.117934

显然,第一bzero呼叫确实远不止流零记忆-这是内存映射和内存归零。 在另一方面,第二bzero调用需要的做的memcpy所需的时间,而这正是预期的一半 - 只写时间与读写时间。 据我所知,第二bzero调用的开销必须有因OS安全原因。 什么休息? 我不能莫名其妙地减少它,例如使用更大的内存页? 不同的内核设置?

我要指出,我在Ubuntu喘息运行此。

Answer 1:

第一bzero运行较长时间,因为(1)懒惰页分配和(2)懒惰页零初始化内核通过。 而第二个原因是不可避免的,因为安全原因,懒页分配可以通过使用更大的(“庞大”)的网页进行优化。

有使用Linux上的大页面至少有两种方法。 硬的方法是hugetlbfs的 。 简单的方法是透明大内存页 。

搜索khugepaged在你的系统中的进程列表。 如果存在这样的过程,支持透明大内存页,你可以,如果你改变使用它们在应用程序中malloc这样的:

posix_memalign((void **)&b, 2*1024*1024, n*sizeof(double));
madvise((void *)b, n*sizeof(double), MADV_HUGEPAGE);


Answer 2:

这也可能是懒惰的页面分配,仅适用于Linux映射在第一次访问的页面。 IIRC在Linux的新块的每一页是写入时复制一个空白页,而你的分配是大到足以需要新的区块。

如果你想解决它,你可以在4K间隔写一个字节或字。 这可能会映射到内存比写入整个每一页的速度稍快的虚拟地址。

我不希望(最有效的解决方法,以迫使懒惰的内存映射发生)加(复印件)不仅仅是(复印件)未经初始化显著快b ,虽然。 因此,除非有就是为什么你关心的表现只是拷贝一个具体的理由,而不是整个操作的,那么它是相当徒劳的。 它的“现在支付或后付款”,后来的Linux支付,而你只测量时间以后。



Answer 3:

当然,如果你是比较INITIALISE的速度和复制到的只是复制的速度,然后初始化应包括在定时部分。 在我看来,你实际上应该比较如下:

// Version 1
for(i=0; i<n; i++)
    a[i] = 1.0;

tic();

memcpy(b, a, n*sizeof(double));

toc();

为此:

// Version 2
for(i=0; i<n; i++)
    a[i] = 1.0;

tic();

for(i=0; i<n; i++)
    b[i] = 0.0;
memcpy(b, a, n*sizeof(double));

toc();

我希望这会看到你的3倍的速度提升急剧下降。

编辑:正如史蒂夫·杰索普的建议,你可能还需要测试的只有触摸每页一个条目的第三个策略:

// Version 3
for(i=0; i<n; i++)
    a[i] = 1.0;

tic();

for(i=0; i<n; i+=DOUBLES_PER_PAGE)
    b[i] = 0.0;
memcpy(b, a, n*sizeof(double));

toc();


文章来源: C: memcpy speed on dynamically allocated arrays