diff --git a/MemoryUsage.cpp b/MemoryUsage.cpp new file mode 100644 index 0000000..745e714 --- /dev/null +++ b/MemoryUsage.cpp @@ -0,0 +1,72 @@ +/* +MemoryUsage.c - MemoryUsage library +Copyright (c) 2015 Thierry Paris. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "Arduino.h" +#include "MemoryUsage.h" + +// Thanks to adafruit : https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory +int mu_freeRam() +{ + //extern int __heap_start, *__brkval; + int v; + return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval); +} + +// Copy / adaptation of the library StackPaint available here : https://github.com/WickedDevice/StackPaint + +#define STACK_CANARY 0xc5 + +void mu_StackPaint(void) __attribute__((naked)) __attribute__((section(".init1"))); + +void mu_StackPaint(void) +{ +#if 1 + uint8_t *p = &_end; + + while (p <= &__stack) + { + *p = STACK_CANARY; + p++; + } +#else + __asm volatile ( + " ldi r30,lo8(_end)\n" + " ldi r31,hi8(_end)\n" + " ldi r24,lo8(0xc5)\n" // STACK_CANARY = 0xc5 + " ldi r25,hi8(__stack)\n" + " rjmp .cmp\n" + ".loop:\n" + " st Z+,r24\n" + ".cmp:\n" + " cpi r30,lo8(__stack)\n" + " cpc r31,r25\n" + " brlo .loop\n" + " breq .loop"::); +#endif +} + +uint16_t mu_StackCount(void) +{ + uint8_t *p = (__brkval == 0 ? (uint8_t *) &__heap_start : __brkval); + + while (*p == STACK_CANARY && (int) p <= SP) + p++; + + return (uint16_t)RAMEND - (uint16_t)p; +} diff --git a/MemoryUsage.h b/MemoryUsage.h index db6b30e..09fb956 100644 --- a/MemoryUsage.h +++ b/MemoryUsage.h @@ -1,5 +1,5 @@ /* -MemoryUsage.h - MemoryUsage library +MemoryUsage.h - MemoryUsage library V2.0 Copyright (c) 2015 Thierry Paris. All right reserved. This library is free software; you can redistribute it and/or @@ -20,37 +20,88 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __MemoryUsage_h__ #define __MemoryUsage_h__ -// Must be used only one time, outside any function. -#define STACK_DECLARE byte *stack_end_max; +#include + +/* +Roughly, the SRAM memory is divided into four areas: the static data, the heap, the free ram and the stack. +The static data size is given by the compiler itself after the building. this is filled by all variables and +arrays declared in global scope, or with 'static' keyword. +The heap is filled with all the dynamic allocations done with 'new' keyword or 'malloc' functions. +The stack start from the end of the SRAM area and grow and shrink downward at each function call. + +SRAM memory ++---------------+------------------+---------------------------------------------+-----------------+ +| | | | | +| | | | | +| static | | | | +| data | heap | free ram | stack | +| | | | | +| | | | | +| | | | | ++---------------+------------------+---------------------------------------------+-----------------+ + _end or __heap_start __brkval SP RAMEND + +Source : http://www.nongnu.org/avr-libc/user-manual/malloc.html +*/ + +extern uint8_t _end; +extern uint8_t __stack; +extern uint8_t *__brkval; +extern uint8_t *__data_start; +extern uint8_t *__heap_start; + +// +// Memory addresses +// + +#define MEMORY_PRINT_START { Serial.print(F("Data start:")); Serial.println((int) &__data_start); } +#define MEMORY_PRINT_HEAPSTART { Serial.print(F("Heap start:")); Serial.println((int)&__heap_start); } +#define MEMORY_PRINT_HEAPEND { Serial.print(F("Heap end:")); Serial.println(__brkval == 0 ? (int)&__heap_start : (int)__brkval); } +#define MEMORY_PRINT_STACKSTART { Serial.print(F("Stack start:")); Serial.println((int) SP); } +#define MEMORY_PRINT_END { Serial.print(F("Stack end:")); Serial.println((int) RAMEND); } + +#define MEMORY_PRINT_HEAPSIZE { Serial.print(F("Heap size:")); Serial.println((int) (__brkval == 0 ? (int)&__heap_start : (int)__brkval) - (int)&__heap_start); } +#define MEMORY_PRINT_STACKSIZE { Serial.print(F("Stack size:")); Serial.println((int) RAMEND - (int)SP); } + +// +// Stack count part. STACK_COMPUTE will get the maximum size of the stack at the moment... +// -// Must be used inside a function, as soon as possible, basicaly at the beginning of the setup(). -// Can be recalled at any time to reset the stack counter and have a local count of stack bytes. -#define STACK_START byte b_Stack; stack_end_max = &b_Stack; +// Must be used only one time, outside any function. +#define STACK_DECLARE unsigned int mu_stack_size = (RAMEND - SP); -// Must be call to update the current maximum size of the stack, at each function beginning. -#define STACK_COMPUTE { byte b_Stack; \ - byte *stack_local_end = &b_Stack; \ - if ((int) stack_local_end < (int) stack_end_max)\ - stack_end_max = stack_local_end; } +// Must be called to update the current maximum size of the stack, at each function beginning. +#define STACK_COMPUTE { mu_stack_size = (RAMEND - SP) > mu_stack_size ? (RAMEND - SP) : mu_stack_size;} // Compute the current maximum and show it now with customized text. -#define STACK_PRINT(text) { STACK_COMPUTE; Serial.print(text); Serial.println(RAMEND - (int) stack_end_max); } +#define STACK_PRINT_TEXT(text) { STACK_COMPUTE; Serial.print(text); Serial.println(mu_stack_size); } // Compute the current maximum and show it now with default text. -#define STACK_PRINT STACK_PRINT(F("Stack Size:")); +#define STACK_PRINT STACK_PRINT_TEXT(F("Stack Maximum Size (Instrumentation method): ")); + +// +// Free Ram part. +// // Shows the current free SRAM memory with customized text. -#define FREERAM_PRINT(text) Serial.print(text); Serial.println(freeRam()); +#define FREERAM_PRINT_TEXT(text) Serial.print(text); Serial.println(mu_freeRam()); // Shows the current free SRAM memory with default text. -#define FREERAM_PRINT FREERAM_PRINT(F("Free Ram Size:")); - -// Thanks to adafruit : https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory -int freeRam () -{ - extern int __heap_start, *__brkval; - int v; - return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); -} +#define FREERAM_PRINT FREERAM_PRINT_TEXT(F("Free Ram Size: ")); + +int mu_freeRam(void); + +// +// StackPaint part. This macro gives a view of used stack area at the end of execution... +// + +uint16_t mu_StackCount(void); + +// Compute the current maximum and show it now with customized text. +#define STACKPAINT_PRINT_TEXT(text) { Serial.print(text); Serial.println(mu_StackCount()); } + +// Compute the current maximum and show it now with default text. +#define STACKPAINT_PRINT STACKPAINT_PRINT_TEXT(F("Stack Maximum Size (Painting method): ")); + #endif diff --git a/examples/FreeRam/FreeRam.ino b/examples/FreeRam/FreeRam.ino index ef29831..9af5fe5 100644 --- a/examples/FreeRam/FreeRam.ino +++ b/examples/FreeRam/FreeRam.ino @@ -3,14 +3,43 @@ void setup() { Serial.begin(115200); + Serial.println(F("Starting state of the memory:")); + Serial.println(); + + MEMORY_PRINT_START + MEMORY_PRINT_HEAPSTART + MEMORY_PRINT_HEAPEND + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_HEAPSIZE + + Serial.println(); + Serial.println(); + FREERAM_PRINT; byte *p = new byte[3000]; + Serial.println(); + Serial.println(); + + Serial.println(F("Ending state of the memory:")); + Serial.println(); + + MEMORY_PRINT_START + MEMORY_PRINT_HEAPSTART + MEMORY_PRINT_HEAPEND + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_HEAPSIZE + + Serial.println(); + Serial.println(); + FREERAM_PRINT; } void loop() { -} +} \ No newline at end of file diff --git a/examples/Stack/Stack.ino b/examples/Stack/Stack.ino index c795725..084c8d0 100644 --- a/examples/Stack/Stack.ino +++ b/examples/Stack/Stack.ino @@ -1,6 +1,6 @@ #include -STACK_DECLARE; +STACK_DECLARE // Dummy structure sample, with a complex content... struct rhaaa @@ -23,71 +23,132 @@ void setup() // some string to see how to access to it inside functions ! rhaaa sample; strcpy(sample.text, "Test string"); + for (int i = 0; i < 50; i++) + sample.ival[i] = i; + for (int i = 0; i < 10; i++) + sample.dval[i] = (double) i; + + Serial.println(F("Starting state of the memory:")); + Serial.println(); - { - // First attempt, just pass the structure. The full content is duplicated on the stack. - // If the sub function modifies the content, the original structure from the caller - // function will not be affected. - STACK_START; - STACK_PRINT(F("Stack Size start:")); - subFull(sample); - } - - { + MEMORY_PRINT_START + MEMORY_PRINT_HEAPSTART + MEMORY_PRINT_HEAPEND + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_STACKSIZE + + STACKPAINT_PRINT + + Serial.println(); + Serial.println(); + // Here we pass a pointer to the original structure instance. // Only this pointer is added to the stack. // The content is fully modifiable by the sub function. // This is the best way to let a sub funtion modify an argument. - STACK_START; - STACK_PRINT(F("Stack Size start:")); subPointer(&sample); - } - { // Here also, this is a pointer which is passed, but the sub function see its argument // as a normal data, not a pointer. Be careful here because the sub function can modify // the structure content and because this is not a pointer syntax, you can believe that // you only modify a copy ! - STACK_START; - STACK_PRINT(F("Stack Size start:")); subSmartPointer(sample); - } - { // You have here the best way to pass a structure if you dont want to modify it. // Only a pointer is added to the stack, and any try to modify the struture content // will be detected as an error by the compiler. - STACK_START; - STACK_PRINT(F("Stack Size start:")); subConstSmartPointer(sample); - } + + // Just pass the structure. The full content is duplicated onto the stack. + // If the sub function modifies the content, the original structure from the caller + // function will not be affected. + subFull(sample); + + // No data as argument, nut a nig array of doubles inside the function... + subLocalData(); + + STACKPAINT_PRINT + + Serial.println(); + Serial.println(); + + Serial.println(F("Ending state of the memory:")); + Serial.println(); + + MEMORY_PRINT_START + MEMORY_PRINT_HEAPSTART + MEMORY_PRINT_HEAPEND + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_STACKSIZE + + Serial.println(); + Serial.println(); } void subFull(rhaaa aSample) { + Serial.println("subFull"); Serial.println(aSample.text); - STACK_PRINT(F("Stack Size subFull:")); + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_STACKSIZE + STACK_PRINT + Serial.println(); } void subPointer(rhaaa *apSample) { + Serial.println("subPointer"); Serial.println(apSample->text); - STACK_PRINT(F("Stack Size subPointer:")); + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_STACKSIZE + STACK_PRINT + Serial.println(); } void subSmartPointer(rhaaa &aSample) { + Serial.println("subSmartPointer"); Serial.println(aSample.text); - STACK_PRINT(F("Stack Size subSmartPointer:")); + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_STACKSIZE + STACK_PRINT + Serial.println(); } void subConstSmartPointer(const rhaaa &aSample) { + Serial.println("subConstSmartPointer"); Serial.println(aSample.text); - STACK_PRINT(F("Stack Size subConstSmartPointer:")); + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_STACKSIZE + STACK_PRINT + Serial.println(); +} + +#define SIZE 200 +void subLocalData() +{ + Serial.println("subLocalData"); + double v[SIZE]; + + for(int i = 0; i < SIZE; i++) + v[i] = (double)i; + + Serial.println(v[10]); + MEMORY_PRINT_STACKSTART + MEMORY_PRINT_END + MEMORY_PRINT_STACKSIZE + STACK_PRINT + Serial.println(); } void loop() { -} +} \ No newline at end of file diff --git a/library.properties b/library.properties index d59cc79..2bbb2d5 100644 --- a/library.properties +++ b/library.properties @@ -2,8 +2,8 @@ name=MemoryUsage version=1.0.0 author=Thierry PARIS maintainer=Thierry PARIS -sentence=Use this library to check your memory usage. +sentence=Use this library to check your SRAM / Stack memory usage. paragraph= -category=Memory +category=Uncategorized url=https://github.com/adafruit/Adafruit-GFX-Library architectures=*