boost::numeric::ublas::vectorの速度比較
boost/numeric/ublas/vectorの生成と代入に関する速度をまとめた。
要素数を5千万にして生成と代入の速度を計測。
compiler及び環境
- i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
- Macbookair 2013mid
clock関数で時間を計測。時間の分解能はμ秒。
時間はコンパイル時にO2
オプションをつけた時と付けない時の時間を記載。
生成と初期化の速度
まとめ
ublas::vector
とstd::vector
の生成に関する時間の差はなし。vectorのfor文での全要素の走査は生成の6倍程度の時間がかかる。但し、O2オプションをつければ生成と同程度の時間ですむ。
- 生成後の代入操作はなるべく避ける。
std::vector
の生成の時間
std::vector<double> vec1(num, 2.0);
上記コードのstd::vector
の生成の時間は
- O2なし:0.379705[sec]
- O2あり:0.244777[sec]
boost::numeric::ublas::vector
の生成の時間
boost::numeric::ublas::vector<double> vec3(num, 1.2);
上記コードのboost::numeric::ublas::vector
の生成の時間
- O2なし:0.408235[sec]
- O2あり:0.249085[sec]
boost::numeric::ublas::vector
の走査時間
for (std::size_t index = 0; index < num; ++index) { vec3[index] = index / 2.0; }
上記コードのboost::numeric::ublas::vector
の走査時間
- O2なし:1.27493[sec]
- O2あり:O2:0.279947[sec]
代入に関する時間
前提として下記コード内のvec2,vec3
は以下のように要素数5千万のublas::vector
として宣言されているとする。
const std::size_t num = 50000000; boost::numeric::ublas::vector<double> vec2(num); boost::numeric::ublas::vector<double> vec3(num);
まとめ
vec2=vec3
の代入が最も高速。for文での要素毎の代入は
vec2=vec3
の4倍程度かかる。関数への参照渡しは要素数にかかわらずほぼ時間0と考えて良い。
関数への実体渡しは、vectorの生成にかかる時間と同程度かやや遅い。
関数への実体戻しでの代入は、for文での代入と同じくらい遅い。
参照渡しで関数内で
vec2=vec3
をするのと、関数外でvec2=vec3
は速度はほぼ同じ。
vec2=vec3
の速度
vec3[1] = vec2[10]; vec2 = vec3; vec2[1] = vec3[2];
- O2なし:0.079151
- O2あり:0.075633
for文による要素毎の代入の速度速度
for (std::size_t index = 0; index < num; ++index) { vec2[index] = vec3[index]; }
- O2なし:1.83324
- O2あり:0.3431
生成のときのfor文の倍の時間かかっているのは、operator[]
が二個あるため。
関数の参照渡しと戻り値を実体戻し
boost::numeric::ublas::vector<double> hoge( boost::numeric::ublas::vector<double>& vec) { return vec; } vec3 = hoge(vec2);
- O2なし:0.408114
- O2あり:0.317184
for文と同じくらい遅い
関数の参照渡しと参照戻し
boost::numeric::ublas::vector<double>& hoge2( boost::numeric::ublas::vector<double>& vec) { return vec; } vec3 = hoge2(vec2);
- O2なし:0.073233
- O2あり:0.075371
おそらく、vec2=vec3
と内部的には同じ動作。
参照渡しにかかる時間
void hoge3( boost::numeric::ublas::vector<double>& vec) { } hoge3(vec3);
- O2なし:1e-06
- O2あり:0
参照渡しにかかる時間はほぼゼロ。O2
で0[sec]になっているのはおそらく関数内にコードがないので、関数呼び出しを省略されたため。
関数の実体渡しにかかる時間
void hoge4( boost::numeric::ublas::vector<double> vec) { } hoge4(vec3);
- O2なし:0.264846
- O2あり:0.249281
実体渡しは生成とほぼ同じ時間がかかる。
参照渡しで関数内でvec2=vec3
void hoge5( boost::numeric::ublas::vector<double>& vec, boost::numeric::ublas::vector<double>& vec2) { vec2 = vec; } hoge5(vec2, vec3);
- O2なし:0.075753
- O2あり:0.074778
コード全体
時間は時間計測開始部分にコメントで以下のように付与している。
//O2オプションなしの時間[sec] //O2オプションありの時間[sec] start = clock() //処理など
#include <boost/numeric/ublas/vector.hpp> #include <vector> #include <time.h> boost::numeric::ublas::vector<double> hoge( boost::numeric::ublas::vector<double>& vec) { return vec; } boost::numeric::ublas::vector<double>& hoge2( boost::numeric::ublas::vector<double>& vec) { return vec; } void hoge3( boost::numeric::ublas::vector<double>& vec) { } void hoge4( boost::numeric::ublas::vector<double> vec) { } void hoge5( boost::numeric::ublas::vector<double>& vec, boost::numeric::ublas::vector<double>& vec2) { vec2 = vec; } int main(int argc, char const* argv[]) { namespace ublas = boost::numeric::ublas; const std::size_t num = 50000000; //0.379705 //O2:0.244777 clock_t start = clock(); std::vector<double> vec1(num, 2.0); clock_t end = clock(); double duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration1:" << duraiton << std::endl; boost::numeric::ublas::vector<double> vec2(num, 1.0); for (std::size_t index = 0; index < num; ++index) { vec2[index] = index; } //0.408235 //O2:0.249085 start = clock(); boost::numeric::ublas::vector<double> vec3(num, 1.2); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration2:" << duraiton << std::endl; //1.27493 //O2:0.279947 start = clock(); for (std::size_t index = 0; index < num; ++index) { vec3[index] = index / 2.0; } end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration3:" << duraiton << std::endl; //0.118211 //O2:0.103219 start = clock(); vec3[1] = vec2[10]; vec2 = vec3; vec2[1] = vec3[2]; end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration4:" << duraiton << std::endl; //2.2732 //O2:0.446582 start = clock(); for (std::size_t index = 0; index < num; ++index) { vec2[index] = vec3[index]; } end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration5:" << duraiton << std::endl; //0.422054 //O2:0.421855 start = clock(); vec3 = hoge(vec2); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration6:" << duraiton << std::endl; //0.119685 //O2:0.115396 start = clock(); vec3 = hoge2(vec2); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration7:" << duraiton << std::endl; //1e-06 //O2:0 start = clock(); hoge3(vec3); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration8:" << duraiton << std::endl; //0.346663 //O2:0.259321 start = clock(); hoge4(vec3); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration9:" << duraiton << std::endl; //0.074641 //O2:0.075302 start = clock(); hoge5(vec2, vec3); end = clock(); duraiton = static_cast<double>((end - start)) / CLOCKS_PER_SEC; std::cout << "duration10:" << duraiton << std::endl; return 0; }