LoginSignup
8
8

More than 5 years have passed since last update.

Boost.Rangeの速度

Posted at

便利なBoost.Range
でもお高いんでしょう?
という事で簡単なコードで速度測ってみた。
ちょっと簡単すぎるループな感はある。

boost_range_speed.cpp
#include <chrono>
#include <boost/range/irange.hpp>
#include <boost/range/adaptors.hpp>

namespace A = boost::adaptors;
namespace ch = std::chrono;

unsigned long native(unsigned int N) {
  unsigned long sum = 0;
  for (unsigned long i = 0; i < N; ++i) {
    if (i % 2 != 0)
      continue;
    sum += i + 1;
  }
  return sum;
}

unsigned long range(unsigned int N) {
  unsigned long sum = 0;
  for (unsigned long i : boost::irange((unsigned int)0, N)) {
    if (i % 2 != 0)
      continue;
    sum += i + 1;
  }
  return sum;
}

unsigned long range_adapter(unsigned int N) {
  unsigned long sum = 0;
  for (auto i : boost::irange((unsigned int)0, N) |
       A::filtered([](int i) { return i % 2 == 0; }) |
       A::transformed([](unsigned int i) { return i + 1; })) {
    sum += i;
  }
  return sum;
}

template <class F> void task_time(F &&f) {
  auto begin = ch::system_clock::now();
  auto sum = f();
  auto end = ch::system_clock::now();
  std::cerr << "sum = " << sum << std::endl;
  std::cout << ch::duration_cast<ch::milliseconds>(end - begin).count()
            << std::endl;
}

int main(int argc, char const *argv[]) {
  const unsigned long N = 10000 * 10000;

  std::cout << "native        = ";
  task_time([=]() { return native(N); });
  std::cout << "range         = ";
  task_time([=]() { return range(N); });
  std::cout << "range_adapter = ";
  task_time([=]() { return range_adapter(N); });

  return 0;
}

自分でインクリメントする従来のfor(native)、irangeだけ使った場合(range)、
adapterも使った場合(range_adapter)で比較した。
コンパイラは以下の通り

clang version 3.4 (tags/RELEASE_34/final)
Target: x86_64-redhat-linux-gnu
Thread model: posix
g++ (GCC) 4.8.3 20140624 (Red Hat 4.8.3-1)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

またCPUは Intel(R) Xeon(R) CPU W3530 @2.80GHz を使用。

clang++ boost_range_speed.cpp -std=c++11 -O0 && ./a.out 2> /dev/null 
native        = 245
range         = 3287
range_adapter = 9412
clang++ boost_range_speed.cpp -std=c++11 -O1 && ./a.out 2> /dev/null
native        = 78
range         = 1689
range_adapter = 3290

Boost.Range遅(汗)と思うじゃん。

clang++ boost_range_speed.cpp -std=c++11 -O2 && ./a.out 2> /dev/null
native        = 98
range         = 91
range_adapter = 129

-O2で同等な速度になる。range_adapterは有意に遅い。
一方g++では

g++ boost_range_speed.cpp -std=c++11 -O0 && ./a.out 2> /dev/null
native        = 479
range         = 4051
range_adapter = 10088
g++ boost_range_speed.cpp -std=c++11 -O1 && ./a.out 2> /dev/null
native        = 73
range         = 105
range_adapter = 113

ん?早くね?

g++ boost_range_speed.cpp -std=c++11 -O2 && ./a.out 2> /dev/null
native        = 71
range         = 68
range_adapter = 49

range_adapterのが早くなったΣ(゜ロ゜;)!!

結論

filteredやtransformedのようなアダプタは-O2でコンパイルするならオーバーヘッドにはならない。
g++だとたまにむしろ速い。

もっと複雑なループだとどうなるかは不明。

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8