我正在用 C++ 编写简单的基准测试来比较不同平台上数据访问的执行时间。
我得到了奇怪的结果。我测量顺序顺序访问和间接顺序访问的时间。为此,我只是以两种不同的方式将一个数组数据复制到另一个数组数据。代码和结果如下。
我得到的时间是模棱两可的。对 int 数据类型的评估表明,顺序访问速度更快(没问题)。但对于 float 和 double 类型来说恰恰相反(见下面的时间结果)。也许我做的基准测试是错误的,或者有一些我没有考虑到的陷阱?或者您能否推荐一些基准工具来比较不同数据类型的数据访问或简单操作性能?
template<typename T>
std::chrono::nanoseconds::rep PerformanceMeter<T>::testDataAccessArr()
{
std::chrono::nanoseconds::rep totalSequential = 0;
T* arrDataIn = new T[k_SIZE];
T* arrDataOut = new T[k_SIZE];
std::generate_n(arrDataIn, k_SIZE, DataProcess<T>::valueGenerator);
DataProcess<T>::clearCache();
std::chrono::nanoseconds::rep timeSequential = measure::ns(copySequentialArr, arrDataIn, arrDataOut, k_SIZE);
std::cout << "Sequential order access:\t" << timePrint(timeSequential) << "\t";
std::cout.flush();
std::chrono::nanoseconds::rep totalIndirection = 0;
T** pointers = new T*[k_SIZE];
T** pointersOut = new T*[k_SIZE];
for (size_t i = 0; i < k_SIZE; ++i)
{
pointers[i] = &arrDataIn[i];
pointersOut[i] = &arrDataOut[i];
}
std::generate_n(arrDataIn, k_SIZE, DataProcess<T>::valueGenerator);
std::generate_n(arrDataOut, k_SIZE, DataProcess<T>::valueGenerator);
DataProcess<T>::clearCache();
totalIndirection = measure::ns(copyIndirectionArr, pointers, pointersOut, k_SIZE);
std::cout << std::endl << "Indirection order access:\t" << timePrint(totalIndirection) << std::endl;
std::cout.flush();
delete[] arrDataIn;
delete[] arrDataOut;
delete[] pointers;
delete[] pointersOut;
return timeSequential;
}
template <typename T>
void PerformanceMeter<T>::copySequentialArr(const T* dataIn, T* dataOut, size_t dataSize)
{
for (int i = 0; i < dataSize; i++)
dataOut[i] = dataIn[i];
}
template <typename T>
void PerformanceMeter<T>::copyIndirectionArr(T** dataIn, T** dataOut, size_t dataSize)
{
for (int i = 0; i < dataSize; i++)
*dataOut[i] = *dataIn[i];
}
结果:
--------------------测量整数----------------
数据:10MB;迭代次数:1
顺序访问:8.50454ms
间接顺序访问:11.6925ms
--------------------测量 float ------------
数据:10MB;迭代次数:1
顺序访问:8.84023ms
间接顺序访问:8.53148ms
--------------------测量双------------
数据:10MB;迭代次数:1
顺序访问:5.57747ms
间接顺序访问:3.72843ms
最佳答案
以下是 GCC 6.3 使用 -O2
的汇编输出示例(使用 T = int
):
copySequentialArr
和 copyIndirectionArr
.
从程序集可以明显看出它们非常相似,但是 copyIndirectionArr
比 copySequentialArr
需要两条 mov
指令。由此我们可以得出一些结论,copySequentialArr
是最快的。
使用 T = double
时也是如此:copySequentialArr
和 copyIndirectionArr
.
矢量化
当我们开始使用 -O3
时变得很有趣:copySequentialArr
和 copyIndirectionArr
.
copyIndirectionArr
没有变化,但 copySequentialArr
现在由编译器矢量化。在正常情况下,这种矢量化将使它比以前更快。
免责声明
这些对生成的汇编代码的检查是“脱离上下文”的,因为如果编译器知道上下文,它会进一步优化它。
关于C++ 数据访问基准,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44068981/