コピーが減らせなくても、malloc/freeを減らすことはできる

MacOSXではgprofが使えない→Sharkを使うでfreeが負担になっていることがわかったので一時オブジェクトを作成しないように変えてみる。

この関数は与えられたgame_scoreをコピーして変更したものを返しているけど、与えられたものを破壊的に変更する関数に変えてみよう。

inline scores end_of_round(const scores &round_score, scores game_score){
  /* ラウンド終了時のゲームスコア更新処理 */
  int median = get_median(round_score[0], round_score[1], round_score[2]);
  if(round_score[0] == median) game_score[0] += median;
  if(round_score[1] == median) game_score[1] += median;
  if(round_score[2] == median) game_score[2] += median;
  return game_score;
}

まず参照を取って参照を返すようにする。

-inline scores end_of_round(const scores &round_score, scores game_score){
+inline scores& end_of_round(const scores &round_score, scores &game_score){

でもって破壊されるスコア用の変数をfor文の外で宣言してそれを使い回すようにする。ってここまで書いてnew_game_score = game_scoreの代入で実は一時オブジェクトを作ってswapしてて意味がないんじゃないかという気がしてきたけど目をつぶって直進する。

-
+    scores new_game_score;
     for(size_t i=0; i < N; i++){
       int o1 = unknowns.pop(i);
       for(size_t j=0; j < N - 1; j++){
 	if(i == j) continue;
 	int o2 = unknowns.pop(j);
 	if(iturn == 3){
+	  new_game_score = game_score;
 	  score += end_of_game(
 	    end_of_round(
 	      end_of_turn(my, o1, o2, round_score), 
-	      game_score));
+	      new_game_score));

実行。お、4.5秒になった。200%以上の高速化になったよ!他の関数も同じように変更しよう。

うひゃ。0.96533sだって。10倍速くなった。以前のバージョンから比べても4倍だ。コピー自体の回数は減らせないから、と思ってチューニングしてなかったけど、コピーの時に新しい一時オブジェクトを作るのではなく一時的に置いておくための領域を作って使い回すことでmallocとfreeを節約できるわけか。

http://coderepos.org/share/changeset/27183/lang/python/saichugen/experiments/cpp/saichugen_simple.cpp