TL;DR VS2013 的优化器是否混淆了,或者我的测量结果是否错误,或者全局虚拟对象实际上是否需要易失性才能使测试有效或____?
免责声明:这主要是出于“学术”兴趣,我不认为我看到的差异会真正影响任何生产代码。
简介:我最近的一些测量结果让我想到了这个问题,因为我看到了 VS2013之间std::vector<std::unique_ptr<T> >
的显着差异。boost::ptr_vector
(另见那里的评论)
对于我的特定测试用例,访问 boost::ptr_vector 中的元素似乎比使用 unique_ptr 的向量快 50%!
我的测试代码在这里:http ://coliru.stacked-crooked.com/a/27dc2f1b91380cca (我将避免在这个问题中也包括它,我将在下面包含片段)
gcc 4.8 没有报告任何差异,所以这是 VS2013 的事情。
Start... The timings are as follows for accessing all (1000000) elements 200 times: * St6vectorISt10unique_ptrIjSt14default_deleteIjEESaIS3_EE: 1764 ms * N5boost10ptr_vectorIjNS_20heap_clone_allocatorESaIPvEEE: 1781 ms Dummy output: 500000
我对链接到的测试代码的确切时间是:
Start... The timings are as follows for accessing all (1.000.000) elements 200 times: * class std::vector<....>: 344 ms * class boost::ptr_vector<unsigned int,....>: 216 ms Dummy output: 500.000
测试循环看起来像这样,我还将在那里保留冗长的注释来解释我所看到的:
template<typename C>
void RunContainerAccess(C& c) {
for (size_t i = 0; i != loop_count; ++i) {
for (auto& e : c) {
// This is relevant:
// If the if-condition is present, VC++2013 will show
// approx. the same runtime for both cases. However,
// if the only line in this loop is assigning the element
// to the pGlobalDummy, *then* ptr_vector will run approx. 50%
// faster than the unique_vector version!
//
// g++-4.8 does not show this behaviour
//
// Note: VS2013 commmand line: (release; /O2; no whole prg opt)
// /GS /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"Release\vc120.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\simple.pch"
//
// Note: http://coliru.stacked-crooked.com/ command line:
// g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
// if (pGlobalDummy)
pGlobalDummy = PtrShim(e);
}
}
}
如果循环中唯一的一行是访问元素(将 ptr 放入全局虚拟对象中),那么 VS2013 优化器似乎做了一些奇怪的事情。当if (pGlobalDummy)
存在时,两种情况都是相同的。
任何人都可以分享一些关于这一点的信息吗?
感谢霍华德的回答,我确实发现添加volatile
到全局虚拟会有所不同,即当全局虚拟像这样不稳定时:
extern MyType* volatile pGlobalDummy;
MyType* volatile pGlobalDummy = nullptr;
循环运行速度稍慢,但运行完全相同。volatile 应该在这里有所作为吗?也就是说,如果没有 volatile,测试是否有效?