Estoy escribiendo un programa para ejecutar en un ATmega 328 que se ejecuta a 16Mhz (es un Arduino Duemilanove si los conoce, es un chip AVR).
Tengo un proceso de interrupción que se ejecuta cada 100 microsegundos. Es imposible, diría, calcular cuánto "código" puede ejecutar en un bucle de 100 microsegundos (estoy escribiendo en C, que presumiblemente se convierte en ensamblaje y luego en una imagen binaria).
Además, esto dependería de la complejidad del código (un trazador de líneas gigante podría correr más lento que varias líneas cortas, por ejemplo).
¿Entiendo bien que mi procesador con una velocidad de reloj o 16Mhz realiza 16 millones de ciclos por segundo (esto significa 16 ciclos por microsegundo 16,000,000 / 1,000 / 1,000); Entonces, si quiero hacer más en mi ciclo de 100 microsegundos, ¿comprar un modelo más rápido como una versión de 72Mhz me daría 72 ciclos por microsegundo (72,000,000 / 1,000 / 1,000)?
Actualmente funciona un poco demasiado lento, es decir, se tarda un poco más de 100 microsegundos en hacer el ciclo (cuánto tiempo es demasiado difícil de decir, pero se retrasa gradualmente) y me gustaría que hiciera un poco más, es ¿Es un enfoque sensato obtener un chip más rápido o me he vuelto loco?
fuente
Respuestas:
En general, el número de instrucciones de ensamblaje que el dispositivo puede ejecutar por segundo dependerá de la combinación de instrucciones y de cuántos ciclos tarda cada tipo de instrucción (CPI) en ejecutarse. En teoría, podría contar su código en ciclo mirando el archivo asm desmontado y mirando la función que le preocupa, contando todos los diferentes tipos de instrucciones en él y buscando los recuentos de ciclo de la hoja de datos para su procesador de destino.
El problema de determinar el número efectivo de instrucciones por segundo se exacerba en los procesadores más complejos por el hecho de que están canalizados y tienen cachés y qué no. Este no es el caso de un dispositivo simple como un ATMega328, que es una sola instrucción en el procesador de vuelo.
En cuanto a cuestiones prácticas, para un dispositivo simple como un AVR, mi respuesta sería más o menos "sí". Duplicar la velocidad de su reloj debería reducir la mitad del tiempo de ejecución de cualquier función. Sin embargo, para un AVR, no funcionarán más rápido que 20MHz, por lo que solo podría "overclockear" su Arduino en otros 4MHz.
Este consejo no se generaliza a un procesador que tenga características más avanzadas. Duplicar la velocidad del reloj en su procesador Intel no duplicará en la práctica el número de instrucciones que ejecuta por segundo (debido a predicciones erróneas de rama, errores de caché, etc.).
fuente
La respuesta de @vicatcu es bastante completa. Una cosa adicional a tener en cuenta es que la CPU puede encontrarse en estados de espera (ciclos de CPU detenidos) al acceder a E / S, incluidos los programas y la memoria de datos.
Por ejemplo, estamos usando un DSP TI F28335; Algunas áreas de la RAM tienen un estado de espera 0 para la memoria de programa y datos, por lo que cuando ejecuta el código en la RAM, se ejecuta a 1 ciclo por instrucción (a excepción de aquellas instrucciones que toman más de 1 ciclo). Sin embargo, cuando ejecuta código desde la memoria FLASH (EEPROM incorporada, más o menos), no puede ejecutarse a 150MHz completos y es varias veces más lento.
Con respecto al código de interrupción de alta velocidad, debe aprender varias cosas.
Primero, familiarícese con su compilador. Si el compilador hace un buen trabajo, no debería ser mucho más lento que el ensamblaje codificado a mano para la mayoría de las cosas. (donde "mucho más lento": un factor de 2 estaría bien para mí; un factor de 10 sería inaceptable) Debe aprender cómo (y cuándo) usar los indicadores de optimización del compilador, y de vez en cuando debe mirar en la salida del compilador para ver cómo funciona.
Algunas otras cosas que puede hacer que el compilador haga para acelerar el código:
use funciones en línea (no recuerdo si C lo admite o si es solo un isma C ++), tanto para funciones pequeñas como para funciones que se ejecutarán solo una o dos veces. La desventaja es que las funciones en línea son difíciles de depurar, especialmente si la optimización del compilador está activada. Pero le ahorran secuencias innecesarias de llamada / retorno, especialmente si la abstracción de "función" es para fines de diseño conceptual en lugar de implementación de código.
Consulte el manual de su compilador para ver si tiene funciones intrínsecas: estas son funciones integradas dependientes del compilador que se asignan directamente a las instrucciones de ensamblaje del procesador; algunos procesadores tienen instrucciones de ensamblaje que hacen cosas útiles como min / max / bit reverse y puede ahorrar tiempo al hacerlo.
Si está haciendo un cálculo numérico, asegúrese de no llamar innecesariamente a las funciones de la biblioteca matemática. Tuvimos un caso en el que el código era algo así como
y = (y+1) % 4
para un contador que tenía un período de 4, esperando que el compilador implementara el módulo 4 como un bit-AND. En su lugar, llamó a la biblioteca de matemáticas. Así que reemplazamosy = (y+1) & 3
por hacer lo que queríamos.Familiarízate con la página de trucos de bit bitiddling . Te garantizo que usarás al menos uno de estos a menudo.
También debe usar los periféricos del temporizador de su CPU para medir el tiempo de ejecución del código; la mayoría de ellos tienen un temporizador / contador que se puede configurar para que se ejecute a la frecuencia del reloj de la CPU. Capture una copia del contador al principio y al final de su código crítico, y podrá ver cuánto tarda. Si no puede hacer eso, otra alternativa es bajar un pin de salida al comienzo de su código, y subirlo al final, y mirar esta salida en un osciloscopio para cronometrar la ejecución. Hay compensaciones para cada enfoque: el temporizador / contador interno es más flexible (puede cronometrar varias cosas) pero es más difícil obtener la información, mientras que configurar / borrar un pin de salida es inmediatamente visible en un osciloscopio y puede capturar estadísticas, pero Es difícil distinguir múltiples eventos.
Finalmente, hay una habilidad muy importante que viene con la experiencia, tanto general como con combinaciones específicas de procesador / compilador: saber cuándo y cuándo no optimizar . En general, la respuesta es no optimizar. La cita de Donald Knuth se publica con frecuencia en StackOverflow (generalmente solo la última parte):
Pero se encuentra en una situación en la que sabe que tiene que hacer algún tipo de optimización, por lo que es hora de morder la bala y optimizar (u obtener un procesador más rápido, o ambos). No NO escribir toda la ISR en el montaje. Eso es casi un desastre garantizado: si lo hace, dentro de meses o incluso semanas olvidará partes de lo que hizo y por qué, y es probable que el código sea muy frágil y difícil de cambiar. Sin embargo, es probable que haya partes de su código que sean buenos candidatos para la asamblea.
Señales de que partes de su código son adecuadas para la codificación de ensamblaje:
Aprenda las convenciones de llamada de la función de su compilador (por ejemplo, dónde coloca los argumentos en los registros y qué registros guarda / restaura) para que pueda escribir rutinas de ensamblaje invocables en C.
En mi proyecto actual, tenemos una base de código bastante grande con código crítico que tiene que ejecutarse en una interrupción de 10 kHz (100usec, ¿suena familiar?) Y no hay tantas funciones escritas en ensamblador. Los que son, son cosas como el cálculo de CRC, las colas de software, la compensación de ganancia / compensación de ADC.
¡Buena suerte!
fuente
Otra cosa a tener en cuenta: probablemente hay algunas optimizaciones que puede realizar para que su código sea más eficiente.
Por ejemplo, tengo una rutina que se ejecuta desde una interrupción del temporizador. La rutina tiene que completarse dentro de 52 µS, y debe pasar por una gran cantidad de memoria mientras lo hace.
Logré un gran aumento de velocidad al bloquear la variable principal del contador en un registro con (en mi µC y compilador, diferente al suyo):
No sé el formato para su compilador: RTFM, pero habrá algo que puede hacer para acelerar su rutina sin tener que cambiar al ensamblaje.
Dicho esto, probablemente pueda hacer un trabajo mucho mejor en la optimización de su rutina que el compilador, por lo que cambiar al ensamblaje puede darle algunos aumentos masivos de velocidad.
fuente