Chúng tôi có một cuộc thảo luận tương tự về tuple và struct và tôi viết một số điểm chuẩn đơn giản với sự giúp đỡ từ một đồng nghiệp của tôi để xác định sự khác biệt về hiệu suất giữa tuple và struct. Đầu tiên chúng ta bắt đầu với một cấu trúc mặc định và một bộ tuple.
struct StructData {
int X;
int Y;
double Cost;
std::string Label;
bool operator==(const StructData &rhs) {
return std::tie(X,Y,Cost, Label) == std::tie(rhs.X, rhs.Y, rhs.Cost, rhs.Label);
}
bool operator<(const StructData &rhs) {
return X < rhs.X || (X == rhs.X && (Y < rhs.Y || (Y == rhs.Y && (Cost < rhs.Cost || (Cost == rhs.Cost && Label < rhs.Label)))));
}
};
using TupleData = std::tuple<int, int, double, std::string>;
Sau đó, chúng tôi sử dụng Celero để so sánh hiệu suất của cấu trúc và tuple đơn giản của chúng tôi. Dưới đây là mã điểm chuẩn và kết quả hiệu suất được thu thập bằng cách sử dụng gcc-4.9.2 và clang-4.0.0:
std::vector<StructData> test_struct_data(const size_t N) {
std::vector<StructData> data(N);
std::transform(data.begin(), data.end(), data.begin(), [N](auto item) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, N);
item.X = dis(gen);
item.Y = dis(gen);
item.Cost = item.X * item.Y;
item.Label = std::to_string(item.Cost);
return item;
});
return data;
}
std::vector<TupleData> test_tuple_data(const std::vector<StructData> &input) {
std::vector<TupleData> data(input.size());
std::transform(input.cbegin(), input.cend(), data.begin(),
[](auto item) { return std::tie(item.X, item.Y, item.Cost, item.Label); });
return data;
}
constexpr int NumberOfSamples = 10;
constexpr int NumberOfIterations = 5;
constexpr size_t N = 1000000;
auto const sdata = test_struct_data(N);
auto const tdata = test_tuple_data(sdata);
CELERO_MAIN
BASELINE(Sort, struct, NumberOfSamples, NumberOfIterations) {
std::vector<StructData> data(sdata.begin(), sdata.end());
std::sort(data.begin(), data.end());
}
BENCHMARK(Sort, tuple, NumberOfSamples, NumberOfIterations) {
std::vector<TupleData> data(tdata.begin(), tdata.end());
std::sort(data.begin(), data.end());
}
Kết quả hiệu suất được thu thập với clang-4.0.0
Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec |
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort | struct | Null | 10 | 5 | 1.00000 | 196663.40000 | 5.08 |
Sort | tuple | Null | 10 | 5 | 0.92471 | 181857.20000 | 5.50 |
Complete.
Và kết quả hiệu suất được thu thập bằng cách sử dụng gcc-4.9.2
Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec |
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort | struct | Null | 10 | 5 | 1.00000 | 219096.00000 | 4.56 |
Sort | tuple | Null | 10 | 5 | 0.91463 | 200391.80000 | 4.99 |
Complete.
Từ kết quả trên chúng ta có thể thấy rõ rằng
Tất cả chúng ta đều biết rằng viết toán tử == hoặc <hoặc> cho mỗi định nghĩa cấu trúc đơn lẻ sẽ là một nhiệm vụ khó khăn và nhiều lỗi. Hãy thay thế bộ so sánh tùy chỉnh của chúng tôi bằng cách sử dụng std :: tie và chạy lại điểm chuẩn của chúng tôi.
bool operator<(const StructData &rhs) {
return std::tie(X,Y,Cost, Label) < std::tie(rhs.X, rhs.Y, rhs.Cost, rhs.Label);
}
Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec |
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort | struct | Null | 10 | 5 | 1.00000 | 200508.20000 | 4.99 |
Sort | tuple | Null | 10 | 5 | 0.90033 | 180523.80000 | 5.54 |
Complete.
Bây giờ chúng ta có thể thấy rằng việc sử dụng std :: tie làm cho mã của chúng ta thanh lịch hơn và khó mắc lỗi hơn, tuy nhiên, chúng ta sẽ giảm hiệu suất khoảng 1%. Tôi sẽ ở lại với giải pháp std :: tie ngay bây giờ vì tôi cũng nhận được cảnh báo về việc so sánh các số dấu phẩy động với trình so sánh tùy chỉnh.
Cho đến nay chúng tôi vẫn chưa có bất kỳ giải pháp nào để làm cho mã cấu trúc của chúng tôi chạy nhanh hơn. Hãy xem qua hàm hoán đổi và viết lại nó để xem liệu chúng ta có thể đạt được bất kỳ hiệu suất nào không:
struct StructData {
int X;
int Y;
double Cost;
std::string Label;
bool operator==(const StructData &rhs) {
return std::tie(X,Y,Cost, Label) == std::tie(rhs.X, rhs.Y, rhs.Cost, rhs.Label);
}
void swap(StructData & other)
{
std::swap(X, other.X);
std::swap(Y, other.Y);
std::swap(Cost, other.Cost);
std::swap(Label, other.Label);
}
bool operator<(const StructData &rhs) {
return std::tie(X,Y,Cost, Label) < std::tie(rhs.X, rhs.Y, rhs.Cost, rhs.Label);
}
};
Kết quả hiệu suất được thu thập bằng cách sử dụng clang-4.0.0
Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec |
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort | struct | Null | 10 | 5 | 1.00000 | 176308.80000 | 5.67 |
Sort | tuple | Null | 10 | 5 | 1.02699 | 181067.60000 | 5.52 |
Complete.
Và kết quả hiệu suất được thu thập bằng cách sử dụng gcc-4.9.2
Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec |
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort | struct | Null | 10 | 5 | 1.00000 | 198844.80000 | 5.03 |
Sort | tuple | Null | 10 | 5 | 1.00601 | 200039.80000 | 5.00 |
Complete.
Bây giờ cấu trúc của chúng tôi nhanh hơn một chút so với một tuple bây giờ (khoảng 3% với clang và ít hơn 1% với gcc), tuy nhiên, chúng tôi cần viết hàm hoán đổi tùy chỉnh cho tất cả các cấu trúc của chúng tôi.
tuple
khai thực hiện được xác định, do đó nó phụ thuộc vào việc triển khai của bạn. Cá nhân, tôi sẽ không tin tưởng vào nó.