1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-08-12 20:49:16 +03:00
Files
esp8266/cores/esp8266/umm_malloc/Notes.h
M Hightower 7a43092df0 Update core with upstream umm_malloc (#6438)
* WIP: Initial overlay of upstream version of umm_malloc over
our current version w/o any edits.

Using files from:
  https://github.com/rhempel/umm_malloc/tree/master/src
  https://github.com/rhempel/c-helper-macros/tree/develop

The following file remanents from our old version were removed:
  umm_malloc.cpp, umm_performance.h, umm_performance.cpp, and umm_stats.h

This is intended to be a "compare to" for changes made to
upstream version.

* WIP: upstream version of umm_malloc customized for Arduino ESP8266 Core
See comments at the top of umm_malloc.cpp for a summary of changes so far.

Added support for integrity check and poison check to refactored heap.cpp.

* Resoved Travis CI - issue

* Corrected #ifdef's for UMM_STATS/UMM_STATS_FULL

* Corrected UMM_REALLOC_DEFRAG option to be more like the original umm_realloc.
Updated some comments and changed method of defining _rom_putc1.

* Updated UMM_POISON_CHECK_LITE - Expanded the poison check on the current
allocation to include its nearest allocated neighbors in the heap.
That is to say, if the nearest neighbor is free, then the next one over
is checked. And this is done in both directions.
umm_malloc() will also checks the neighbors of the selected
allocation before use.

Merged umm_malloc.c into umm_malloc.cpp.

Added additional stats for debug build.

On going comment cleanup.

Removed #if 0 block from isr_safe_printf.

Corrected mistyped UMM_POISON_CHECK UMM_CHECK_POISON.
Corrected other conditional build issues.

* Updated printing in heap.cpp to behave the way os_printf did.

Updated printing in heap.cpp to behave the way os_printf would have with regards
to system_set_os_print. ie. setDebugOutput enable/disables printing

Expanded #ifdef fenceing of .c files to prevent Arduino IDE from building them
outside of the .cpp file they are included in.

Corrected more conditional building issues.

Remaining concern - umm_info(0, true) printing - does it need an ISR safe method,
all printing is done from within a critical sectionn with rsil(15)?
Or should be have the print option disabled for non-debug builds.
ie. Debug port: "Disabled"

* Merged latest, 2019-09-07, from upstream umm_malloc

* R.Hempel 2019-09-07 - Separate the malloc() and free() functionality into
*                        wrappers that use critical section protection macros
*                        and static core functions that assume they are
*                        running in a protected con text. Thanks @devyte

* Resolved issue where OOM selected w/ Debug port: "Disabled" caused hang.

With OOM selected w/ Debug port: "Disabled" you can now use
Serial.setDebugOutput(true); to enable OOM message displaying.
This is the behavior previously available with os_printf.

commit rev 1

* Fixed realloc OOM bug introduced due to confusing code, added comment for future.

umm_info(NULL, true) is now treated as a debug option that is enabled by
Arduino IDE->tools `Debug port: "Serial"`, etc. It now prints when
DEBUG_ESP_PORT or UMM_INFO_PRINT are defined.

Cleanup comments and some conditionals.

* Updated to track PRs for various print definitions. Cleaned up comments

* Added missing "#ifdef __cplusplus"

* Reorganize local enhancements
More comment cleanups
Added Status TODOs marks for upstream

* Print notice message for the need of -DUMM_INFO_PRINT

* This updates the heap management library, umm_malloc, to the current upstream
version at https://github.com/rhempel/umm_malloc. Some reorganizing and new code
was needed to use the new version.

This is a list of note worthy changes:

UMM_POISON - now has a lite option as well as the previous intensive check
option. The code for running the full poison test at the call of the various
alloc functions was removed in the upstream version. In this port the missing
code was added to heap.cpp and umm_local.cpp.
* UMM_POISON - appears to have been partially changed to UMM_POISON_CHECK,
  I treat it as depricated and used UMM_POISON_CHECK, when needed.
  However, the Arduino Core's references to UMM_POISON were replaced with
  UMM_POISON_CHECK_LITE.
* UMM_POISON_CHECK_LITE - Less intense, it just checks poison on active
  neighboring allocations.
* UMM_POISON_CHECK - Full heap intensive check of poison

UMM_INFO_PRINT - This new define makes building UMM_INFO with printing
capability, optional. When umm_info(NULL, true) is used to print a debug view of
heap information to the debug port, it has to walk the heap and print out
information, while in a critical section. This requires that the print function
be able to print w/o doing malloc calls and from an IRQ disabled context. It
also requires more IRAM to handle printing. Without this define
`umm_info(NULL, true)` will not print.
* UMM_INFO_PRINT is enabled as part of selecting `Debug port: "Serial" or
* "Serial1"`. To make available all the time use '-D UMM_INFO_PRINT`.

A cautionary note, on the use of UMM_INTEGRITY_CHECK, UMM_POISON_CHECK, and
UMM_INFO_PRINT. All of these run with IRQs disabled, for periods that can go
into 100's of us. With umm_info(NULL, true) that may go into seconds, depending
on the serial interface speed and the number of memory allocations present. Use
UMM_INTEGRITY_CHECK, UMM_POISON_CHECK, and UMM_INFO_PRINT sparingly.
If you want to see numbers for the disabled time, explore using
UMM_CRITICAL_METRICS in umm_malloc_cfg.h.

* This updates the heap management library, umm_malloc, to the current upstream
version at https://github.com/rhempel/umm_malloc. Some reorganizing and new code
was needed to use the new version.

This is a list of note worthy changes:

UMM_POISON - now has a lite option as well as the previous intensive check
option. The code for running the full poison test at the call of the various
alloc functions was removed in the upstream version. In this port the missing
code was added to heap.cpp and umm_local.cpp.
* UMM_POISON - appears to have been partially changed to UMM_POISON_CHECK,
  I treat it as depricated and used UMM_POISON_CHECK, when needed.
  However, the Arduino Core's references to UMM_POISON were replaced with
  UMM_POISON_CHECK_LITE.
* UMM_POISON_CHECK_LITE - Less intense, it just checks poison on active
  neighboring allocations.
* UMM_POISON_CHECK - Full heap intensive check of poison

UMM_INFO_PRINT - This new define makes building UMM_INFO with printing
capability, optional. When umm_info(NULL, true) is used to print a debug view of
heap information to the debug port, it has to walk the heap and print out
information, while in a critical section. This requires that the print function
be able to print w/o doing malloc calls and from an IRQ disabled context. It
also requires more IRAM to handle printing. Without this define
`umm_info(NULL, true)` will not print.
* UMM_INFO_PRINT is enabled as part of selecting `Debug port: "Serial" or
* "Serial1"`. To make available all the time use '-D UMM_INFO_PRINT`.

A cautionary note, on the use of UMM_INTEGRITY_CHECK, UMM_POISON_CHECK, and
UMM_INFO_PRINT. All of these run with IRQs disabled, for periods that can go
into 100's of us. With umm_info(NULL, true) that may go into seconds, depending
on the serial interface speed and the number of memory allocations present. Use
UMM_INTEGRITY_CHECK, UMM_POISON_CHECK, and UMM_INFO_PRINT sparingly.
If you want to see numbers for the disabled time, explore using
UMM_CRITICAL_METRICS in umm_malloc_cfg.h.

* Updated upstream TODO

* Changes on printing to comply with new understanding of SPI bus availability
from an ISR vs forground with INTLEVEL 15.

* Removed no longer needed files.

* OOM build option now saves file and line number for post mortem reporting.

* Missed change.

* Consolated upstream integration comments into Notes.h. This helps
keep these comments separated from the upstream code and to avoid
getting lost. I'll expand this as I think of and remember more.

* Comment updates.

* Notes update.

* Changes to heap.cpp -
Refactored macro PTR_CHECK__LOG_LAST_FAIL.
Replaced macros __umm_... with uppercase versions.
Corrected misplaced POISON_CHECK__PANIC_FL macro in realloc.

Added debug free options for OOM and Poison to umm_malloc_cfg.h

Updated Notes.h.

Lines that start with "//C" are meant to flag reviewer's attention.

* Corrected Full Poison Check's placement and documented the
thinking behind its placement and Integrity Checks placement
with relation to the *alloc function. Just so I don't forget
again :/

* Fixed typos
2019-10-29 03:42:30 -03:00

252 lines
12 KiB
C++

#if 0
/*
* This .h is nothing but comments about thoughts and observations made while
* updating the Arduino ESP8266 Core, with the new upstream umm_malloc. It is
* added as a .h so that it does not get lost and to avoid cluttering up the
* code with a huge block comment.
PR text description:
upstream version of `umm_malloc` customized for Arduino ESP8266 Core
This updates the heap management library, umm_malloc, to the current upstream
version at https://github.com/rhempel/umm_malloc. Some reorganizing and new code
was needed to use the new version.
This is a list of noteworthy changes:
UMM_POISON - now has a lite option as well as the previous intensive check
option. The code for running the full poison test at the call of the various
alloc functions was removed in the upstream version. In this port, the missing
code was added to heap.cpp and umm_local.cpp.
* UMM_POISON - appears to have been partially changed to UMM_POISON_CHECK,
I treat it as deprecated and used UMM_POISON_CHECK when needed.
However, the Arduino Core's references to UMM_POISON were replaced with
UMM_POISON_CHECK_LITE.
* UMM_POISON_CHECK_LITE - Less intense, it just checks poison on active
neighboring allocations.
* UMM_POISON_CHECK - Full heap intensive check of poison
A cautionary note, on the use of UMM_INTEGRITY_CHECK and UMM_POISON_CHECK, and
umm_info(). All of these run with IRQs disabled, for periods that can go into
100's of us. With umm_info(NULL, true) that may go into seconds, depending on
the serial interface speed and the number of memory allocations present. Use
UMM_INTEGRITY_CHECK, UMM_POISON_CHECK, and umm_info() sparingly. If you want to
see numbers for the disabled time, explore using UMM_CRITICAL_METRICS in
umm_malloc_cfg.h.
===============================================================================
New upstream umm_malloc feature delta's from the old umm_malloc we were using:
umm_posion check for a given *alloc - failure - no longer panics.
option to run full poison check at each *alloc call, not present
option to run full interity check at each *alloc call, not present
upstream code does not call panic from poison_check_block.
Defragmenting effect of realloc is gone. It now minimizes copy. This
may have been an accident during code cleanup.
In one form or another these features have been restored in the
reintegration of the upstream umm_malloc into the Arduino ESP8266 Core.
===============================================================================
A list of changes made for local adaptation of newer upstream umm_malloc.
In umm_malloc.c
Renamed to umm_malloc.cpp
Added `extern "C" { ... };` around code.
Surround DBGLOG_LEVEL with #ifndef... Define value of DBGLOG_LEVEL from
umm_malloc_cfg.h
umm_realloc() - Added UMM_CRITICAL_SUSPEND()/UMM_CRITICAL_RESUME() for when
lightweight locks are available. eg. sti/cli. Single threaded single CPU
case.
umm_realloc() - appears to have been refactored to minimize memmove and
memcpy. The old version would always combine an adjacent block in the
direction of the start of the heap when available and do a memmove. This
had a defragging effect. This appears to have been replaced with an attempt
to minimize copy when possible.
Added heap stats tracking.
In umm_info.c
umm_info() - Added UMM_CRITICAL_DECL(id_info), updated critical sections
with tag.
Carried forward: Added NULL ptr check at beginning (umm_malloc.c).
In umm_poison.c:
Resolved C++ compiler error reported on get_poisoned(), and get_unpoisoned().
They now take in void * arg instead of unsigned char *.
Added #if ... || defined(UMM_POISON_CHECK_LITE) to the conditional.
In umm_integrity.c:
Replaced printf with DBGLOG_FUNCTION. This needs to be a malloc free
function and ISR safe.
Added critical sections.
In umm_malloc_cfg.h:
Added macro UMM_CRITICAL_SUSPEND()/UMM_CRITICAL_RESUME()
Globally change across all files %i to %d: umm_info.c, umm_malloc.c,
Added a #ifdef BUILD_UMM_MALLOC_C fence to prevent Arduino IDE from building
the various .c files that are #included into umm_malloc.cpp. They are
normally enabled by #define <feature name> in umm_malloc_cfg.h. In this
case it builds fine; however, if the define is global, the IDE will try and
build the .c by itself.
Notes,
umm_integrity_check() is called by macro INTEGRITY_CHECK which returns 1
on success. No corruption. Does a time consuming scan of the whole heap.
It will call UMM_HEAP_CORRUPTION_CB if an error is found.
umm_poison_check(), formerly known as check_poison_all_blocks(),
is called by macro POISON_CHECK which returns 1 on success for no
corruption. Does a time consuming scan of all active allocations for
modified poison. The new upstream version does *NOT* call
UMM_HEAP_CORRUPTION_CB if an error is found. The option description says
it does!
umm_poison_realloc() and umm_poison_free() no longer call the macro
UMM_HEAP_CORRUPTION_CB on poison error. Just a printf message is
generated. I have added alternative functions umm_poison_free_fl,
umm_poison_realloc_fl, and get_unpoisoned_check_neighbors in
umm_local.cpp. These expand the poison check on the current allocation to
include its nearest allocated neighbors in the heap.
umm_malloc() has been extended to call check_poison_neighbors for the
allocation it selects, conditionally for UMM_POISON_CHECK_LITE.
For upstream umm_malloc "# define POISON_CHECK() 0" should have been 1
add to list to report.
==============================================================================
Notes from searching for the best print option
Printing from the malloc routines is tricky. Since a print library
might call *alloc. Then recursion may follow as each error call may fail
into another error and so on.
Objective: To be able to print "last gasp" diagnostic messages
when interrupts are disabled and w/o availability of heap resources.
It turns out things are more complicated than that. These are three cases for
printing from the heap and the current solution.:
1. Printing detailed heap info through `umm_info(NULL, 1);`. This function
resides in flash and can only be called from non-ISR context. It can use
PROGMEM strings. Because SPI bus will not be busy when called from foreground.
At this time it is believed that, while running from foreground, a cache-miss
at INTLEVEL 15 can be handled. The key factor being the SPI bus is not
busy at the time of the cache-miss. It is not clear what gets invoked to
process the cache-miss. A software vector call? A hardware assisted transfer?
In any case `umm_info_safe_printf_P()` is also in flash.
The focus here is to print w/o allocating memory and use strings
in flash to preserve DRAM.
2. Printing diagnostic messages possibly from from ISR context.
Use `ets_uart_printf()` in boot ROM.
3. Printing diagnostic messages from `heap.cpp` these printf's need to check
`system_get_os_print()` to confirm debug-output is enabled just as
`os_printf()` did.
Do test calls to `system_get_os_print()` and call `ets_uart_printf()`
in boot ROM when debug print allowed.
Considerations:
* can be called from ISR
* can be called from malloc code, cannot use malloc
* can be called from malloc code that was called from an ISR
* can be called from within a critical section, eg. xt_rsil(15);
* this may be effectively the same as being called from an ISR?
Update: Current thinking is that from foreground we have more leeway
than an ISR.
Knowns:
* ets_printf - For RTOS SDK they replaced this function with one in the SDK.
Most of the problems I can see with ets_printf center around not being
able to maintain a port to thread context. That is you cannot have one
thread using one port while another thread uses the other. In the no OS
case we cannot have one area of code using one port and another area of
code using the other port. Most of the ROM printf functions are not built
to support this kind of usage. Things get especially dangerous when you
try to use the ets_external_printf stuff.
* ets_vprintf - by itself is safe.
* newlibc printf - not safe - lives in flash.
* newlibc snprintf - not safe - lives in flash.
* builtin putc1 print function - Is installed when you use
ets_install_uart_printf. Which calls ets_install_putc1. The selection of UART
is performed by calling uart_buff_switch with 0 for UART0 and 1 for UART1.
This should work for our purpose here, if handled as follows:
* call uart_buff_switch at each printf call to reselect UART
* Update: uart_buff_switch is now updated by uart_set_debug() in uart.cpp
* use a stack buffer to hold a copy the PROGMEM string to print from.
* use ets_vprintf for printing with putc1 function.
* os_printf_plus looks interesting. It is in IRAM. If no heap is available it
will use up to 64 bytes of stack space to copy a PROGMEM fmt for printing.
Issues:
* Printing is turned off by system_set_os_print
* putc1 needs to be in IRAM - this is a uart.cpp issue
* Need to force system_get_free_heap_size to return 0 during critical periods.
* won't work for umm_info if it prints over 64 characters.
* along with umm_info there are other debug messages that exceed 64 characters.
* ets_uart_printf - Appears safe. Just no PROGMEM support. Uses
uart_buff_switch to select UART.
===============================================================================
heap.cpp is the entry point for most of the heap API calls.
It is a merge point for abstracted heap API calls, such as _malloc_r,
pvPortMalloc, and malloc. Thin wrappers are created here for these entry points
and others. The wrappers call through to equivalent umm_malloc entry-point.
These wrappers also provide the access points to do debug options, like OOM,
Integrity Check, and Poison Check.
-DEBUG_ESP_OOM or select `Debug Level: "OOM"` from the IDE.
This option will add extra code to save information on the last OOM event. If
your code is built with the `Debug port: "Serial"` option, debug messages will
print on OOM events. You do not have to do `Debug port: "Serial"` to get OOM
debug messages. From within your code, you can make a call to
`Serial.debugOutput(true);` to enable OOM printing. Of course for this to work
your code must be built with `Debug Level: "OOM"` or equal.
-DUUM_POISON is now the same as -DUMM_POISON_CHECK_LITE
This is new behavior with this updated. UMM_POISON_CHECK_LITE - checks the
allocation presented at realloc() and free(). Expands the poison check on the
current allocation to include its nearest allocated neighbors in the heap.
umm_malloc() will also check the neighbors of the selected allocation before
use.
For more details and options search on UMM_POISON_CHECK in `umm_malloc_cfg.h`
TODO: provide some interesting numbers on the time to perform:
* UMM_POISON_CHECK
* UMM_INTEGRITY_CHECK
* umm_info(NUll, 0) built with and without print capability
* umm_info(NUll, 1) printing a report to Serial device.
===============================================================================
Enhancement ideas:
1. Add tagging to heap allocations. Redefine UMM_POISONED_BLOCK_LEN_TYPE,
expand it to include an element for the calling address of allocating
requester. Expand umm_info(NULL, 1) to print the respective address with each
active allocation. The difficulty here will be the ever-growing complexity of
overlapping build options. I think it would be easiest to build this in with
and expand the UMM_POISON_CHECK_LITE option.
2. A build option to not have printing, from umm_info() compiled in. This can
save on the execution time spent with interrupts disabled.
*/
#endif