以下函数使用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;
}
答案 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::copy
或std::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;
}
并查看该副本真正考虑的减速程度。