2010-08-06 9 views
5

Desglose esta pregunta en subpreguntas. Estoy confundido si debería preguntar por separado o en una pregunta. Así que me limitaré a una sola pregunta.cuáles son los pasos/estrategia para analizar y mejorar el rendimiento de un sistema integrado

  1. ¿Cuáles son en general los pasos para analizar y mejorar el rendimiento de las aplicaciones C?

  2. ¿Estos pasos cambian si estoy desarrollando un sistema integrado?

  3. ¿Qué herramientas hay disponibles que me pueden ayudar?

Recientemente se me ha encomendado una tarea para mejorar el rendimiento de nuestro producto en la plataforma ARM11. Soy relativamente nuevo en este campo de sistemas integrados y necesito gurús aquí en SO para ayudarme.

+1

¿Hay un sistema operativo? ¿Qué es? ¿Qué compilador/cadena de herramientas estás usando? ¿Tienes GPIO de repuesto? ¿Tienes simulador de trabajo? _Embedded_ es un gran campo. – nategoose

Respuesta

4

simplemente el cambio de compiladores puede mejorar su rendimiento de C para el mismo código fuente por muchas veces. GCC no necesariamente ha mejorado para el rendimiento en los últimos años, para algunos programas, gcc 3.x produce un código mucho más estricto que 4.x. Cuando tenía acceso a las herramientas, el compilador ARM producía un código significativamente mejor que gcc. Tanto como 3 o 4 veces más rápido. LLVM ha alcanzado a GCC 4.x y sospecho que pasará a gcc en términos de rendimiento y uso general para la compilación cruzada de código incrustado. Pruebe diferentes versiones de gcc, 3.xy 4.x si está usando gcc. El compilador de Metaware y Arms Adt corrieron alrededor de gcc3.x, gcc3.x dará gcc4.xa ejecutar por su dinero con el código de brazo, para el código de pulgar gcc4.x es mejor y para thumb2 (que no se aplica a usted) gcc4.x también mejor. Recuerde que no he dicho una palabra acerca de cambiar una sola línea de código (todavía).

LLVM es capaz de optimización completa del programa, además de más perillas de ajuste infinitamente que gcc. A pesar de que el código generado (ver 27) solo está alcanzando al actual gcc 4.x en términos de rendimiento para los pocos programas que probé.Y no probé el n número factoral de combinaciones de optimización (optimizo en el paso de compilación, diferentes opciones para cada archivo, o combino dos archivos o tres archivos o todos los archivos y optimizo esos paquetes, mi teoría es no hacer optimizaciones en la C a la BC Pasos, enlace todos los BC juntos y luego haga una sola pasada de optimización en todo el programa, permita la optimización predeterminada cuando llc lo lleve al objetivo.

De la misma manera, simplemente conocer su compilador y las optimizaciones puede mejorar enormemente el rendimiento del código sin tener que cambiar nada de él. ¿Tiene un ARM11 arr compilando para arm11 o brazo genérico? Puede ganar entre un poco y un doce por ciento al decirle al compilador específicamente qué arquitectura/familia (por ejemplo, armv6) sobre el brazo genérico (ARM7) que a menudo se elige como la predeterminada. Sabiendo usar -O2 o -O3 si eres valiente.

A menudo no es el caso, pero cambiar al modo de pulgar puede mejorar el rendimiento para plataformas específicas. No se aplica a usted, pero el avance de gameboy es un ejemplo perfecto, cargado con buses de estado de espera no nulos de 16 bits. El pulgar tiene un puñado de sobrecarga porque requiere más instrucciones para hacer lo mismo, pero al aumentar los tiempos de recuperación, y aprovechando algunas de las características de lectura secuencial del código de gba, el código puede ejecutarse significativamente más rápido que el código de armado para el mismo código fuente

teniendo un brazo11 es probable que tenga un caché L1 y tal vez L2, ¿están encendidos? ¿Están configurados? ¿Tienes un mmu y tu memoria de uso intensivo está en caché? o ¿está ejecutando memoria de estado de espera cero y no necesita un caché y debe apagarlo? Además de no darse cuenta de que puede tomar el mismo código fuente y hacer que se ejecute mucho más rápido cambiando los compiladores u opciones, la gente a menudo no se da cuenta de que cuando usa un caché simplemente agrega un único hasta unos pocos puntos en su código de inicio (como un truco para ajustar el lugar donde el código aterriza en la memoria por una, dos, algunas palabras) puede cambiar la velocidad de ejecución de sus códigos hasta en un 10 a 20 por ciento. Donde esas lecturas de línea de caché tocan en las funciones/bucles muy utilizados hace una gran diferencia. Incluso guardando una línea de caché de lectura ajustando dónde cae el código es notable (por ejemplo, cortar de 3 a 2 o de 2 a 1).

Conociendo su arquitectura, tanto el procesador como su entorno de memoria es donde comenzaría la sintonización. La mayoría de las bibliotecas C si tiene un nivel alto suficiente para usar una (a menudo no uso una biblioteca C ya que funciono sin un sistema operativo y con recursos muy limitados) en su código C y algunas veces agrego algún ensamblador para crear rutinas de cuello de botella como memcpy. mucho mas rápido. Si sus programas funcionan en 32 direcciones alineadas o incluso mejores de 64 bits, y se ajusta incluso si eso significa usar un puñado de bytes más de memoria para que cada estructura/matriz/memcpy sea un múltiplo entero de 32 bits o 64 bits, verá mejoras notables (si su código usa estructuras o copia datos de otras maneras). Además de obtener sus estructuras (si las usa, ciertamente no con el código incrustado) alineadas con el tamaño, incluso si desperdicia memoria, alineando los elementos, considere usar enteros de 32 bits para cada elemento en lugar de bytes o medias palabras. Dependiendo de su sistema de memoria, esto puede ayudar (también puede doler). Al igual que con el ejemplo anterior de GBA, al buscar funciones específicas que, ya sea por perfil o intuición, usted sabe que no se están implementando de manera que aproveche su procesador o plataforma o bibliotecas, es posible que desee convertirlo en ensamblador desde cero o compilando desde C inicialmente. luego desmontar y afinar a mano. Memcpy es un buen ejemplo de que puede conocer el rendimiento de la memoria de su sistema y puede elegir crear su propia memcpy específicamente para datos alineados, copiando 64 o 128 o más bits por instrucción.

Del mismo modo, mezclar las variables globales y locales puede hacer una notable diferencia en el rendimiento. Tradicionalmente se les dice a las personas que nunca usen los globales, pero esto no es necesariamente cierto, depende de cuán profundamente incrustado y cuánto afinado y velocidad y otros factores le interesen. Este es un tema delicado y puede que me llame la atención, por lo que Lo dejaré así.

El compilador tiene que grabar y desalojar registros para realizar llamadas a funciones, y si usa variables locales puede ser necesario un marco de pila, por lo que las llamadas a funciones son costosas, pero al mismo tiempo, dependiendo del código dentro de un función que ahora ha crecido en tamaño evitando funciones, puede crear el problema que intentaba evitar, desalojando registros para reutilizarlos. Incluso una sola línea de código C puede hacer que la diferencia entre todas las variables en una función se ajuste en los registros a tener que comenzar a expulsar un grupo de registros. Para funciones o segmentos de código donde sabe que necesita algún rendimiento, compile y desmonte (y observe el uso del registro, la frecuencia con que recupera la memoria o escribe en la memoria). Puede y encontrará los lugares donde necesita tomar un ciclo bien utilizado y convertirlo en su propia función aunque la llamada a la función tenga una penalización porque al hacerlo el compilador puede optimizar mejor el ciclo y no desalojar/reutilizar los registros y obtiene un ganancia neta general. Incluso una sola instrucción adicional en un bucle que gira cientos de veces es un golpe de rendimiento cuantificable.

Afortunadamente, ya sabe que no compilar para la depuración, apague toda la compilación para las opciones de depuración. Es posible que ya sepa que la compilación de código para depuración que se ejecuta sin errores no significa que esté depurada, compilando errores y utilizando depuradores para ocultar errores dejándolos como bombas de tiempo en su código para su compilación final para el lanzamiento. Aprenda a compilar siempre para su lanzamiento y prueba con la versión de lanzamiento, tanto para el rendimiento como para encontrar errores en su código.

La mayoría de los conjuntos de instrucciones no tienen una función dividir. Evite usar divisiones o módulo en su código tanto como sea humanamente posible, son asesinos de rendimiento. Naturalmente, este no es el caso para los poderes de dos, para salvar al compilador y para evitar mentalmente las divisiones y los modulos que intentan usar los cambios y los ys. Las multiplicaciones son más fáciles y se encuentran con mayor frecuencia en los conjuntos de instrucciones, pero siguen siendo costosas. Este es un buen caso para escribir ensamblador para hacer sus multiplicaciones en lugar de dejar que lo haga la copiadora C. La multiplicación del brazo es 32bit * 32bit = 32 bit, así que para hacer cálculos precisos sin desbordamiento tiene que haber un código C adicional envuelto alrededor de la multiplicación, si ya sabes que no se desbordará, graba los registros para una llamada de función y haz la multiplicación en ensamblador (para el brazo).

Del mismo modo, la mayoría de los conjuntos de instrucciones no tienen una unidad de punto flotante, con la suya es posible que, aun así, evite la flotación si es posible. Si tiene que usar float, es una caja de pandora de problemas de rendimiento. La mayoría de las personas no ven los problemas de rendimiento con código tan simple como esto:

 

float a,b; 

... 

a = b * 7.0; 

El resto del problema no es la comprensión de precisión de punto flotante y lo bueno o malo de las bibliotecas de C están tratando de obtener sus constantes en coma flotante formar. De nuevo, flotar es una larga discusión sobre los problemas de rendimiento.

Soy un producto de Michael Abrash (en realidad tengo una copia impresa del zen del lenguaje ensamblador) y la conclusión es el tiempo de su código. Propón una forma precisa de medir el tiempo del código, puedes pensar que sabes dónde están los cuellos de botella y puedes pensar que conoces tu arquitectura, pero probando diferentes cosas incluso si crees que están equivocadas, y al cronometrarlas puedes encontrar y eventualmente tener que descubre el error en tu forma de pensar Agregar nops para comenzar. Como un paso de ajuste final es un buen ejemplo de esto, todos los demás trabajos que ha realizado para el rendimiento se pueden borrar instantáneamente al no tener una buena alineación con el caché, esto también significa reorganizar las funciones dentro de su código fuente para que aterricen en diferentes lugares en la imagen binaria. He visto un aumento de 10 a 20 por ciento en el aumento y la disminución de la velocidad como resultado de las alineaciones de la línea de caché.

-1
  1. Tienes que usar un generador de perfiles. Le ayudará a identificar los cuellos de botella de su aplicación. Luego concéntrese en mejorar las funciones en las que pasa más tiempo y las que más llama. Repita este procedimiento hasta que esté satisfecho con el rendimiento de su aplicación.

  2. No, no lo hacen.

  3. Dependiendo de la plataforma está desarrollando en:

    de Windows: Código AMD Analyst, VTune, soñoliento

    Linux: valgrind/Callgrind/Cachegrind

    Mac: el generador de perfiles Xcode es bastante bueno.

Intente encontrar un generador de perfiles para la arquitectura en la que realmente trabaja.

+0

2 - pueden ser un tanto si se dirige a algo que no es Windows, Linux, Mac u otro sistema operativo de escritorio.Cambian mucho más cuando no puede ejecutar su código en su escritorio y aún más cuando no tiene un puerto serie, gpio adicional o ICE decente. – nategoose

+0

Sus respuestas son específicas de Pc así que la pregunta 2. es sí. – Gerhard

1
  1. Revisión Código:

    What are good code review techniques ?

    El análisis estático y dinámico del código.

    Herramientas para el análisis estático: Sparrow, prevenir, Klockworks

    herramientas para el análisis dinámico: Valgrind, purify

    Gprof le permite aprender en su programa de distribución de su tiempo y que las funciones llamadas que otras funciones mientras se estaba ejecutando.

  2. pasos son los mismos

  3. Aparte de lo que se indica es el punto 1, existen herramientas como memcheck etc. Hay una gran lista here basado en la plataforma

0

Es una pregunta difícil de responder en breve ya diversas técnicas se han propuesto como diagrama de flujo y diagrama de estado, para que pueda echar un vistazo a algunos títulos:

ARM System-on-chip Arquitectura, 2ª edición - Steve Furber

sistema de brazo Guía del desarrollador - Software de diseño y optimización del sistema - Andrew N. Sloss, Dominic Symes, Chris Wright & John Rayfield

La guía definitiva para la ARM Cortex-M3 --Joseph Yiu

C de programación para sistemas embebidos --Kirk Zurell

Embedded C - Michael J. Pont

programación integrado Sistemas en C y C++ --Michael Barr

Un software integrado Primer --David e, Simon

Embedded sistemas de microprocesadores 3ª Edición --Stuart bola

Especificación global y validación de sistemas integrados - Integración de componentes heterogéneos --G. Nicolescu & AA Jerraya

sistemas embebidos: Modelado, Tecnología y Aplicaciones --Gunter Hommel & Sheng Huanye

Embedded Sistemas y Arquitectura de Computadores --Graham Wilson

Proyectos de hardware embebido --John Catsoulis

1

¡¡¡uf !! ¡Una gran pregunta!

Qué son generalmente los pasos a analizar y mejorar el rendimiento de las aplicaciones C ?

Además de otros analizadores de código estático mencionados aquí, existe una versión bastante barata llamada PC-Lint que ha existido durante mucho tiempo. A veces arroja muchos errores y advertencias por un error, pero para el final se sentirá feliz y sabrá más acerca de C/C++ debido a eso.

Con todos los analizadores de código, algunos de los problemas pueden ser más estructurales para el código, por lo que es mejor comenzar a analizarlo desde el día 1 de codificación; ejecutar análisis en un software antiguo puede saturarlo con problemas que pueden tardar un tiempo en desenredarse, lo mejor es mantenerlo limpio desde el principio.

¡Pero los analizadores de código no detectarán todos los errores lógicos, es decir, no harán lo que usted quiere que haga! Lo mejor es que primero se realicen con revisiones de códigos y luego con pruebas. El rendimiento a menudo se mejora tratando de mantener los algoritmos lo más simple posible, manteniendo las instrucciones en bucles ajustadas, posiblemente desenrollando bucles (las optimizaciones de su compilador pueden hacer esto), uso de cachés rápidos cuando se accede a datos que tardan en obtenerse.

Las revisiones de código pueden generar muchos problemas por parte de muchas personas que lo miran.No atrape demasiadas personas, trate de obtener otras 3 personas si es posible, a veces los desarrolladores menores hacen las preguntas más perspicaces como, "¿por qué estamos haciendo esto?".

Testing se puede dividir a grandes rasgos en dos secciones, automatizada y manual. Las pruebas automatizadas requieren un esfuerzo de producción de controladores de prueba para funciones/unidades, pero una vez que se ejecuta puede ejecutarse una y otra vez muy rápidamente. Las pruebas manuales requieren planificación, autodisciplina para realizarlas todas de la manera necesaria, imaginación para pensar en escenarios que pueden perjudicar el rendimiento y debe ser observador (es posible que haya pasado la prueba, pero el 'trazo del alcance tiene un poco de una anomalía antes/después de la prueba).

"¿Estos pasos cambian si estoy desarrollando para un sistema integrado?"

El ananálisis de rendimiento puede ser diferente en sistemas incorporados a sistemas de aplicaciones; con el pincel muy amplio que ahora "incrustado" cubre, depende de cuán centrado en el hardware se encuentre. Se puede hacer usando perfiladores, si quieres un método más barato y útil, utiliza pines de salida de prueba para medir secciones de código, o mídelas con puntos de interrupción en simuladores que vienen con el entorno de desarrollo.

Asegúrese de que no sólo una longitud típica de la tarea se mide, sino también un máximo, ya que es donde una tarea puede comenzar impidiendo en otras tareas y las tareas programadas no se han completado en el tiempo.

¿Qué herramientas hay disponibles que pueden ayudarme?

simuladores en los entornos de desarrollo, herramientas de análisis estático, herramientas de análisis dinámico, pero la mayor parte de todo lo que los seres humanos y otros que consiguen los requisitos de la derecha, la revisión decente (de código y pruebas) y las pruebas a fondo (automático y manual).

¡Buena suerte!

1

mis experiencias.

  1. Las llamadas de función son lentas, eliminen con macros o métodos en línea. Mire la lista de desensambladores para ver.
  2. Si se utiliza GCC, marcar secciones optimizadas con #pragma GCC optimize("O3") o compilar por separado.
  3. Juega con diferentes combinaciones de aplicar el atributo en línea (básicamente, encuentra un equilibrio entre el tamaño y la velocidad).
Cuestiones relacionadas