¿Cómo determinar el uso máximo de pila en un sistema embebido con gcc?


Estoy escribiendo el código de inicio para un sistema embebido the el código que carga el puntero de pila inicial antes de saltar a la función main (). y necesito decirle cuántos bytes de pila usará mi aplicación (o alguna estimación conservadora más grande).

Me han dicho que el compilador de gcc ahora tiene una opción-fstack-usage y una opción-fcallgraph-info que de alguna manera se puede usar para calcular estáticamente el "Uso Máximo de la pila" exacto para mí. ("Requisitos de la pila en tiempo de compilación análisis con GCC " por Botcazou, Comar y Hainque ).

Nigel Jones dice que la recursividad es una muy mala idea en sistemas embebidos ("Computing your stack size" 2009), así que he tenido cuidado de no hacer ninguna función mutuamente recursiva en este código.

Además, me aseguro de que ninguno de mis manejadores de interrupciones vuelva a habilitar interrupciones hasta su instrucción final de retorno de interrupción, por lo que no necesito preocuparme por los manejadores de interrupciones de reentrada.

Sin recursión o manejadores de interrupción de reentrante, debería ser posible determinar estáticamente el uso máximo de la pila. (Y así la mayoría de las respuestas a Cómo determinar el uso máximo de la pila? no procede). Mi entendimiento es que (o preferiblemente, un poco de código en mi PC que se ejecuta automáticamente cada vez que reconstruyo el ejecutable) primero encuentro la profundidad máxima de pila para cada manejador de interrupciones cuando no es interrumpido por una interrupción de mayor prioridad, y la profundidad máxima de pila de la función main() cuando no se interrumpe. Luego los agrego todos para encontrar la profundidad máxima total (en el peor de los casos) de la pila. Esto ocurre (en mi sistema embebido) cuando la tarea main () en segundo plano está en su máxima profundidad cuando es interrumpida por la interrupción de menor prioridad, y esa interrupción está en su máxima profundidad cuando es interrumpida por la siguiente interrupción de menor prioridad, y así sucesivamente.

Estoy usando YAGARTO con gcc 4.6.0 para compilar código para el LM3S1968 ARM Cortex-M3.

Entonces, ¿cómo uso el - fstack-opción de uso y-fcallgraph-info opción con gcc para calcular la profundidad máxima de la pila? ¿O hay algún enfoque mejor para determinar el uso máximo de la pila?

(Ver ¿Cómo determinar el uso máximo de la pila en el sistema embebido? para casi la misma pregunta dirigida al compilador de Keil .)

Author: Community, 2011-06-17

5 answers

Documentos del CCG:

- fstack-uso

Hace que la salida del compilador apile información de uso para el programa, sobre una base por función. El nombre de archivo para el volcado se hace añadiendo .su al auxname. auxname se genera a partir del nombre del archivo de salida, si se especifica explícitamente y no es un ejecutable, de lo contrario es el nombre base del archivo de origen. Una entrada se compone de tres campos:

  • el nombre de La función.
  • Un número de byte.
  • Uno o más calificadores: estático, dinámico, acotado.

El calificador static significa que la función manipula la pila estáticamente: se asigna un número fijo de bytes para el marco en la entrada de la función y se libera en la salida de la función; de lo contrario, no se realizan ajustes de pila en la función. El segundo campo es este número fijo de bytes.

El calificador dinámico significa que la función manipula la pila dinámicamente: además de la estática asignación descrita anteriormente, los ajustes de pila se realizan en el cuerpo de la función, por ejemplo, para empujar/pop argumentos alrededor de llamadas a funciones. Si el calificador acotado también está presente, la cantidad de estos ajustes está acotada en tiempo de compilación y el segundo campo es un límite superior de la cantidad total de pila utilizada por la función. Si no está presente, la cantidad de estos ajustes no está limitada en tiempo de compilación y el segundo campo solo representa la parte limitada.

No puedo encuentre cualquier referencia a-fcallgraph-info

Podría crear la información que necesita de-fstack-usage y-fdump-tree-optimized

Para cada hoja en-fdump-tree-optimized, obtenga sus padres y sume su número de tamaño de pila (teniendo en cuenta que este número se encuentra para cualquier función con "dinámica" pero no "limitada") de-fstack-usage, encuentre el máximo de estos valores y este debería ser su uso máximo de pila.

 17
Author: τεκ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-17 19:44:49

En caso de que a nadie se le ocurra una respuesta mejor, publicaré lo que tenía en el comentario a su otra pregunta, a pesar de que no tengo experiencia con estas opciones y herramientas:

GCC 4.6 añade la opción -fstack-usage que proporciona estadísticas de uso de la pila función por función.

Si combina esta información con un gráfico de llamadas producido por cflow o una herramienta similar, puede obtener el tipo de análisis de profundidad de pila que está buscando (un script probablemente podría ser escrito bastante fácilmente para hacer esto). Haga que el script lea la información de uso de la pila y cargue un mapa de nombres de funciones con la pila utilizada por la función. Luego haga que el script camine por el gráfico cflow (que puede ser un árbol de texto fácil de analizar), sumando el uso de la pila asociado con cada línea para cada rama en el gráfico de llamadas.

Por lo tanto, parece que esto se puede hacer con GCC, pero es posible que tenga que improvisar el conjunto correcto de herramientas.

 9
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-17 21:44:46

Bastante tarde, pero para cualquiera que mire esto, las respuestas dadas que implican combinar las salidas de fstack-usage y herramientas de gráficos de llamadas como cflow pueden terminar siendo tremendamente incorrectas para cualquier asignación dinámica, incluso limitada, porque no hay información sobre cuándo se produce esa asignación dinámica de la pila. Por lo tanto, no es posible saber a qué funciones debe aplicar el valor. Como ejemplo artificial, si la salida (simplificada) de fstack-usage es:

main        1024     dynamic,bounded
functionA    512     static
functionB     16     static

Y un muy simple el árbol de llamadas es:

main
    functionA
    functionB

El enfoque ingenuo para combinarlos puede resultar en que main -> functionA sea elegida como la ruta de uso máximo de la pila, a 1536 bytes. Pero, si la mayor asignación de pila dinámica en main () es empujar un argumento grande como un registro a functionB () directamente en la pila en un bloque condicional que llama a functionB (ya dije que esto fue inventado), entonces realmente main -> functionB es la ruta de máximo uso de pila, a 1040 bytes. Dependiendo del diseño de software existente, y también para otros objetivos más restringidos que pasan todo en la pila, los errores acumulativos pueden llevarlo rápidamente a buscar caminos completamente incorrectos que reclaman tamaños máximos de pila significativamente exagerados.

También, dependiendo de su clasificación de "reentrante" cuando se habla de interrupciones, es posible perder algunas asignaciones de pila por completo. Por ejemplo, la interrupción de nivel 7 de muchos procesadores Coldfire es sensible al borde y, por lo tanto, ignora la máscara de desactivación de interrupción, por lo que si semáforo se utiliza para dejar la instrucción temprano, puede que no lo considere reentrante, pero la asignación inicial de la pila todavía ocurrirá antes de que se compruebe el semáforo.

En resumen, hay que tener mucho cuidado al usar este enfoque.

 6
Author: Adam Palaniuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-29 04:35:41

No estoy familiarizado con las opciones -fstack-usage y -fcallgraph-info. Sin embargo, siempre es posible averiguar el uso real de la pila por:

  1. Asignar el espacio adecuado de la pila (para este experimento), e inicializarlo a algo fácilmente identificable. Me gusta 0xee.
  2. Ejecute la aplicación y pruebe todas sus rutas internas (mediante todas las combinaciones de entrada y parámetros). Deje que se ejecute por más de "el tiempo suficiente".
  3. Examine el área de la pila y vea cuánto de la pila era utilizar.
  4. Hacer que el tamaño de la pila, más 10% o 20% para tolerar las actualizaciones de software y condiciones raras.
 3
Author: wallyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-17 18:38:05

Terminé escribiendo un script python para implementar la respuesta de τεκ. Es demasiado código para publicar aquí, pero se puede encontrar en github

 3
Author: PeterM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:01