0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Sqrt等の算術演算と掛け算の処理負荷について

Last updated at Posted at 2019-02-22

たまたま気になる記事を見つけて流石に mulとsqrtの負荷が同じは無いだろうということで検証してみました
(まさかりOKということなので)
はてなで一度上げましたがせっかくなのでQiitaを使ってみました

SinとかSqrt等の算術演算と掛け算の処理負荷を比べてみた
https://qiita.com/geekdrums/items/1a6e7480f23c9ffbcfc0


2/22 更新

コメントで指摘があったのでJITレベルで正しいコードに変更しました

  • 計算に使用する変数をstatic化
  • forありなしの結果が別実行だったので同時に出力するように

新しい結果

for文あり
Mult=4959us Sqrt=12772us
SqrtはMulの2.575倍

for文なし
Mult=789us Sqrt=8602us
SqrtはMulの10.901倍


結論から言うと
for文込み
Mult=4863us Sqrt=13664us
SqrtはMulの2.810倍
for文負荷抜き
Mult=446us Sqrt=9460us
SqrtはMulの21.198倍

新たなまさかり歓迎ですmm

気になった点

  • UnityのProfiler精度が10usなため誤差が大きいがそれに対しループ数が少ない
  • 倍精度積の負荷を見ているがfor文で倍精度の加算も行われている
  • そもそもReleaseビルドだと最適化されて中身消えそう
  • for文の負荷とか気になる

環境

Unity2018.3.2 .Net4.X
MacBook Pro 2.9 GHz Intel Core i7

検証コード

今回気になったところは乗算と平方根が同じ負荷というところなので、そこに絞って計測しました

public class MathTest : MonoBehaviour
{
    public const int count = 1000000;
    public const int loop = 100;

    public static double f;

    IEnumerator Start()
    {
        yield return new WaitForSeconds(1f);
        Test();
    }

    static void Test()
    {
        long loopTime = 0L;
        long multTime = 0L;
        long sqrtTime = 0L;

        for (int i = 0; i < loop; i++)
        {
            loopTime += Loop();
            multTime += Mult();
            sqrtTime += Sqrt();
        }

        Debug.Log($"{f}");

        Debug.Log($"Loop={loopTime} Mult={multTime} Sqrt={sqrtTime}");

        Debug.Log("for文あり");
        Debug.Log($"Mult={multTime / loop / 10L}us Sqrt={sqrtTime / loop / 10L}us");
        Debug.Log($"SqrtはMulの{(double) sqrtTime / multTime:F3}倍");

        Debug.Log("for文なし");
        multTime -= loopTime;
        sqrtTime -= loopTime;
        Debug.Log($"Mult={multTime / loop / 10L}us Sqrt={sqrtTime / loop / 10L}us");
        Debug.Log($"SqrtはMulの{(double) sqrtTime / multTime:F3}倍");
    }

    static long Loop()
    {
        f = 1.0;
        var sw = System.Diagnostics.Stopwatch.StartNew();
        for (int i = 0; i < count; i++)
        {
            f = f;
        }

        sw.Stop();
        return sw.ElapsedTicks;
    }

    static long Mult()
    {
        f = 1.00001;
        var sw = System.Diagnostics.Stopwatch.StartNew();
        for (int i = 0; i < count; i++)
        {
            f *= f;
        }

        sw.Stop();
        return sw.ElapsedTicks;
    }

    static long Sqrt()
    {
        f = 100000.0;
        var sw = System.Diagnostics.Stopwatch.StartNew();
        for (int i = 0; i < count; i++)
        {
            f = System.Math.Sqrt(f);
        }

        sw.Stop();
        return sw.ElapsedTicks;
    }
}

ILはこんな感じになります
SharpLab

修正後のJITはこちらです
SharpLab

Mult()
L0017: fmul qword [0x27e016a0]
Sqrt()
L0017: fsqrt

差分がここだけになったのでおそらく抜けは無いと思います

ついでにiOS用に出力したil2cppのコードは以下のようになっていて特に抜けはなさそうです

// f *= f;
double L_1 = ((MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_StaticFields*)il2cpp_codegen_static_fields_for(MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_il2cpp_TypeInfo_var))->get_f_6();
double L_2 = ((MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_StaticFields*)il2cpp_codegen_static_fields_for(MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_il2cpp_TypeInfo_var))->get_f_6();
((MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_StaticFields*)il2cpp_codegen_static_fields_for(MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_il2cpp_TypeInfo_var))->set_f_6(((double)il2cpp_codegen_multiply((double)L_1, (double)L_2)));

// f = System.Math.Sqrt(f);
double L_1 = ((MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_StaticFields*)il2cpp_codegen_static_fields_for(MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_il2cpp_TypeInfo_var))->get_f_6();
IL2CPP_RUNTIME_CLASS_INIT(Math_tFB388E53C7FDC6FCCF9A19ABF5A4E521FBD52E19_il2cpp_TypeInfo_var);
double L_2 = sqrt(L_1);
((MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_StaticFields*)il2cpp_codegen_static_fields_for(MathTest_tA4D864CB9DFCED1A10B65A009CDBB2F4A99381F9_il2cpp_TypeInfo_var))->set_f_6(L_2);

気をつけた点は

  • 計測にメソッドを通さない
  • ticksでの計測
  • 十分CPUに同一負荷がかけられるように計測の平均値算出

ここまで回すと割と結果が安定しました

Mult=4863us Sqrt=13664us
SqrtはMulの2.810倍

Mult=446us Sqrt=9460us
SqrtはMulの21.198倍

for文あり
Mult=4959us Sqrt=12772us
SqrtはMulの2.575

for文なし
Mult=789us Sqrt=8602us
SqrtはMulの10.901倍

ちゃんと処理を見直しましたが割としっくり来る結果になってよかったです

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?