C ++ STD :: Vector使用模板化函数运行异常很长时间

时间:2009-07-02 15:43:56

标签: c++ templates stl performance

以下函数使用T的两个值进行操作。一个是4个字节(与DWORD相同)。另一个是64字节。缓冲区用于在缓存中存储对象,并在以后检索它们。

使用64字节结构时,函数中的总时间会急剧增加。向量中的搜索时间,memcpy甚至是函数“SELF”部分的时间都会急剧上升。

存储函数几乎与下面的代码相反,并且似乎没有遭受相同的非对称时序。

关于为什么的任何想法?

template <class T>
void Buffer::retrieve ( T& Value )
   {
   int nTypeSize  = sizeof ( T );
   int nDWORDSize = sizeof ( DWORD );

   /*
    * Number of DWORDs needed to store this value.
    */

   int nDWORDCount = ( nTypeSize + 3 ) / 4;

   if ( m_nReadPosition + nDWORDCount >= m_nSize )
      return;

   memcpy ( &Value, &m_Cache[m_nReadPosition], nTypeSize );  //m_Cache is a DWORD vector.
   m_nReadPosition += nDWORDCount;
   }

3 个答案:

答案 0 :(得分:1)

memcpy时间增加可能只是复制更多字节,因为memcpy时间会随着复制的内存量而缩小(天真)。它不一定是线性缩放,因为memcpy的某些实现将通过一次复制32位或64位来优化。

std :: vector中的查找不应该使用对象大小进行缩放,因为m_nReadPosition或m_Cache都不依赖于T.

对于操作T的任何代码,你会有一些减速,因为4字节结构可以存储在32位处理器的寄存器中,而更大的代码对于编译器来说更复杂。这可能会增加一些开销。

总时间增加了多少?如果它是16的倍数,我会把它简单地归结为T的大小变化。

答案 1 :(得分:1)

如果您有std::vector,为什么使用memcpy?我建议使用std::copystd::vector自己的方法。它在很大程度上是一种风格上的变化,但确实可以保证构造者被调用。

至于为什么事情进展缓慢,我不确定:

  
      
  • 向量中的搜索时间,
  •   

这很奇怪,因为向量指向连续的内存,并且内存的寻道时间是不变的。也就是说,如果我指向向量中的第一个项目,则从第二个项目移动第二个项目将花费与从其移动到最后一个项目(通过++=std::advance)。

如果您使用std::list,则会显示寻找时间。但它不应该在矢量中。绝对不应该在memcpy操作向量的原始内存。

  
      
  • memcpy
  •   

您复制的数据是16倍(4个字节,64个字节)。

  
      
  • 甚至该功能的“SELF”部分的时间都大幅上升。
  •   

这也很奇怪,如

int nTypeSize  = sizeof ( T );
int nDWORDSize = sizeof ( DWORD );
int nDWORDCount = ( nTypeSize + 3 ) / 4;

都是编译时常量,应由编译器为每种类型T预先计算。

if ( m_nReadPosition + nDWORDCount >= m_nSize )

m_nReadPosition += nDWORDCount;

Buffer::retrieve中唯一在运行时实际执行的行(memcpy除外)。除非这种增加只是由于重复计算memcpy(一次在“memcpy”标题下,一次在“Buffer::retrieve”标题下。


std::vector中要注意的事情是零碎的内存分配和不需要的副本。但是,您在示例代码中没有做任何事情。

答案 2 :(得分:0)

我怀疑分析器将时间归因于从这里调用的函数:std::vector的访问器是内联的,memcpy()可能是编译器内在的,这意味着优化的发布版本(你 计划发布版本,对吗?)他们的大部分工作将归因于调用函数。

所以考虑到我会运行一些受控实验来本地化减速。例如,这里大部分CPU时间最可能的罪魁祸首是memcpy(),所以请暂时将其从等式中取出:

volatile DWORD g_dummy;
void Buffer::retrieve ( T& Value )
   {
   /* ... */
   // memcpy ( &Value, &m_Cache[m_nReadPosition], nTypeSize );  
   g_dummy += m_Cache[m_nReadPosition]; // force the compiler to perform the vector lookup
   m_nReadPosition += nDWORDCount;
   }

并查看该副本真正考虑的减速程度。