便利な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++だとたまにむしろ速い。
もっと複雑なループだとどうなるかは不明。