【发布时间】:2016-08-19 20:24:54
【问题描述】:
以下是我认为是事实的事情:
- 快速排序应该对缓存非常友好。
- 一个 64 字节的高速缓存行可以包含 16 个 32 位整数或 8 个 64 位整数。
假设:
- 对 32 位整数向量进行排序应该比对 64 位整数向量。
但是当我运行下面的代码时,我得到了结果:
i16 = 7.5168
i32 = 7.3762
i64 = 7.5758
为什么我没有得到我想要的结果?
C++:
#include <iostream>
#include <vector>
#include <cstdint>
#include <algorithm>
#include <chrono>
int main() {
const int vlength = 100'000'000;
const int maxI = 50'000;
std::vector<int16_t> v16;
for (int i = 0; i < vlength; ++i) {
v16.push_back(int16_t(i%maxI));
}
std::random_shuffle(std::begin(v16), std::end(v16));
std::vector<int32_t> v32;
std::vector<int64_t> v64;
for (int i = 0; i < vlength; ++i) {
v32.push_back(int32_t(v16[i]));
v64.push_back(int64_t(v16[i]));
}
auto t1 = std::chrono::high_resolution_clock::now();
std::sort(std::begin(v16), std::end(v16));
auto t2 = std::chrono::high_resolution_clock::now();
std :: cout << "i16 = " << (std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1)).count() << std :: endl;
t1 = std::chrono::high_resolution_clock::now();
std::sort(std::begin(v32), std::end(v32));
t2 = std::chrono::high_resolution_clock::now();
std :: cout << "i32 = " << (std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1)).count() << std :: endl;
t1 = std::chrono::high_resolution_clock::now();
std::sort(std::begin(v64), std::end(v64));
t2 = std::chrono::high_resolution_clock::now();
std :: cout << "i64 = " << (std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1)).count() << std :: endl;
}
编辑: 为了避免缓存友好排序的问题,我还尝试了以下代码:
template <typename T>
inline void function_speed(T& vec) {
for (auto& i : vec) {
++i;
}
}
int main() {
const int nIter = 1000;
std::vector<int16_t> v16(1000000);
std::vector<int32_t> v32(1000000);
std::vector<int64_t> v64(1000000);
auto t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < nIter; ++i) {
function_speed(v16);
}
auto t2 = std::chrono::high_resolution_clock::now();
std :: cout << "i16 = " << (std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1)).count()/double(nIter) << std :: endl;
t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < nIter; ++i) {
function_speed(v32);
}
t2 = std::chrono::high_resolution_clock::now();
std :: cout << "i32 = " << (std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1)).count()/double(nIter) << std :: endl;
t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < nIter; ++i) {
function_speed(v64);
}
t2 = std::chrono::high_resolution_clock::now();
std :: cout << "i64 = " << (std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1)).count()/double(nIter) << std :: endl;
}
典型结果:
i16 = 0.00618648
i32 = 0.00617911
i64 = 0.00606275
我知道正确的基准测试本身就是一门科学,也许我做错了。
EDIT2: 通过避免溢出,我现在开始得到更有趣的结果:
template <typename T>
inline void function_speed(T& vec) {
for (auto& i : vec) {
++i;
i %= 1000;
}
}
给出如下结果:
i16 = 0.0143789
i32 = 0.00958941
i64 = 0.019691
如果我这样做:
template <typename T>
inline void function_speed(T& vec) {
for (auto& i : vec) {
i = (i+1)%1000;
}
}
我明白了:
i16 = 0.00939448
i32 = 0.00913768
i64 = 0.019615
【问题讨论】:
-
7.5,是秒吗?还是毫秒?
-
您期望哪个差异(因素)?
-
@Jean-FrançoisFabre:秒。
-
@Jarod42:我不确定我预期的差异有多大,但至少有些明显。
-
顺便说一下,当您尝试将数字
>= 32768存储在 16 位有符号整数中时会溢出。但这不应该改变任何基准,因为溢出的值会按原样复制到其他向量。