this is using the mbed os version 5-13-1

Dependencies:   mbed-http

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_memory_status.cpp Source File

mbed_memory_status.cpp

00001 /*
00002     mbed Memory Status Helper
00003     Copyright (c) 2017 Max Vilimpoc
00004 
00005     Permission is hereby granted, free of charge, to any person obtaining a copy
00006     of this software and associated documentation files (the "Software"), to deal
00007     in the Software without restriction, including without limitation the rights
00008     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009     copies of the Software, and to permit persons to whom the Software is
00010     furnished to do so, subject to the following conditions:
00011 
00012     The above copyright notice and this permission notice shall be included in
00013     all copies or substantial portions of the Software.
00014 
00015     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021     THE SOFTWARE.
00022 */
00023 
00024 /**
00025  * Purpose: Print out thread info and other useful details using
00026  *          only raw serial access.
00027  *
00028  * Based on mbed_board.c's error printing functionality, minus
00029  * pulling in all the printf() code.
00030  */
00031 
00032 // Not great having to pull in all of mbed.h just to get the MBED_VERSION macro,
00033 // but it's the only way to do it for both pre- and post-5.4 releases
00034 //
00035 // If you're only supporting something newer than 5.4, you could use this alone:
00036 // #include "platform/mbed_version.h"
00037 //
00038 // platform/mbed_version.h says:
00039 // 999999 is default value for development version (master branch)
00040 
00041 #include "mbed.h"
00042 
00043 // Critical sections header file renamed in mbed OS 5.4 release
00044 // See: https://github.com/ARMmbed/mbed-os/commit/aff49d8d1e3b5d4dc18286b0510336c36ae9603c
00045 
00046 #ifndef MBED_VERSION
00047 #warning "You're probably using an unsupported version of mbed older than 5.2."
00048 #endif
00049 
00050 #if   MBED_VERSION >= 50400
00051 #include "platform/mbed_critical.h"
00052 #elif MBED_VERSION >= 50200
00053 #include "platform/critical.h"
00054 #endif
00055 
00056 #include "platform/mbed_stats.h"
00057 
00058 #if !MBED_STACK_STATS_ENABLED
00059 #warning MBED_STACK_STATS_ENABLED != 1, so there will be no stack usage measurements.
00060 #endif
00061 
00062 #ifndef DEBUG_ISR_STACK_USAGE
00063 #define DEBUG_ISR_STACK_USAGE  0
00064 #endif
00065 
00066 #ifndef DEBUG_MEMORY_CONTENTS
00067 #define DEBUG_MEMORY_CONTENTS  0
00068 #endif
00069 
00070 #define OUTPUT_SERIAL          1
00071 #define OUTPUT_RTT             0
00072 #define OUTPUT_SWO             0
00073 
00074 #if DEBUG_ISR_STACK_USAGE
00075 #include "compiler_abstraction.h"
00076 
00077 // Value is sprayed into all of the ISR stack at boot time.
00078 static const uint32_t ISR_STACK_CANARY = 0xAFFEC7ED; // AFFECTED
00079 
00080 // Refers to linker script defined symbol, may not be available
00081 // on all platforms.
00082 extern uint32_t __StackLimit;
00083 extern uint32_t __StackTop;
00084 
00085 void fill_isr_stack_with_canary(void)
00086 {
00087     uint32_t * bottom = &__StackLimit;
00088     uint32_t * top    = (uint32_t *) GET_SP();
00089 
00090     for (; bottom < top; bottom++)
00091     {
00092         *bottom = ISR_STACK_CANARY;
00093     }
00094 }
00095 #endif // DEBUG_ISR_STACK_USAGE
00096 
00097 #if OUTPUT_SERIAL && DEVICE_SERIAL
00098 #include "hal/serial_api.h"
00099 
00100 extern int      stdio_uart_inited;
00101 extern serial_t stdio_uart;
00102 
00103 static void output_serial_init(void)
00104 {
00105     if (!stdio_uart_inited)
00106     {
00107         serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
00108         serial_baud(&stdio_uart, 115200); // This is hard coded.
00109     }
00110 }
00111 
00112 static void output_serial_print_label(const char * label)
00113 {
00114 #if MBED_VERSION < 50902
00115     // After mbed OS 5.9.2, this locks up the system.
00116     core_util_critical_section_enter();
00117 #endif
00118 
00119     output_serial_init();
00120 
00121     while (*label) serial_putc(&stdio_uart, *label++);
00122 
00123 #if MBED_VERSION < 50902
00124     core_util_critical_section_exit();
00125 #endif
00126 }
00127 #endif // OUTPUT_SERIAL && DEVICE_SERIAL
00128 
00129 #if OUTPUT_RTT
00130 #include "RTT/SEGGER_RTT.h"
00131 
00132 enum
00133 {
00134     DEFAULT_RTT_UP_BUFFER = 0
00135 };
00136 
00137 static void output_rtt_init(void)
00138 {
00139     static int initialized = 0;
00140 
00141     if (!initialized)
00142     {
00143         SEGGER_RTT_ConfigUpBuffer(DEFAULT_RTT_UP_BUFFER, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
00144 
00145         initialized = 1;
00146     }
00147 }
00148 
00149 static void output_rtt_print_label(const char * label)
00150 {
00151     output_rtt_init();
00152     SEGGER_RTT_WriteString(DEFAULT_RTT_UP_BUFFER, label);
00153 }
00154 #endif // OUTPUT_RTT
00155 
00156 #if OUTPUT_SWO
00157 #if defined (NRF52) && !defined (ENABLE_SWO)
00158   #error "You need to enable SWO using `-D ENABLE_SWO` on the mbed compile command line."
00159 #endif
00160 
00161 #ifdef NRF52
00162 #include "nrf.h"
00163 #endif
00164 
00165 static void output_swo_init(void)
00166 {
00167     static int initialized = 0;
00168 
00169     if (!initialized)
00170     {
00171         NRF_CLOCK->TRACECONFIG = (NRF_CLOCK->TRACECONFIG & ~CLOCK_TRACECONFIG_TRACEPORTSPEED_Msk) |
00172             (CLOCK_TRACECONFIG_TRACEPORTSPEED_4MHz << CLOCK_TRACECONFIG_TRACEPORTSPEED_Pos);
00173 
00174         ITM->TCR |= 1;
00175         ITM->TER |= 1;
00176 
00177         initialized = 1;
00178     }
00179 }
00180 
00181 static void output_swo_print_label(const char * label)
00182 {
00183     output_swo_init();
00184     while (*label) ITM_SendChar(*label++);
00185 }
00186 #endif // OUTPUT_SWO
00187 
00188 static void nway_print_label(const char * label)
00189 {
00190 #if OUTPUT_SERIAL
00191     output_serial_print_label(label);
00192 #endif
00193 
00194 #if OUTPUT_RTT
00195     output_rtt_print_label(label);
00196 #endif
00197 
00198 #if OUTPUT_SWO
00199     output_swo_print_label(label);
00200 #endif
00201 }
00202 
00203 static const char HEX[] = "0123456789ABCDEF";
00204 
00205 static void debug_print_u32(uint32_t u32)
00206 {
00207     char output[9] = {0};
00208 
00209     // Always printed as big endian.
00210     output[0] = HEX[(((uint32_t) u32 & 0xf0000000) >> 28)];
00211     output[1] = HEX[(((uint32_t) u32 & 0x0f000000) >> 24)];
00212     output[2] = HEX[(((uint32_t) u32 & 0x00f00000) >> 20)];
00213     output[3] = HEX[(((uint32_t) u32 & 0x000f0000) >> 16)];
00214     output[4] = HEX[(((uint32_t) u32 & 0x0000f000) >> 12)];
00215     output[5] = HEX[(((uint32_t) u32 & 0x00000f00) >>  8)];
00216     output[6] = HEX[(((uint32_t) u32 & 0x000000f0) >>  4)];
00217     output[7] = HEX[(((uint32_t) u32 & 0x0000000f) >>  0)];
00218 
00219     nway_print_label(output);
00220 }
00221 
00222 static void debug_print_pointer(const void * pointer)
00223 {
00224     debug_print_u32((uint32_t) pointer);
00225 }
00226 
00227 #define DPL(X) nway_print_label((X))
00228 
00229 #if (defined (MBED_CONF_RTOS_PRESENT) && (MBED_CONF_RTOS_PRESENT != 0))
00230 #include "cmsis_os.h"
00231 
00232 // cmsis_os.h provides some useful defines:
00233 //
00234 // For mbed OS 5.4 and lower,  osCMSIS == 0x10002U (see: rtos/rtx/TARGET_CORTEX_M)
00235 // For mbed OS 5.5 and higher, osCMSIS == 0x20001U (see: rtos/TARGET_CORTEX/rtx{4|5})
00236 //
00237 // Starting in mbed OS 5.5, a new RTOS layer was introduced with a different API.
00238 
00239 #if (osCMSIS < 0x20000U)
00240     // Temporarily #undef NULL or the compiler complains about previous def.
00241     #undef NULL
00242     #include "rt_TypeDef.h"
00243 #else
00244     #include "rtx_lib.h"
00245     // #include <stdlib.h>  // Include if you need malloc() / free() below. (probably better for non-C99 compilers)
00246 #endif
00247 
00248 #if (osCMSIS < 0x20000U)
00249 
00250 // No public forward declaration for this.
00251 extern "C" P_TCB rt_tid2ptcb (osThreadId thread_id);
00252 
00253 static void print_thread_info(osThreadId threadId)
00254 {
00255     if (!threadId) return;
00256 
00257     osEvent event;
00258 
00259     P_TCB tcb = rt_tid2ptcb(threadId);
00260 
00261     DPL("    stack ( start: ");
00262     debug_print_pointer(tcb->stack);
00263 
00264     event = _osThreadGetInfo(threadId, osThreadInfoStackSize);
00265 
00266     DPL(" end: ");
00267     debug_print_pointer(((uint8_t *) tcb->stack + event.value.v)); // (tcb->priv_stack)));
00268 
00269     DPL(" size: ");
00270     debug_print_u32(event.value.v);
00271 
00272     event = _osThreadGetInfo(threadId, osThreadInfoStackMax);
00273     DPL(" used: ");
00274     debug_print_u32(event.value.v);
00275 
00276 
00277     DPL(" ) ");
00278 
00279     DPL("thread ( id: ");
00280     debug_print_pointer(threadId);
00281 
00282     event = _osThreadGetInfo(threadId, osThreadInfoEntry);
00283     DPL(" entry: ");
00284     debug_print_pointer(event.value.p);
00285 
00286     DPL(" )\r\n");
00287 }
00288 
00289 void print_all_thread_info(void)
00290 {
00291     osThreadEnumId enumId   = _osThreadsEnumStart();
00292     osThreadId     threadId = (osThreadId) NULL; // Can't use nullptr yet because mbed doesn't support C++11.
00293 
00294     while ((threadId = _osThreadEnumNext(enumId)))
00295     {
00296         print_thread_info(threadId);
00297     }
00298 
00299     _osThreadEnumFree(enumId);
00300 }
00301 
00302 #else
00303 
00304 static void print_thread_info(osThreadId threadId)
00305 {
00306     // Refs: rtx_lib.h - #define os_thread_t osRtxThread_t
00307     //       rtx_os.h  - typedef struct osRtxThread_s { } osRtxThread_t
00308 
00309     if (!threadId) return;
00310 
00311     os_thread_t * tcb = (os_thread_t *) threadId;
00312 
00313     uint32_t stackSize = osThreadGetStackSize(threadId);
00314     uint32_t stackUsed = osThreadGetStackSpace(threadId);
00315 
00316     DPL("    stack ( start: ");
00317     debug_print_pointer(tcb->stack_mem);
00318 
00319     DPL(" end: ");
00320     debug_print_pointer((uint8_t *) tcb->stack_mem + stackSize);
00321 
00322     DPL(" size: ");
00323     debug_print_u32(stackSize);
00324 
00325     DPL(" used: ");
00326     debug_print_u32(stackSize - stackUsed);
00327 
00328     DPL(" ) ");
00329 
00330     DPL("thread ( id: ");
00331     debug_print_pointer(threadId);
00332 
00333     DPL(" entry: ");
00334     debug_print_u32(tcb->thread_addr);
00335 
00336     DPL(" name: ");
00337     DPL(osThreadGetName(threadId) ? osThreadGetName(threadId) : "unknown");
00338 
00339     DPL(" )\r\n");
00340 }
00341 
00342 void print_all_thread_info(void)
00343 {
00344     // Refs: mbed_stats.c - mbed_stats_stack_get_each()
00345 
00346     uint32_t     threadCount = osThreadGetCount();
00347     osThreadId_t threads[threadCount]; // g++ will throw a -Wvla on this, but it is likely ok.
00348 
00349     // osThreadId_t * threads = malloc(sizeof(osThreadId_t) * threadCount);
00350     // MBED_ASSERT(NULL != threads);
00351 
00352     memset(threads, 0, threadCount * sizeof(osThreadId_t));
00353 
00354     // This will probably only work if the number of threads remains constant
00355     // (i.e. the number of thread control blocks remains constant)
00356     //
00357     // This is probably the case on a deterministic realtime embedded system
00358     // with limited SRAM.
00359 
00360     osKernelLock();
00361 
00362     threadCount = osThreadEnumerate(threads, threadCount);
00363 
00364     for (uint32_t i = 0; i < threadCount; i++)
00365     {
00366         // There seems to be a Heisenbug when calling print_thread_info()
00367         // inside of osKernelLock()!
00368 
00369         // This error may appear on the serial console:
00370         // mbed assertation failed: os_timer->get_tick() == svcRtxKernelGetTickCount(), file: .\mbed-os\rtos\TARGET_CORTEX\mbed_rtx_idle.c
00371 
00372         // The RTOS seems to be asserting an idle constraint violation due
00373         // to the slowness of sending data through the serial port, but it
00374         // does not happen consistently.
00375         print_thread_info(threads[i]);
00376     }
00377 
00378     osKernelUnlock();
00379 
00380     // free(threads);
00381 }
00382 
00383 #endif
00384 
00385 void print_current_thread_id(void)
00386 {
00387     DPL("Current thread: ");
00388     debug_print_pointer(osThreadGetId());
00389     DPL("\r\n");
00390 }
00391 #endif // MBED_CONF_RTOS_PRESENT
00392 
00393 #if DEBUG_MEMORY_CONTENTS
00394 static void print_memory_contents(const uint32_t * start, const uint32_t * end)
00395 {
00396     uint8_t line = 0;
00397 
00398     for (; start < end; start++)
00399     {
00400         if (0 == line)
00401         {
00402             debug_print_pointer(start);
00403             DPL(": ");
00404         }
00405 
00406         debug_print_u32(*start);
00407 
00408         line++;
00409 
00410         if (16 == line)
00411         {
00412             DPL("\r\n");
00413             line = 0;
00414         }
00415     }
00416 }
00417 #endif
00418 
00419 extern uint32_t mbed_stack_isr_size;
00420 
00421 #if DEBUG_ISR_STACK_USAGE
00422 uint32_t calculate_isr_stack_usage(void)
00423 {
00424     for (const uint32_t * stack = &__StackLimit; stack < &__StackTop; stack++)
00425     {
00426         if (*stack != ISR_STACK_CANARY)
00427         {
00428             return (uint32_t) &__StackTop - (uint32_t) stack;
00429         }
00430     }
00431 
00432     return mbed_stack_isr_size;
00433 }
00434 #endif
00435 
00436 void print_heap_and_isr_stack_info(void)
00437 {
00438 #ifdef ENABLE_MEMORY_CHECKS
00439     extern unsigned char * mbed_heap_start;
00440     extern uint32_t        mbed_heap_size;
00441 
00442     extern unsigned char * mbed_stack_isr_start;
00443 
00444     mbed_stats_heap_t      heap_stats;
00445 
00446     mbed_stats_heap_get(&heap_stats);
00447 
00448     DPL("     heap ( start: ");
00449     debug_print_pointer(mbed_heap_start);
00450 
00451     DPL(" end: ");
00452     debug_print_pointer(mbed_heap_start + mbed_heap_size);
00453 
00454     DPL(" size: ");
00455     debug_print_u32(mbed_heap_size);
00456 
00457     DPL(" used: ");
00458     debug_print_u32(heap_stats.max_size);
00459 
00460     DPL(" )  alloc ( ok: ");
00461     debug_print_u32(heap_stats.alloc_cnt);
00462 
00463     DPL("  fail: ");
00464     debug_print_u32(heap_stats.alloc_fail_cnt);
00465 
00466     DPL(" )\r\n");
00467 
00468     DPL("isr_stack ( start: ");
00469     debug_print_pointer(mbed_stack_isr_start);
00470 
00471     DPL(" end: ");
00472     debug_print_pointer(mbed_stack_isr_start + mbed_stack_isr_size);
00473 
00474     DPL(" size: ");
00475     debug_print_u32(mbed_stack_isr_size);
00476 
00477 #if DEBUG_ISR_STACK_USAGE
00478     DPL(" used: ");
00479     debug_print_u32(calculate_isr_stack_usage());
00480 #endif
00481 
00482     DPL(" )\r\n");
00483 
00484 #if DEBUG_MEMORY_CONTENTS
00485     // Print ISR stack contents.
00486     print_memory_contents(&__StackLimit, &__StackTop);
00487 #endif
00488 #endif
00489 }
00490