三つの観点
実行速度は当然重要ですが、エンジンにとってはそれだけではありません。次の三つを計測しました。
- 実行性能:四則演算、リストへの追加、ユーザー定義型の生成をそれぞれ10万回。
- コンパイル時間:変更が実行可能になるまでの時間。デザイナーの試行錯誤の速さを左右します。
- C++呼び出しのコスト:言語の境界をまたぐ呼び出し一回あたりのコスト。エンジンのスクリプトはほとんどこれで成り立っています。
WrenはCライブラリなので薄いC++ラッパーだけで済みます。C#の選択肢はP/Invoke、COM相互運用、埋め込み相互運用型、Monoによるホスティングでした。
// Arithmetic (C#)
for (int i = 0; i < 100000; i++)
{
int x = 0, y = 10;
int result = x * y / (i + 1);
}
// Collections (Wren)
var items = []
for (i in 1..100000) {
items.add(i * i)
}
結果
四則演算(µs・小さいほど良い)
リスト(µs・小さいほど良い)
オブジェクト生成(µs・小さいほど良い)
コンパイル時間(µs・小さいほど良い)
C++の呼び出し(ms・小さいほど良い)
計測方法:実行性能のベンチマークは上のループ(10万回)を、両言語で同じように書いたものです。大学での短い調査であり本格的なベンチマークではないため、結果は正確な値ではなく桁の目安として見てください。こうした数値はハードウェア、ランタイムのバージョン、JITのウォームアップによって変わります。
勝ち負けではなくトレードオフ
C#は6〜15倍速く動作しました。一方Wrenはコンパイルが1000倍以上速く、C++の呼び出しもほぼゼロコスト。C#は境界をまたぐたびに無視できないコストがかかりました。
つまり、正解はスクリプトの役割次第です。エンジンのゲームプレイスクリプトの多くはエンジンの機能同士をつなぐもので、C++を頻繁に呼び出し、頻繁に書き換えられます。これはWrenの安い呼び出しコストと即時の反復に向いています。重い計算はどちらにせよC++で書くべきです。