比较四种ordered set的性能

标准库提供了有序的std::set,abseil中新增了btree_set,folly中新增了两种有序set,sorted_vector_set和heap_vector_set。我们比较下它们的查找和插入的性能。

benchmark代码:

#include <vector>
#include <folly/Benchmark.h>
#include <vector>
#include <set>
#include <folly/sorted_vector_types.h>
#include <folly/container/heap_vector_types.h>
#include <folly/Random.h>
#include <absl/container/btree_set.h>
static inline constexpr int N = 1000000;
BENCHMARK_DRAW_LINE();
template<class T>
void ordered_search(unsigned int n)
{
  folly::BenchmarkSuspender       s;
  folly::Random::DefaultGenerator rng;
  rng.seed(0xdeadbeaf);
  std::vector<int> v(N);
  std::iota(v.begin(), v.end(), 0);
  T m;
  m.insert(v.begin(), v.end());
  auto it = m.begin();
  s.dismiss();
  for (int i = 0; i < n; ++i) {
    it = m.find(folly::Random::rand32(0, N));
  }
  folly::doNotOptimizeAway(it);
}
BENCHMARK(set_search, n)
{ ordered_search<std::set<int>>(n); }
BENCHMARK_RELATIVE(btree_set_search, n)
{ordered_search < absl::btree_set<int>>(n);
}
BENCHMARK_RELATIVE (sorted_vector_set_search, n)
{ordered_search<folly::sorted_vector_set<int>>(n);}
BENCHMARK_RELATIVE (heap_vector_set_search, n)
{ordered_search<folly::heap_vector_set<int>>(n);}
BENCHMARK_DRAW_LINE();
template<class T, bool sorted_unique =false >
void ordered_insert()
{
  folly::BenchmarkSuspender s;
  std::vector<int>          v(N);
  std::iota(v.begin(), v.end(), 0);
  T m;
  s.dismiss();
  m.insert(v.begin(), v.end());
  if constexpr (sorted_unique)
  {
    m.insert(folly::sorted_unique,v.begin(), v.end());
  } else {
    m.insert(v.begin(), v.end());
  }
  folly::doNotOptimizeAway(m);
}
BENCHMARK(set_insert )
{ ordered_insert<std::set<int>>(); }
BENCHMARK_RELATIVE(btree_set_insert)
{ ordered_insert<absl::btree_set<int>>(); }
BENCHMARK_RELATIVE (sorted_vector_set_insert_with_tag)
{ ordered_insert<folly::sorted_vector_set<int>,true>(); }
BENCHMARK_RELATIVE (sorted_vector_set_insert)
{ ordered_insert<folly::sorted_vector_set<int>>(); }
BENCHMARK_RELATIVE (heap_vector_set_insert)
{ ordered_insert<folly::heap_vector_set<int>>(); }
BENCHMARK_DRAW_LINE();
template<class T>
void ordered_insert_random()
{
  folly::BenchmarkSuspender s;
  std::vector<int>          v(N);
  std::iota(v.begin(), v.end(), 0);

  std::random_device rd;
  std::mt19937       g(rd());
  std::shuffle(v.begin(), v.end(), g);

  T m;
  s.dismiss();
  m.insert(v.begin(), v.end());
  folly::doNotOptimizeAway(m);
}
BENCHMARK(set_insert_random)
{ ordered_insert_random<std::set<int>>(); }
BENCHMARK_RELATIVE(btree_set_insert_random)
{ ordered_insert_random<absl::btree_set<int>>(); }
BENCHMARK_RELATIVE (sorted_vector_set_insert_random )
{ ordered_insert_random<folly::sorted_vector_set<int>>(); }
BENCHMARK_RELATIVE (heap_vector_set_insert_random )
{ ordered_insert_random<folly::heap_vector_set<int>>(); }
BENCHMARK_DRAW_LINE();
template<class T>
void ordered_insert_one_by_one()
{
  folly::BenchmarkSuspender s;
  auto n =N/10;
  std::vector<int>          v(n);
  std::iota(v.begin(), v.end(), 0);
  T m;

  std::random_device rd;
  std::mt19937       g(rd());
  std::shuffle(v.begin(), v.end(), g);
  s.dismiss();
  for (int i = 0; i < n; ++i) {
    m.insert(v[i]);
  }
  folly::doNotOptimizeAway(m);
}
BENCHMARK(set_insert_one_by_one)
{ ordered_insert_one_by_one<std::set<int>>(); }
BENCHMARK_RELATIVE(btree_set_insert_one_by_one )
{ ordered_insert_one_by_one<absl::btree_set<int>>(); }
BENCHMARK_RELATIVE (sorted_vector_insert_one_by_one )
{ ordered_insert_one_by_one<folly::sorted_vector_set<int>>(); }
BENCHMARK_RELATIVE (heap_vector_insert_one_by_one )
{ ordered_insert_one_by_one<folly::heap_vector_set<int>>(); }
int main(int argc, char** argv)
{
  folly::runBenchmarks();
}

ordered_benchmark

结论

  • 当容器中有1000000个元素时,heap_vector_set的查询性能最佳,set最差。
  • 如果插入的是有序的range,range中有1000000个元素时,sorted_vector_set使用folly::sorted_unique tag时插入性能最佳,set最差。
  • 如果插入的是随机的range,range中有1000000个元素时,sorted_vector_set插入性能依然最佳,set最差。
  • 如果是一个一个插入随机元素,插入100000个时,btree_set插入性能依然最佳,而heap_vector_set的插入性能最差,只有set的0.2%,sorted_vector_set的性能只有set的13% 。
Posted 2023-05-14