对于
int8
、int16
、int32
和int64
类型的std::array
,每增加一倍大小,写入时间就会加倍。我可以理解在8位CPU上的这种行为,但在32/64位上就不应该出现这种情况。为什么32位系统需要4倍的时间来保存32位的值,而保存8位的值只需要1倍的时间呢?
以下是我的测试代码:
#include <iostream>
#include <array>
#include <chrono>
std::array<std::int8_t, 64 * 1024 * 1024> int8Array;
std::array<std::int16_t, 64 * 1024 * 1024> int16Array;
std::array<std::int32_t, 64 * 1024 * 1024> int32Array;
std::array<std::int64_t, 64 * 1024 * 1024> int64Array;
void PutZero()
{
auto point1 = std::chrono::high_resolution_clock::now();
for (auto &v : int8Array) v = 0;
auto point2 = std::chrono::high_resolution_clock::now();
for (auto &v : int16Array) v = 0;
auto point3 = std::chrono::high_resolution_clock::now();
for (auto &v : int32Array) v = 0;
auto point4 = std::chrono::high_resolution_clock::now();
for (auto &v : int64Array) v = 0;
auto point5 = std::chrono::high_resolution_clock::now();
std::cout << "Time of processing int8 array:\t" << (std::chrono::duration_cast<std::chrono::microseconds>(point2 - point1)).count() << "us." << std::endl;
std::cout << "Time of processing int16 array:\t" << (std::chrono::duration_cast<std::chrono::microseconds>(point3 - point2)).count() << "us." << std::endl;
std::cout << "Time of processing int32 array:\t" << (std::chrono::duration_cast<std::chrono::microseconds>(point4 - point3)).count() << "us." << std::endl;
std::cout << "Time of processing int64 array:\t" << (std::chrono::duration_cast<std::chrono::microseconds>(point5 - point4)).count() << "us." << std::endl;
}
int main()
{
PutZero();
std::cout << std::endl << "Press enter to exit" << std::endl;
std::cin.get();
return 0;
}
我使用以下命令在Linux下进行编译:g++ -o array_issue_1 main.cpp -O3 -std=c++14
我的结果如下:
Time of processing int8 array: 9922us.
Time of processing int16 array: 37717us.
Time of processing int32 array: 76064us.
Time of processing int64 array: 146803us.
如果我使用
-O2
编译,那么对于int8
,结果会恶化5倍!你也可以在Windows上编译此源代码。您将获得类似的结果关系。
更新#1
当我使用-O2编译时,我的结果如下:Time of processing int8 array: 60182us.
Time of processing int16 array: 77807us.
Time of processing int32 array: 114204us.
Time of processing int64 array: 186664us.
我没有分析汇编输出。我的主要观点是我想在C++中编写高效的代码,像std::array
这样的东西从性能角度来看可能具有挑战性,并且在某种程度上是违反直觉的。
BYTE
、WORD
、DWORD
和QWORD
写入的成本。结果是,在现代英特尔CPU上,它们都只需要1个周期,除非它们跨越缓存行边界,此时需要2个周期。请注意,如果您在字节粒度位置随机写入数据,则更大的值更有可能跨越缓存行边界。实际上,这个基准测试和大多数代码将使用对齐的缓冲区,因此根本不会发生跨越边界的情况。 - BeeOnRope