コールアンドマジックの製品版では、体験版で作成したスクリプトを再利用しつつ、よりパフォーマンスが出せるようにリファクタリングや最適化をしている。
今回はその中でも、体験版で頻繁に使用していたSendMessageについて調査してみた。
SendMessageの利点は、オブジェクト間の疎結合を保ちつつ、メッセージのやり取りを汎用的に行う優れた仕組みだ。
ただ、それだけに(汎用的なだけに)かなりCPUコストがかかっている事が予想される。
また、製品版はスクリプトの再利用性よりもパフォーマンスを重視するようにチューニングしたい。
オブジェクト間の静的な関係も体験版でおおかた見えているので、依存性の高い設計に変えてもゲームシステムに影響はない。
後は、SendMessageを関数ポインタや、メソッドの直接呼出しに変更する労力に見合った成果が得られるかどうかだ。
そこで、同じメソッドに対して、SendMessageと直接呼出し、関数ポインタからの呼出しで、どれくらいコストが違うのかを調べてみた。
処理時間の計測には、System.Diagnostics.Stopwatchクラスを使用した。
double sec = (double) sw.ElapsedTicks / (double) System.Diagnostics.Stopwatch.Frequency;
上記の方法で、ミリ秒よりもさらに細かい精度で計測している。
たとえば、SendMessageを呼び出す箇所の計測コードはこんな感じ。
sw.Reset();
sw.Start();
for (int counter = 0; counter < loop; counter++) {
go.SendMessage("ExecAction", args, SendMessageOptions.RequireReceiver);
}
sw.Stop();
sec = (double) sw.ElapsedTicks / (double) System.Diagnostics.Stopwatch.Frequency;
Debug.Log ("SendMessage:" + sec);
[/csharp]
直接呼出し、関数ポインタからの呼出し、SendMessageからの呼出しで同じメソッドを10万回呼び出した結果が以下となる。
Direct:0.0015052
Action:0.0016074
SendMessage:0.9018596
直接呼出しと関数ポインタからの呼出しでは、ほとんど同じ処理時間で、10万回の呼び出しで1ミリ秒程度だ。
それに対しSendMessage経由だと、900ミリ秒(前者の900倍!)のコストがかかっている。
依存性が高くなっても、呼出先について十分な情報が得られる場合には、SendMessageは使用せず、直接呼出しか関数ポインタからの呼出を検討すべきだという結論になった。