feat(docs): update reducing stack size article

pull/13854/head
Alexey Lapshin 2023-08-07 14:57:06 +04:00 zatwierdzone przez BOT
rodzic a8ba5e86d7
commit e1946b6446
3 zmienionych plików z 51 dodań i 11 usunięć

Wyświetl plik

@ -447,6 +447,8 @@ Consult :doc:`Heap Memory Debugging <../api-reference/system/heap_debug>` docume
.. only:: SOC_ASSIST_DEBUG_SUPPORTED
.. _Hardware-Stack-Guard:
Hardware Stack Guard
""""""""""""""""""""

Wyświetl plik

@ -45,24 +45,59 @@ To minimize static memory use:
.. _optimize-stack-sizes:
Reducing Stack Sizes
--------------------
Determining Stack Size
----------------------
In FreeRTOS, task stacks are usually allocated from the heap. The stack size for each task is fixed and passed as an argument to :cpp:func:`xTaskCreate`. Each task can use up to its allocated stack size, but using more than this will cause an otherwise valid program to crash, with a stack overflow or heap corruption.
Therefore, determining the optimum sizes of each task stack, minimizing the required size of each task stack, and minimizing the number of task stacks as whole, can all substantially reduce RAM usage.
To determine the optimum size for a particular task stack, users can consider the following methods:
Configuration Options for Stack Overflow Detection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- At runtime, call the function :cpp:func:`uxTaskGetStackHighWaterMark` with the handle of any task where you think there is unused stack memory. This function returns the minimum lifetime free stack memory in bytes.
.. only:: SOC_ASSIST_DEBUG_SUPPORTED
Hardware Stack Guard
~~~~~~~~~~~~~~~~~~~~
The Hardware Stack Guard is a reliable method for detecting stack overflow. This method uses the hardware's assist-debug module to monitor the CPU's stack pointer register. A panic is immediately triggered if the stack pointer register goes beyond the bounds of the current stack (see :ref:`Hardware-Stack-Guard` for more details). The Hardware Stack Guard can be enabled via the :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` option.
End of Stack Watchpoint
~~~~~~~~~~~~~~~~~~~~~~~
The End of Stack Watchpoint feature places a CPU watchpoint at the end of the current stack. If that word is overwritten (such as in a stack overflow), a panic is triggered immediately. End of Stack Watchpoints can be enabled via the :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` option, but can only be used if debugger watchpoints are not already being used.
Stack Canary Bytes
~~~~~~~~~~~~~~~~~~
The Stack Canary Bytes feature adds a set of magic bytes at the end of each task's stack, and checks if those magic bytes have changed on every context switch. If those magic bytes are overwritten, a panic is triggered. Stack Canary Bytes can be enabled via the :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW` option.
FreeRTOS Check Stack Overflow
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There is a less effective alternative, see :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW` docs for details.
.. note::
When using the End of Stack Watchpoint or Stack Canary Bytes, it is possible that a stack pointer skips over the watchpoint or canary bytes on a stack overflow and corrupts another region of RAM instead. Thus, these methods cannot detect all stack overflows.
.. only:: SOC_ASSIST_DEBUG_SUPPORTED
Recomended and default option is :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` which avoids this disadvantage.
Run-time Methods to Determine Stack Size
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- The :cpp:func:`uxTaskGetStackHighWaterMark` returns the minimum free stack memory of a task throughout the task's lifetime, which gives a good indication of how much stack memory is left unused by a task.
- The easiest time to call :cpp:func:`uxTaskGetStackHighWaterMark` is from the task itself: call ``uxTaskGetStackHighWaterMark(NULL)`` to get the current task's high water mark after the time that the task has achieved its peak stack usage, i.e., if there is a main loop, execute the main loop a number of times with all possible states, and then call :cpp:func:`uxTaskGetStackHighWaterMark`.
- Often, it is possible to subtract almost the entire value returned here from the total stack size of a task, but allow some safety margin to account for unexpected small increases in stack usage at runtime.
- Call :cpp:func:`uxTaskGetSystemState` at runtime to get a summary of all tasks in the system. This includes their individual stack high watermark values.
- When debugger watchpoints are not being used, users can set the :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` option. This will cause one of the watchpoints to watch the last word of the task's stack. If that word is overwritten (such as in a stack overflow), a panic is triggered immediately. This is slightly more reliable than the default :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW` option of ``Check using canary bytes``, because the panic happens immediately, rather than on the next RTOS context switch. Neither option is perfect. In some cases, it is possible that the stack pointer skips the watchpoint or canary bytes and corrupts another region of RAM instead.
- Call :cpp:func:`uxTaskGetSystemState` to get a summary of all tasks in the system. This includes their individual stack high watermark values.
To reduce the required size of a particular task stack, users can consider the following methods:
Reducing Stack Sizes
--------------------
- Avoid stack heavy functions. String formatting functions (like ``printf()``) are particularly heavy users of the stack, so any task which does not ever call these can usually have its stack size reduced.
@ -71,12 +106,13 @@ To reduce the required size of a particular task stack, users can consider the f
- Avoid allocating large variables on the stack. In C, any large structures or arrays allocated as an automatic variable (i.e., default scope of a C declaration) uses space on the stack. To minimize the sizes of these, allocate them statically and/or see if you can save memory by dynamically allocating them from the heap only when they are needed.
- Avoid deep recursive function calls. Individual recursive function calls do not always add a lot of stack usage each time they are called, but if each function includes large stack-based variables then the overhead can get quite high.
To reduce the total number of tasks, users can consider the following method:
Reducing Task Count
^^^^^^^^^^^^^^^^^^^
- Combine tasks. If a particular task is never created, the task's stack is never allocated, thus reducing RAM usage significantly. Unnecessary tasks can typically be removed if those tasks can be combined with another task. In an application, tasks can typically be combined or removed if:
Combine tasks. If a particular task is never created, the task's stack is never allocated, thus reducing RAM usage significantly. Unnecessary tasks can typically be removed if those tasks can be combined with another task. In an application, tasks can typically be combined or removed if:
- The work done by the tasks can be structured into multiple functions that are called sequentially.
- The work done by the tasks can be structured into smaller jobs that are serialized (via a FreeRTOS queue or similar) for execution by a worker task.
- The work done by the tasks can be structured into multiple functions that are called sequentially.
- The work done by the tasks can be structured into smaller jobs that are serialized (via a FreeRTOS queue or similar) for execution by a worker task.
Internal Task Stack Sizes
^^^^^^^^^^^^^^^^^^^^^^^^^

Wyświetl plik

@ -447,6 +447,8 @@ ESP-IDF 堆的实现包含许多运行时的堆结构检查,可以在 menuconf
.. only:: SOC_ASSIST_DEBUG_SUPPORTED
.. _Hardware-Stack-Guard:
硬件堆栈保护
""""""""""""""""""""