4

編集: C# コードの追加unsafeバージョン。この提案に感謝しますunsafe。C# コードはより高速に実行されますが、約 3% しかありません。


短いバージョン: C# と Objective-C でいくつかのベンチマーク コードを作成し、iPad 3 でテストしました。これが私の質問です。ベンチマークに使用したコード (以下を参照) よりも高速に実行される C# コードを記述できますか? それとも、MonoTouch/Obj-C 固有の違いが原因でしょうか?


長いバージョン:計画中のマルチプラットフォーム ゲームの小さなプロトタイプを書きました。ゲーム コアを Windows/.NET から iPad 3/MonoTouch に移植した後、iPad でのコードの実行速度が非常に遅いことに気付きました。ゲーム コアの特定の重要な部分は、Intel CPU よりも iPad CPU の方が約 10 倍遅く実行されました (iPad は ARM プロセッサで実行されるため、これは正常なようです)。

ただし、これは私たちのゲームにとって大きな問題であるため、iPad 3 で小さなベンチマーク テストを実行しまし。ベンチマークは、多くの単純な追加と配列の検索を行います。MonoTouch は GC で処理されているため、Obj-C を支持する小さな違いが見られると予想していましたが、驚いたことに、MonoTouch コードは Obj-C コードよりも実行に多くの時間を必要としました。正確には:floatfloat

  • DEBUG モードとRELEASE モードで実行する必要があるObj-Cコード。47'647 ms27'162 ms
  • DEBUG モードおよびRELEASE モードでの実行に必要なポインターを使用しないMonoTouchコード。unsafe116'885 ms40'002 ms
  • DEBUG モードおよびRELEASE モードで実行するために必要なポインターを含むMonoTouchコード。unsafe90'372 ms38'764 ms

もちろん、気になるのはRELEASEモード。

LLVMMonoTouchが Obj-Cと同じネイティブ コードにコンパイルされるという事実を考えると、この違いは私には少し大きいように思えます。

私が使用した Obj-C コードは次のとおりです。

int i, j;
long time = GetTimeMs64();
float * arr = (float *) malloc(10000 * sizeof(float)); //  10'000
for (j = 0; j < 100000; j++) {                         // 100'000
    arr[0] = 0;
    arr[1] = 1;
    for (i = 2; i < 10000; i++) {                      //  10'000
        arr[i] = arr[i - 2] + arr[i - 1];
        if (arr[i] > 2000000000) {             // prevent arithm. overflow
            arr[i - 1] = 0;
            arr[i] = 1;
        }
    }
}
long time2 = GetTimeMs64() - time;

GetTimeMs64()<sys/time.h>のを使用しgettimeofdayます。

ここに私のC#/MonoTouchコードのunsafeバージョンがあります:

var array = new float[10000];                          //  10'000
var watch = System.Diagnostics.Stopwatch.StartNew();
fixed (float* arr = array)
{
    for (int j = 0; j < 100000; j++)                   // 100'000
    {
        *(arr + 0) = 0;
        *(arr + 1) = 1;
        for (int i = 2; i < 10000; i++)                //  10'000
        {
            *(arr + i) = *(arr + i - 2) + *(arr + i - 1);
            if (*(arr + i) > 2000000000)               // prevent arithm. overflow
            {
                *(arr + i - 1) = 0;
                *(arr + i) = 1;
            }
        }
    }
}

watch.Stop();

編集 2:これは、Xamarin から得た回答です。

この特定の例には、モノのパフォーマンスを損なう 2 つの問題があります。

まず、LLVM ではなくデフォルトの MonoTouch コンパイラを使用している場合、実行速度ではなくコンパイル速度が調整されているため、パフォーマンスが低下することが予想されます。LLVM を使用すると、より良い結果が得られます。

次に、mono は浮動小数点に関する ECMA 仕様に準拠し、すべての計算を倍精度で行います。float を使用する C コードと比較すると、これは通常、特に測定可能なパフォーマンス コストを伴います。

正確性を損なうことなく倍精度のパフォーマンスを緩和する方法、または少なくともオプトイン メカニズムを使用する方法を検討してきました。

4

1 に答える 1

5

Marc がコードを使用するよう提案したようunsafeに、MonoTouch はこの .NET 機能をサポートしています。

これにより、.NETの優れた安全な機能である .NET 配列境界チェックが削除されますが、パフォーマンスが低下します (各配列アクセスをチェックする必要があるため)。

これにより、コードが(ソースとネイティブの両方で)Objective-C コードのように見え、パフォーマンスがより近くなります。それでもunsafe、パフォーマンスが本当に重要な場合にのみコードを使用することをお勧めします (そして、その価値があることを測定した後)。

于 2012-09-14T17:14:07.997 に答える