¿Es posible monitorear un bloque de código y determinar el número de ciclos de reloj del procesador que tomó el código en un procesador Atdu Arduino y / o AVR? o, ¿debería más bien monitorear los microsegundos pasados antes y después de ejecutar el código? Nota: No me preocupa tanto el tiempo real (como en cuántos segundos reales pasaron) como "cuántos ciclos de reloj requiere este código de la CPU"
La solución actual que se me ocurre es de time.c:
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
cableado.c agrega:
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
Con esta cuenta, podría calcular los ciclos de reloj pasados mediante el monitoreo de microsegundos pasados y luego pasar eso a microsecondsToClockCycles (). Mi pregunta es, ¿hay una mejor manera?
nota al margen: ¿existen buenos recursos para el monitoreo del desempeño del AVR? lmgtfy.com y varias búsquedas en foros no proporcionan resultados obvios, aparte de la exploración de temporizadores
Gracias
¿Qué quieres decir con "monitor"?
No debería ser difícil contar los ciclos de reloj para AVR para pequeñas piezas de código de ensamblaje.
También puede configurar un puerto antes de que se ejecute el código y luego reiniciarlo, y monitorearlo con un analizador lógico o un osciloscopio para obtener el tiempo.
Y también puede leer el tiempo de un temporizador de funcionamiento rápido, como usted dice.
fuente
Este es un ejemplo para Arduino usando la función clockCyclesPerMicrosecond () para calcular los relojes que han pasado. Este código esperará 4 segundos, luego imprimirá el tiempo transcurrido desde el inicio del programa. Los 3 valores de la izquierda son el tiempo total (microsegundos, milisegundos, ciclos de reloj totales) y los 3 más a la derecha son los tiempos transcurridos:
Salida:
Estoy seguro de que hay una explicación razonable de por qué los primeros bucles también tenían ciclos de reloj transcurridos más cortos que la mayoría y por qué todos los demás bucles alternan entre dos longitudes de ciclos de reloj.
Código:
Nota al margen: si elimina el retraso de 4 segundos, comenzará a ver los efectos de Serial.print () mucho más claramente. Tenga en cuenta que aquí se comparan 2 carreras. Solo he incluido 4 muestras cercanas entre sí de sus registros respectivos.
Ejecución 1:
Ejecución 2:
El tiempo transcurrido aumenta sobre el tiempo total de ejecución. Después de un segundo, los relojes aumentan en promedio de 40k a 44k. Esto sucede constantemente unos pocos milisegundos después de 1 segundo y los relojes transcurridos permanecen alrededor de 44k durante al menos los siguientes 10 segundos (no lo he probado más). Es por eso que el monitoreo es útil o necesario. ¿Quizás la disminución de la eficiencia tiene que ver con la configuración o los errores en serie? O tal vez el código no está usando la memoria correctamente y tiene una fuga que afecta el rendimiento, etc.
fuente
Dado que cada línea de código agregada a su fuente tendrá un impacto en el rendimiento y podría cambiar las optimizaciones aplicadas. Los cambios deben ser el mínimo requerido para realizar la tarea.
Acabo de encontrar un complemento de Atmel Studio llamado "Depurador de archivos de ensamblaje anotado". http://www.atmel.com/webdoc/aafdebugger/pr01.html Parece que pasa por el lenguaje ensamblador real generado, aunque probablemente tedioso le mostrará exactamente lo que está sucediendo. Es posible que aún tenga que decodificar cuántos ciclos se necesitan para cada instrucción, pero se acercaría mucho más que algunas de las otras opciones publicadas.
Para aquellos que no saben en la carpeta Salida de su proyecto, hay un archivo con una extensión LSS. Este archivo contiene todo su código fuente original como comentarios y debajo de cada línea está el lenguaje ensamblador que se generó en función de esa línea de código. La generación del archivo LSS se puede desactivar, así que verifique la siguiente configuración.
Propiedades del proyecto | Cadena de herramientas | AVR / GNU Común | OutputFiles
Casilla de verificación ".lss (Generar archivo lss)
fuente
Puede usar uno de los temporizadores integrados. Configura todo para preescalador = 1 y TCNT = 0 antes del bloque. Luego active el temporizador en la línea antes del bloque y desactívelo en la línea después del bloque. El TCNT ahora mantendrá el número de ciclos que tomó el bloque, menos los ciclos fijos para el código de activación y desactivación.
Tenga en cuenta que el TNCT se desbordará después de 65535 ciclos de reloj en un temporizador de 16 bits. Puede usar el indicador de desbordamiento para duplicar el tiempo de ejecución. Si aún necesita más tiempo, puede usar un preescalador, pero obtendrá menos resolución.
fuente