C ++,加载数据的延迟从内存到缓存的结构

时间:2011-02-19 21:51:20

标签: c++ memory-management

我在C ++中有以下功能

int readData ( Class1 *data)  
{    
//StartTime     
   try{  
       char *a1 = data->name1;  
       int a2 = data->age1;     

        char *b1 = data->name1;
        int b2 = data->age1; 
        .
        .
        . 
        char *e1 = data->name5;
        int e2 = data->age5;
   }
   catch(...)
   {
        return -1;
   } 
  //endTime
        return 0;
}

有一种模式

我第一次调用此函数需要9 - 10microsec才能返回 我称这个函数第二次需要1 - 2microsec,这样第二次调用就是500毫秒的第一次调用

我第3次调用此函数需要9 - 10microsec,这样第3次调用是在第3次调用后的2-3秒之后

请问你为什么在2到3秒后打电话需要这么多时间?什么是这个问题的解决方案,所以它总是需要1 - 2微秒。

注意:我已将标签放在测量时间的位置。我正在使用cputicks所以我确信时间档案是正确的。

谢谢,

Ila Agarwal

3 个答案:

答案 0 :(得分:0)

仅从您的描述中,我不会100%确定它实际上与缓存相关。这些是确定这一点的一些问题。

  • 您正在阅读多少数据?
  • 什么是数据布局(即如何在内存中分配数据?)
  • 你有什么CPU?
  • 您使用的编译器/优化是什么?
  • 是否正在运行其他进程/线程?
  • 您的应用程序使用多少内存,甚至可能开始交换(使用的内存多于可用内存)
  • 您使用的是哪种操作系统?对于Linux,您可以使用PAPI读取CPU内部计数器,告诉您有关缓存未命中等的信息。
  • 在第2次和第3次通话之间的2s期间发生了什么。

但我们现在假设这与缓存有关,最初数据在主内存中。

第一次执行该功能时,CPU必须从内存中取出它到L2 / L1 DCache。

现在,如果你'快速'再次调用该函数,可以从CPU-Cache中检索数据,这比访问主存储器花费的时间少得多。

在通过其他代码运行的两秒钟内,包括操作系统,这个其他代码将访问内存中的不同数据 - 这将覆盖以前存储在缓存中的数据。

因此,第三次执行将再次变慢。

然而,填充缓存的10ms对我来说显得很长,我怀疑内存访问模式非常糟糕,并且您没有有效地使用可用带宽来主内存。优化代码以实现良好的缓存访问是一个复杂的主题。有许多技巧来优化内存访问模式,其中大部分是由编译器和CPU自己完成的。您可以控制的重点是内存中的数据布局,内存访问模式/循环,编译器标志(和选择)。如果您提供有关代码的更多信息,我们可能会对此有所帮助。

答案 1 :(得分:0)

你的电话之间发生了什么?最明显的是CPU L1,L2缓存充满了其他数据,因为你几秒钟没有做任何事情。当您再次访问存储器位置时,必须再次从主存储器加载数据,这要慢得多。 C ++没有GC或类似的东西,所以你和机器之间没有任何东西。只有操作系统和硬件。 当您的代码和数据进入页面文件时,您应该检查午餐后再次测量所需的时间。然后,第一次通话的速度会慢1000倍。

此致,   Alois Kraus

答案 2 :(得分:0)

略微复制其他答案,但您所看到的是预期的:

  • 缓存未命中。点击次数越长,您的代码和/或数据就越有可能从L1,L2和L3(如果有的话)缓存中消失。
  • 在缓存之上,有TLB未命中(MMU)。在这里走路通常有2-3级间接,这是一个巨大的延迟。
  • 然后就是DDR作为最后的手段,与CPU时钟相比,这是一个巨大的延迟。
  • 您可能已启用节电方案,这意味着在空闲2-3秒后,它会在唤醒后以减少的时钟运行一段时间。因此,你会在一段时间内慢慢运行。
  • DDR还具有强大的省电模式,可以在闲置/睡眠时产生更多的周期惩罚。

如何解决这个问题?这非常困难:

  • TLB锁定。对硬件TLB进行编程,以保留您将要访问的代码和数据的条目。这会降低其他所有内容的TLB效率
  • 缓存锁定。为代码和数据保留一种或多种方式。这会减少其他所有内容的缓存的有效大小
  • 请勿使用省电功能。这对所有其他用例都不利。

换句话说,。你需要围绕最糟糕的情况进行设计,而不是试图做出最好的情况。绝对没有办法在现代操作系统上在x86上安排上述内容。您可能需要付出一些努力才能在Linux中使用ARM。但这不是一个明智的做法。如果你真的需要微秒的响应时间,你需要一个专用的硬件,或者一个micro(例如基于ARM)只做那个任务。如果这是一个多用户操作系统,你基本上没有保证,我会很高兴甚至得到10usec延迟。另一方面,如果您实际上已经在micro上执行此操作,那么无论如何都要执行TLB / Cache锁定方法:)