2012-09-14 46 views
4

編輯:增加了unsafe版本的C#代碼。謝謝你們的建議,unsafe C#代碼運行得更快,但只有大約3%。ObjC與MonoTouch浮點和陣列性能


短版:我在C#和Objective-C中寫了一些基準測試代碼和測試它在iPad 3,50%-150%的時間比執行之間所需的MonoTouch的/ C#版本Objective-C中的相同代碼。這裏是我的問題:我可以編寫比我用於基準測試的代碼執行速度更快的C#代碼(見下文),還是由於某些固有的MonoTouch/Obj-C差異導致?


龍版本:我只是寫了一個小原型計劃的多平臺遊戲。將遊戲內核從Windows/.NET移植到iPad 3/MonoTouch後,我注意到代碼在iPad上運行速度較慢。遊戲內核的某些關鍵部分在iPad CPU上運行速度比在Intel CPU上慢10倍左右(這似乎是正常現象,因爲iPad是使用ARM處理器運行的)。

然而,因爲這是我們的遊戲的一個主要問題,我經營的小基準測試在iPad 3,一旦MonoTouch的,然後用普通Objective-C的同樣的事情。該基準測試增加了很多簡單的floatfloat陣列查找。由於MonoTouch已經GC了,我預計會看到Obj-C的小小差異,但讓我驚訝的是,MonoTouch代碼比Obj-C代碼需要更多的時間來運行。更確切地說:

  • 的OBJ-C代碼所需47'647 ms在調試模式下運行,並且在釋放模式27'162 ms
  • MonoTouch沒有使用unsafe代碼的指針需要116'885 ms在DEBUG模式下運行,而40'002 ms在RELEASE模式下運行。
  • MonoTouch的代碼與需要90'372 ms在調試模式下運行unsafe指針,並在釋放模式38'764 ms

當然,RELEASE模式是我所關心的。

鑑於MonoTouch編譯爲與Obj-C相同的本地LLVM代碼,這一差異對我來說似乎有點高。

這裏是的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得到了答案:

有兩個問題與此特定損害單聲道性能的例子。首先,如果您使用的是默認MonoTouch編譯器,而不是LLVM,則可能會導致性能降低,因爲它的編譯速度爲 ,而不是執行速度。 LLVM會給你更好的結果。其次,單聲道符合關於浮點的ECMA規範,並且 以雙精度進行所有計算。如果與使用 浮點數的C代碼相比,這通常會具有可測量的性能成本。

我們一直在尋找各種方法來放鬆雙精度性能 而不影響正確性,或者至少有一個選擇在 機制。

+1

單點觸摸是否允許「不安全」?你可以用'float *'做所有這些 - 應該明顯更快......? –

+0

謝謝,不幸的是它只有3%的速度。 – cheeesus

+0

@cheeesus你最終決定使用什麼? – Den

回答

5

像Marc建議你應該使用unsafe代碼,MonoTouch支持這個.NET特性。

這將刪除.NET陣列邊界檢查其是的.NET一個不錯的,更安全,功能,但具有的性能損失(因爲每個數組訪問必須進行檢查)。

這會讓你的代碼看起來更像源代碼和本地代碼,看起來像Objective-C代碼,性能應該更接近。不過,我建議你只有在性能真正重要時才使用unsafe代碼(並且在測量增益值之後)。

+0

謝謝,不幸的是,不安全的C#代碼速度只有3%左右。我編輯了代碼以反映「不安全」的變化,並添加了新的基準測試結果。我仍在尋找其他解決方案。 – cheeesus

+0

'unsafe'允許你刪除'[]'數組索引(使用指針),這將刪除需要額外時間的ABC(數組邊界檢查)。 – poupou

+0

OTOH我沒有看到使用指針的任何真正的改進。我建議您聯繫[email protected]與您的測試用例,以便運行時的人員可以查看正在生成的代碼。 – poupou