Tuple ve struct hakkında benzer bir tartışmamız var ve tuple ve struct arasındaki performans açısından farklılıkları belirlemek için meslektaşlarımdan birinin yardımıyla bazı basit kıyaslamalar yazıyorum. Önce varsayılan bir yapı ve bir demet ile başlarız.
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>;
Daha sonra basit yapımızın ve demetimizin performansını karşılaştırmak için Celero'yu kullanıyoruz. Gcc-4.9.2 ve clang-4.0.0 kullanılarak toplanan karşılaştırma kodu ve performans sonuçları aşağıdadır:
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());
}
Clang-4.0.0 ile toplanan performans sonuçları
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.
Gcc-4.9.2 kullanılarak toplanan performans sonuçları
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.
Yukarıdaki sonuçlardan şunu açıkça görebiliriz:
Tuple, varsayılan bir yapıdan daha hızlıdır
Clang tarafından ikili üretim, gcc'den daha yüksek performansa sahiptir. clang-vs-gcc bu tartışmanın amacı değil, bu yüzden ayrıntılara girmeyeceğim.
Her bir yapı tanımı için bir == veya <veya> operatörü yazmanın zahmetli ve hatalı bir iş olacağını hepimiz biliyoruz. Özel karşılaştırıcımızı std :: tie kullanarak değiştirelim ve kıyaslamamızı yeniden çalıştıralım.
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.
Şimdi std :: tie kullanmanın kodumuzu daha zarif hale getirdiğini ve hata yapmanın daha zor olduğunu görebiliriz, ancak yaklaşık% 1 performans kaybedeceğiz. Kayan nokta sayılarını özelleştirilmiş karşılaştırıcıyla karşılaştırmakla ilgili bir uyarı aldığım için şimdilik std :: tie çözümünü kullanmaya devam edeceğim.
Şimdiye kadar, struct kodumuzu daha hızlı çalıştıracak herhangi bir çözümümüz yok. Takas işlevine bir göz atalım ve herhangi bir performans kazanıp kazanamayacağımızı görmek için yeniden yazalım:
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);
}
};
Clang-4.0.0 kullanılarak toplanan performans sonuçları
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.
Ve gcc-4.9.2 kullanılarak toplanan performans sonuçları
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.
Artık yapımız şu anda bir demetinkinden biraz daha hızlı (clang ile yaklaşık% 3 ve gcc ile% 1'den az), ancak, tüm yapılarımız için özelleştirilmiş takas işlevimizi yazmamız gerekiyor.
tuple
is uygulamasının uygulanması tanımlanmıştır, bu nedenle sizin uygulamanıza bağlıdır. Kişisel olarak, ben ederim değil üzerinde sayılmaz.