今回やること
namespaceの導入
背景
$ valgrind --tool=callgrind --callgrind-out-file=./callgrind.out ./bin/mastermind 4 4 --test $ gprof2dot -f callgrind ./callgrind.out | dot -Tpdf -o report.pdf
でプロファイルをしたところ,
countHitBlow関数が全体の35.57%を占めていることが分かりました.
その中でもvectorの生成が時間を要しているようですね.
/** * @fn HitBlow countHitBlow(Code &code, Code &guess) * @brief コード2つから, hit, blowを計算する * @param[in] code コード * @param[in] guess コード * @param[in] config パラメタ * @return (hit, blow) */ auto countHitBlow( Code &code, Code &guess, Config &config ) { std::vector<int> x(config.nColors, 0); // ここか std::vector<int> y(config.nColors, 0); // ここか int hit = 0, blow = 0; ... ( 中略 ) ... return HitBlow(hit, blow); }
メモリの動的確保は時間がかかるので, メモリの動的確保をなるべく減らすべく次のように変更してみます.
std::vector<int> x(1, 0); // 外に出してみた std::vector<int> y(1, 0); // 外に出してみた /** * @fn HitBlow countHitBlow(Code &code, Code &guess) * @brief コード2つから, hit, blowを計算する * @param[in] code コード * @param[in] guess コード * @param[in] config パラメタ * @return (hit, blow) */ auto countHitBlow( Code &code, Code &guess, Config &config ) { if ( x.size() < config.nColors ) { x.resize(config.nColors); // 必要な分だけresize y.resize(config.nColors); // 必要な分だけresize } std::fill(x.begin(), x.end(), 0); // reset std::fill(y.begin(), y.end(), 0); // reset int hit = 0, blow = 0; ... ( 中略 ) ... return HitBlow(hit, blow); }
これでもコンパイルは通りますが, x
, y
変数がglobal変数となってしまいます.
そのため他の変数空間を汚さないために, 自作のコード部分を新しくnamespaceで囲います.
これにより, 変数x
, y
は自分のnamespace内のグローバル変数として定義されることになり,
他のライブラリに影響を与えませんし、他のライブラリから意図的にアクセスされない限り参照されることもありません。
namespaceは下記のように囲みます. 入れ子にすることも可能です.
namespace 名前{ a func(int x, int y){ ... }; };
実験
10回の実行時間の平均で比較します.
nColors | nPins | totalTime [msec] | new countHitBlow - totalTime [msec] |
---|---|---|---|
5 | 5 | 3.7 | 0.1 |
6 | 5 | 679.7 | 41.5 |
7 | 5 | 18467.3 | 16983.7 |
速くなっていますね.
まとめ
namespaceを導入し, 安全にグローバル変数を用意してvectorの動的生成の回数を減らすことで実行時間を減少させることができました
コード
他の記事
- 次の記事
- 前の記事
- 一覧 mastermind カテゴリーの記事一覧 - サブロウ丸