きっかけ
とある実装でC#処理負荷が非常に高く困っていたのですが、C#の実行速度が遅いからと考えていました。
ふと、magnitudeの平方根計算が非常に高負荷になっているのではないかと思い、検証してみました。
A,B2点間の距離を出す式は以下のようになり、公式リファレンスにも負荷があるよと記述があります
HatenaってTex記述もできるんだねすごぃ
Unity - Scripting API: Vector3.sqrMagnitude
計測方法
そこで負荷を以下の計算式で試してみました
magnitude | Vector3.magnitude |
sqrMagnitude | Vector3.sqrMagnitude |
systemMagnitude | System.Math.Sqrt(V.x*V.x+V.y*V.y+V.z*V.z) |
systemSqrMagnitude | V.x*V.x+V.y*V.y+V.z*V.z |
最初に以下のようなスクリプトを組んだのですが、ラムダ式の負荷が想像以上に高く(ベタに記述した場合の2倍以上)正確な実行速度差が分からなかったためdelegateを使わないようにしています。
また、実行結果が正しい事を確認するために結果をlengthとして出力しています。
IEnumerator Start () { yield return new WaitForSeconds(0.5f); CalcTest("magnitude", (v) => v.magnitude); yield return 0; CalcTest("sqrMagnitude", (v) => v.sqrMagnitude); yield return 0; CalcTest("systemMagnitude", (v) => (float)System.Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z)); yield return 0; CalcTest("systemSqrMagnitude", (v) => v.x * v.x + v.y * v.y + v.z * v.z); } void CalcTest(string n, System.Func<Vector3,float> method) { var vA = Vector3.zero; var vB = new Vector3(2f, 2f, 2f); var v = vA - vB; float length = 0f; float time = Time.realtimeSinceStartup; for(int i = 0; i < COUNT; i++) { length = method(v); } Debug.Log(n + "->" + (Time.realtimeSinceStartup - time) + " length=" + length); }
実行結果
今回は10000000回の実行速度を計測します。
環境
- Corei7-2600K 3.4Ghz
- UnityEditor
magnitude->2.611315 length=3.464102
sqrMagnitude->1.627022 length=12
systemMagnitude->1.290134 length=3.464102
systemSqrMagnitude->0.8662863 length=12
まさかの結果でした。
magnitudeはSystem.Mathの2倍の負荷がかかる事がわかりました。
magnitudeの実装を見るとSystem.Math.Sqrtを実行しているだけだったのでVector3のプロパティを通すだけで負荷がかかるようです。
平方根の負荷自体は1.5倍程度だったので激しくボトルネックになることはなさそうです。
面白い結果が分かってよかったです。