Boost.Rangeの速度

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

```cpp: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)で比較した。
コンパイラは以下の通り

```console
clang version 3.4 (tags/RELEASE_34/final)
Target: x86_64-redhat-linux-gnu
Thread model: posix
```

```console
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 を使用。

```command
clang++ boost_range_speed.cpp -std=c++11 -O0 && ./a.out 2> /dev/null 
```

```console
native        = 245
range         = 3287
range_adapter = 9412
```

```command
clang++ boost_range_speed.cpp -std=c++11 -O1 && ./a.out 2> /dev/null
```

```console
native        = 78
range         = 1689
range_adapter = 3290
```

Boost.Range遅（汗）と思うじゃん。


```command
clang++ boost_range_speed.cpp -std=c++11 -O2 && ./a.out 2> /dev/null
```

```console
native        = 98
range         = 91
range_adapter = 129
```

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

```command
g++ boost_range_speed.cpp -std=c++11 -O0 && ./a.out 2> /dev/null
```

```console
native        = 479
range         = 4051
range_adapter = 10088
```

```command
g++ boost_range_speed.cpp -std=c++11 -O1 && ./a.out 2> /dev/null
```

```console
native        = 73
range         = 105
range_adapter = 113
```

ん？早くね？

```command
g++ boost_range_speed.cpp -std=c++11 -O2 && ./a.out 2> /dev/null
```

```console
native        = 71
range         = 68
range_adapter = 49
```

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


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

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