2010-05-03 12 views
7

He estado progresando con la programación de audio para iPhone. Ahora estoy haciendo un ajuste de rendimiento, tratando de ver si puedo sacar más provecho de esta pequeña máquina. Ejecutando Shark, veo que una parte significativa de mi potencia de CPU (16%) se está comiendo por objc_msgSend. Entiendo que puedo acelerar esto un poco almacenando punteros a las funciones (IMP) en lugar de llamarlos utilizando la notación [object message]. Pero si voy a pasar por todo este problema, me pregunto si sería mejor usar C++.El objetivo C es lo suficientemente rápido para programar DSP/audio

¿Alguna idea de esto?

+1

¿Está teniendo problemas de rendimiento? ¿Es esa la fruta colgando más baja? –

+0

objc_msgSend parece ser la fruta colgante más baja en mi caso. – morgancodes

Respuesta

4

El problema con Objective-C y las funciones como DSP no es la velocidad per se, sino la incertidumbre de cuándo ocurrirán los inevitables cuellos de botella.

Todos los idiomas tienen cuellos de botella, pero en los lenguajes vinculados estáticos como C++ se puede predecir mejor cuándo y dónde se mostrarán en el código. En el caso del acoplamiento en tiempo de ejecución de Objective-C, el tiempo que lleva encontrar el objeto apropiado, el tiempo que lleva enviar un mensaje no es necesariamente lento, pero es variable e impredecible. La flexibilidad de Objective-C en la interfaz de usuario, la gestión de datos y la reutilización funcionan en su contra en el caso de una tarea estrictamente programada.

La mayoría del procesamiento de audio en la API de Apple se realiza en C o C++ debido a la necesidad de definir el tiempo que tarda el código en ejecutarse. Sin embargo, es fácil mezclar Objective-C, C y C++ en la misma aplicación. Esto le permite elegir el mejor idioma para la tarea inmediata a mano.

+0

Gracias TechZen. Creo que es hora de que me mueva más a la tierra C++. – morgancodes

13

El objetivo C es lo suficientemente rápido para la programación DSP/audio, porque Objective C es un superconjunto de C. No es necesario (y no debe) hacer que todo sea un mensaje. Donde el rendimiento es crítico, use llamadas a funciones simples C (o use ensamblaje en línea, si hay funciones de hardware que puede aprovechar de esa manera). Cuando el rendimiento no es crítico y su aplicación puede beneficiarse de las características de la indirección del mensaje, use los corchetes.

El marco Accelerate en OS X, por ejemplo, es una gran biblioteca Objective C de alto rendimiento. Solo utiliza llamadas a funciones C99 estándar, y puede llamarlas desde código Objective C sin ningún ajuste o indirección.

+1

Gracias Stephen. Si quiero codificar el audio de una manera orientada a objetos, parece que Obj-C puede no ser de mucha ayuda. Si quiero componentes modulares y conectables y no quiero hacer acrobacias para llamar a métodos en mis objetos, parece que C++ se adapta mejor a mis necesidades. – morgancodes

+6

@morgancodes: en la mayoría de los códigos de alto rendimiento que he encontrado, la modularidad ocurre en un nivel relativamente alto, no en el nivel de cada llamada de función. No hay nada que le impida tener componentes modulares de alto nivel conectables utilizando el envío de mensajes de Objective-C cuyas implementaciones centrales de bajo nivel usan llamadas a función C. Si eso realmente no es posible en su situación, pero la sobrecarga de búsqueda de funciones virtuales de C++ * es * de alguna manera aceptable, entonces supongo que debería usar C++. Sin embargo, parece una situación bastante estrecha. –

+0

@StephenCanon * Si eso realmente no es posible en su situación, pero la sobrecarga de búsqueda de funciones virtuales de C++ es de alguna manera aceptable, entonces supongo que debería usar C++. Sin embargo, parece una situación bastante estrecha. * - No es en absoluto 'estrecha'. El envío dinámico de C++ tiene una complejidad baja y prácticamente invariante; es decir, es como usar punteros de función. siempre. El envío de ObjC debe pasar por el tiempo de ejecución de ObjC. Esto puede (pero a menudo no) dar como resultado muchas adquisiciones y/o asignaciones de bloqueos. Entonces, la diferencia es que el despacho dinámico de C++ tiene un costo constante y predecible en el tiempo. – justin

1

objc_msgSend es solo una utilidad. El costo de enviar un mensaje no es solo el costo de enviar el mensaje. Es el costo de hacer todo lo que inicia el mensaje. (igual que el verdadero costo de una llamada de función es su incluido costes, incluyendo E/S si hay alguna.)

Lo que hay que saber es dónde están los mensajes en tiempo dominante con origen o destino y por qué. Stack samples le dirá qué rutinas/métodos se están llamando con tanta frecuencia que debe averiguar cómo llamarlos de manera más eficiente.

Es posible que los llame más de lo necesario.

Especialmente si encuentra que muchas de las llamadas son para crear y eliminar estructuras de datos, probablemente pueda encontrar mejores formas de hacerlo.

+0

Gracias Sr. Dunlavey. Déjame asegurarme de que no estoy confundido sin embargo. Cuando perfilo mi código en shark, y veo "15%" junto a objc_msgSend, eso parece una oportunidad para optimizarme. Creo que el 15% es el gasto real de enviar el mensaje, no la ejecución del código que inicia el mensaje. ¿Correcto? Entonces, en un ciclo cerrado, puedo obtener algún rendimiento al evitar objc_msgSend, ¿verdad? – morgancodes

+0

@morgancodes: No te concentres en esa rutina. Esto es lo que debe hacer: mientras se está ejecutando, pause unas 20 veces y grabe la pila de llamadas. En 3 de esos (más o menos), debería verlo en objc_msgSend. En esas 3 pilas, si miras hacia arriba un nivel, verás la (s) línea (s) exacta (s) del código responsable de ese momento. Mientras lo hace, busque otras cosas que aparezcan en varias pilas y vea de qué más podría deshacerse. En mi experiencia, el código antes de la puesta a punto tiene mucho más margen de mejora que el 15%. –

+0

@morgancodes: Shark dice que toma 10,000 muestras durante 10 segundos. Supongamos que una línea de código está en la pila el 20% del tiempo, por lo que eliminarla podría ahorrar ese tiempo total. Si toma 20 muestras, la verá en el 20% (4) de las muestras, dar o tomar el 9% (1.8). Si se toman 10.000 muestras, la línea mostrará el 20% (2000) de las muestras, dar o recibir el 0,4% (40). De cualquier manera, ¿lo extrañarás? El problema con Shark es que te da una precisión innecesaria pero no te da la información que obtienes al mirar muestras específicas. –

3

C es objetivo lo suficientemente rápido como para la programación DSP/audio

renderizado en tiempo real

Definitivamente No. El tiempo de ejecución de Objective-C y sus bibliotecas simplemente no están diseñadas para las demandas de la reproducción de audio en tiempo real. El hecho es que es virtualmente imposible garantizar que el uso del tiempo de ejecución de ObjC o bibliotecas como Foundation (o incluso CoreFoundation) no provocarán que su procesador falte a su fecha límite.

el caso común es un bloqueo - incluso una asignación de montón sencillo (malloc, new/new[], [[NSObject alloc] init]) probablemente requerirá una cerradura.

Para usar ObjC es utilizar bibliotecas y un tiempo de ejecución que asume que los bloqueos son aceptables en cualquier punto dentro de su ejecución. El bloqueo puede suspender la ejecución de su subproceso de representación (por ejemplo, durante la devolución de llamada de representación) mientras espera adquirir el bloqueo. Entonces puede perder su fecha límite de procesamiento porque su hilo de renderización se mantiene, lo que finalmente resulta en abandonos/fallas.

Pregunte a un desarrollador de plugin de audio profesional: le dirán que el bloqueo dentro del dominio de renderizado en tiempo real está prohibido. No puedes, por ej. ejecute el sistema de archivos o cree asignaciones de pila porque no tiene límites superiores prácticos con respecto al tiempo que le llevará terminar.

Aquí es una buena introducción: http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing

Desconectado representación

Sí, sería aceptablemente rápido en la mayoría de los escenarios de alto nivel mensajería. En los niveles inferiores, recomiendo no usar ObjC porque sería un desperdicio: podría llevar muchas, muchas veces más tiempo renderizar si se usara la mensajería ObjC en ese nivel (en comparación con una implementación C o C++).

Consulte también: Will my iPhone app take a performance hit if I use Objective-C for low level code?

Cuestiones relacionadas