当前位置: 首页 > 知识库问答 >
问题:

为什么memcpy()的速度每4KB就会急剧下降?

姜嘉良
2023-03-14

测试memcpy()的速度,发现速度在I*4KB时急剧下降。结果表明:Y轴是memcpy()的速度(MB/秒),X轴是memcpy()的缓冲区大小,从1KB增加到2MB。子图2和子图3详细说明了1KB-150KB和1KB-32KB的部分。

环境:

CPU:Intel(R)至强(R)CPU E5620@2.40 GHz

void memcpy_speed(unsigned long buf_size, unsigned long iters){
    struct timeval start,  end;
    unsigned char * pbuff_1;
    unsigned char * pbuff_2;

    pbuff_1 = malloc(buf_size);
    pbuff_2 = malloc(buf_size);

    gettimeofday(&start, NULL);
    for(int i = 0; i < iters; ++i){
        memcpy(pbuff_2, pbuff_1, buf_size);
    }   
    gettimeofday(&end, NULL);
    printf("%5.3f\n", ((buf_size*iters)/(1.024*1.024))/((end.tv_sec - \
    start.tv_sec)*1000*1000+(end.tv_usec - start.tv_usec)));
    free(pbuff_1);
    free(pbuff_2);
}

考虑到@usr、@chrisw和@leeor的建议,我更精确地重做了测试,下图显示了结果。缓冲区大小从26KB到38KB,我每隔64B测试一次(26KB,26KB+64B,26KB+128B,......,38KB)。每次测试循环100,000次,时间约为0.15秒。有趣的是,下降不仅精确地发生在4KB边界上,而且在4*I+2KB边界上出现,下降幅度小得多。

@Leeor提供了一种填充drop的方法,在pbuff_1pbuff_2之间添加了一个2KB的虚拟缓冲区。它起作用了,但我不确定Leeor的解释。

共有1个答案

姬国安
2023-03-14

内存通常以4K的页面组织(尽管也支持更大的页面)。您的程序看到的虚拟地址空间可能是连续的,但在物理内存中不一定是这样。OS维护虚拟地址到物理地址的映射(在页面映射中),通常也会尝试将物理页面保持在一起,但这并不总是可能的,它们可能会被分解(特别是在长时间使用时,它们可能偶尔被交换)。

当内存流跨越4K页边界时,CPU需要停下来获取一个新的翻译--如果它已经看到了页面,它可能被缓存在TLB中,并且访问被优化为最快,但是如果这是第一次访问(或者如果您有太多的页面让TLB无法保持),CPU将不得不暂停内存访问,并在页面映射条目上开始一次页面遍历--这相对较长,因为实际上每个级别都是自己读取的内存(在虚拟机上,它甚至更长,因为每个级别可能需要在主机上进行一次完整的页面遍历)。

您的memcpy函数可能有另一个问题--当第一次分配内存时,OS只会将页面构建到pagemap中,但由于内部优化,将它们标记为未访问和未修改。第一次访问可能不仅调用页面遍历,而且可能还会帮助操作系统使用该页面(并将其存储到目标缓冲区页面),这将需要向某个操作系统处理程序进行昂贵的转换。

当代码访问两个不同的内存位置时,它们之间的偏移量为4Kbyte时,就会发生4Kbyte内存混叠。4Kbyte混叠情况可以在内存复制例程中表现出来,其中源缓冲区和目的缓冲区的地址保持一个恒定偏移量,而该恒定偏移量恰好是从一次迭代到下一次迭代的字节增量的倍数。

...

加载必须等到商店退役后才能继续。例如,在偏移量16,下一个迭代的负载是4Kbyte别名的当前迭代存储,因此循环必须等待到存储操作完成,使整个循环序列化。随着偏移量的增大,等待所需的时间会减少,直到偏移量96解决了问题(因为在加载相同地址时没有挂起的存储)。

 类似资料:
  • 问题内容: 当尝试使用maven构建Web应用程序时,当我的Internet连接处于连接状态时,通常会出现以下错误。 我的问题是,为什么在较早构建同一应用程序时,maven总是每次都要下载。 我的配置每次Maven都要下载时可能出什么毛病? 以下是我尝试离线构建时遇到的错误: 问题答案: 在您的元素(或项目的父级或公司父级POM)中查找该元素。它看起来像下面的样子。 注意元素。该示例告诉Maven

  • 我注意到,如果在ListView中Listitem的TextView中使用android:singleLine=“true”,则滚动会非常缓慢。虽然我找到了另一种android:maxLines=“1”,但我很好奇为什么android:singleLine=“true”会让滚动变得很慢,即使很慢,为什么android仍在使用它?

  • 我编写了一个程序来测试的速度。然而,内存的分配方式对速度有很大的影响。 为什么memcpy()的速度每4KB就会急剧下降? 原因与GCC编译器有关,我用不同版本的GCC编译运行了这个程序: GCC版本------------------------

  • 我们面临的情况是,只要有滞后,我们的akka流kaka消费者处理率就会下降。当我们在分区中没有任何延迟的情况下启动它时,处理速度会突然增加。 MSK群集-10个主题-每个40个分区= 为了在系统中实现高吞吐量和并行性,我们实现了akka-stream-kafka消费者分别订阅每个主题分区,从而在消费者和分区之间实现1:1映射。 这是消费者设置: ec2服务实例数-7 每个服务为10个主题中的每一个

  • 问题内容: 今天,我做了一些快速基准测试来测试and的速度性能: 结果如下: 为什么运行速度差异如此之大? 基准系统: 问题答案: 从这个Oracle博客中: 使用GetSystemTimeAsFileTime方法实现该方法,该方法本质上只是读取Windows维护的低分辨率日期时间值。读取此全局变量自然非常快- 根据报告的信息,大约需要6个周期。 使用 (如果可用,则返回。)实现,具体取决于运行的