ObjC vs. MonoTouch flotante y performance de la matriz

EDIT: Se agregó una versión unsafe del código C #. Gracias por esta sugerencia, el código C # unsafe ejecuta más rápido, pero solo alnetworkingedor del 3%.


Versión corta: escribí un código de reference en C # y en Objective-C y lo probé en el iPad 3. La versión MonoTouch / C # necesitaba entre 50% -150% más time para ejecutarse que el mismo código en Objective-C. Aquí está mi pregunta: ¿Puedo escribir un código C # que se ejecute más rápido que el código que utilicé para el punto de reference (ver más abajo) o es causado por alguna diferencia MonoTouch / Obj-C inherente?


Versión larga: acabo de escribir un pequeño prototipo para un juego multiplataforma planificado. Después de portar el núcleo del juego desde Windows / .NET al iPad 3 / MonoTouch, noté cuánto más lento funcionaba el código en el iPad. Ciertas partes cruciales del núcleo del juego funcionaron aproximadamente 10 veces más lentamente en la CPU del iPad que en la CPU de Intel (lo que parece ser normal porque el iPad se ejecuta con un procesador ARM).

Sin embargo, dado que este es un problema importante para nuestro juego, ejecuté una pequeña testing de reference en el iPad 3, una vez con MonoTouch , y luego la misma cosa con Plain Objective-C . El punto de reference hace una gran cantidad de adiciones float simples y búsquedas de matriz float . Como MonoTouch está en GC, esperaba ver una pequeña diferencia a favor de Obj-C, pero para mi asombro, el código MonoTouch necesitaba mucho más time para ejecutar que el código Obj-C. Para ser preciso:

  • El código Obj-C necesitaba 47'647 ms para ejecutarse en modo DEBUG y 27'162 ms en modo RELEASE.
  • El código MonoTouch sin el uso de pointers unsafe necesitó 116'885 ms para ejecutarse en modo DEBUG y 40'002 ms en modo RELEASE.
  • El código MonoTouch con pointers unsafe necesitaba 90'372 ms para ejecutarse en modo DEBUG y 38'764 ms en modo RELEASE.

Por supuesto, el modo RELEASE es lo que me importa.

Esta diferencia parece un poco alta para mí, dado el hecho de que MonoTouch comstack al mismo código LLVM nativo como Obj-C.

Aquí está el código Obj-C que usé:

 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() utiliza <sys/time.h> 's gettimeofday .

Aquí mi código C # / MonoTouch, en la versión 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(); 

EDIT 2: esta es la respuesta que recibimos de Xamarin:

Hay dos problemas con este ejemplo en particular que perjudican el performance mono.

Primero, si está utilizando el comstackdor MonoTouch por defecto, y no LLVM, puede esperar un performance menor, ya que está optimizado para la velocidad de compilation y no para la velocidad de ejecución. LLVM te dará mejores resultados.

En segundo lugar, mono cumple con la especificación ECMA con respecto al punto flotante y realiza todos los cálculos con doble precisión. Esto generalmente tiene un costo de performance medible especialmente si se compara con el código C que usa flotadores.

Hemos estado buscando maneras de relajar el desempeño de doble precisión sin comprometer la corrección o, al less, tener un mecanismo de opción.

Como Marc sugirió que debería usar unsafe código unsafe , MonoTouch admite esta function .NET.

Eso eliminará las comprobaciones de los límites de la matriz .NET, que son una característica agradable y segura de .NET, pero tiene penalizaciones de performance (ya que cada acceso a la matriz debe verificarse).

Eso hará que su código luzca más (tanto en origen como en forma nativa), se parece al código Objective-C y el performance debería ser más cercano. Aún así, le aconsejo que use código unsafe solo cuando el performance realmente sea importante (y después de medir que la ganancia valga la pena).