Giter Site home page Giter Site logo

locoduino / memoryusage Goto Github PK

View Code? Open in Web Editor NEW
21.0 21.0 7.0 836 KB

This is a library for Arduino to see memory usage during a program execution.

Home Page: http://www.locoduino.org

License: GNU General Public License v2.0

Batchfile 0.04% HTML 55.67% CSS 15.26% JavaScript 23.61% C++ 5.42%
arduino arduino-library memory-management

memoryusage's People

Contributors

trusty77 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

memoryusage's Issues

It would be nice for MemoryUsage to provide numeric values (enhancement)

The MemoryUsage macros provide good insight into what is happening with RAM storage.

But it would be nice to have the library return numeric values, too. This could be used in different ways:

  • A sketch can print values in decimal or hex (or both)
  • A sketch can customize the output text
  • A sketch can send output to somewhere other than Serial
  • A sketch can do more than just print the information collected. For example a sketch could safely restart itself if it detected a memory leak (before it crashes).

I have created a pull request #7 which could help with this suggestion. Please let me know if you have questions or concerns.

MEMORY_PRINT_TOTALSIZE is off by one byte

This is for an Arduino UNO, which has 2048 bytes of total RAM.

Run the following sketch "GetMemoryTotalSize.ino":

#include <MemoryUsage.h>

// Simple example to report memory TOTAL size

void setup() {
    Serial.begin(115200);
    delay(1000);
    Serial.println(F( "Running " __FILE__ ", Built " __DATE__));
    Serial.println();

    MEMORY_PRINT_TOTALSIZE
}

void loop() {
    // User reads output from setup().
}

Your serial monitor generates an output something like this:

Running C:\Users\philk\OneDrive\Documents\Arduino\GetMemoryTotalSize\GetMemoryTotalSize.ino, Built Jun  4 2021

SRAM size:2047

NOTE: The RAM size reported is 2047 bytes (not 2048 bytes).

This is because the END macro returns the address of the last byte of RAM (not the byte after it). So beginning and end are inclusive limits.
It is harder to recognize problem because the start of RAM is at 0x100, so it's harder to tell where 2k byte RAM boundaries should really belong (particularly as decimal numbers).

See #4 for a fix.

Wrong free ram size

+----------------+ 256 (__data_start)
+      data      +
+    variables   + size = 264
+----------------+ 520 (__data_end / __bss_start)
+      bss       +
+    variables   + size = 673
+----------------+ 1193 (__bss_end / __heap_start)
+      heap      + size = 0
+----------------+ 1193 (__brkval if not 0, or __heap_start)
+                +
+                +
+   FREE RAM     + size = -15
+                +
+                +
+----------------+ 2801 (SP)
+     stack      + size = 15
+----------------+ 2815 (RAMEND / __stack)

FREE RAM size does not display the free ram size, it displays the negative stack size.

Example sketches always report the same values?

Hi. Thank you for publishing this library. I wanted to make something similar, but it was good to see you had a library already available!

Unfortunately, I have not been able to get MemoryUsage to report any changing values for the example sketches (or for my own sketches). I expected the examples to report changing values as storage was allocated and released. Am I using the library incorrectly?

My environment:

  • Windows 10 build computer
  • Arduino IDE 1.8.13
  • board family: "Arduino AVR Boards" v1.8.3
  • Board: "Arduino Uno"
  • Library: MemoryUsage v2.21.0 (fresh today)

I tried to run the example sketches "FreeRam" and "Stack".

NOTE 1:
The MemoryUsage examples are under File/Examples/INCOMPATIBLE/MemoryUsage...

  • Are these examples really incompatible with "Arduino Uno"?
  • I have other libraries compatible with the AVR architecture -- in these other libraries their library.properties files declare "architectures=avr" -- they declared "avr" in lower case. Should "avr" be declared lower case for MemoryUsage too?

The examples seemed to compile anyway.

NOTE 2: Stack.ino

Stack.ino builds with the following warning:

WARNING: library MemoryUsage claims to run on AVR architecture(s) and may be incompatible with your current board which runs on avr architecture(s).
C:\Users\philk\OneDrive\Documents\Arduino\libraries\MemoryUsage\src\MemoryUsage.cpp: In function 'uint16_t mu_StackCount()':
C:\Users\philk\OneDrive\Documents\Arduino\libraries\MemoryUsage\src\MemoryUsage.cpp:76:39: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  while (*p == STACK_CANARY && (int) p <= SP)
                                       ^
Sketch uses 5262 bytes (16%) of program storage space. Maximum is 32256 bytes.
Global variables use 286 bytes (13%) of dynamic memory, leaving 1762 bytes for local variables. Maximum is 2048 bytes.

The sketch output gives values that never change. For example stack size is always 1256 bytes:

Starting state of the memory:

Data start:256
Heap start:542
Heap end:542
Stack start:1047
Stack end:2303
Stack size:1256
Stack Maximum Size (Painting method): 1761


subPointer
Test string
Stack start:1047
Stack end:2303
Stack size:1256
Stack Maximum Size (Instrumentation method): 1256

subSmartPointer
Test string
Stack start:1047
Stack end:2303
Stack size:1256
Stack Maximum Size (Instrumentation method): 1256

subConstSmartPointer
Test string
Stack start:1047
Stack end:2303
Stack size:1256
Stack Maximum Size (Instrumentation method): 1256

subFull
Test string
Stack start:1047
Stack end:2303
Stack size:1256
Stack Maximum Size (Instrumentation method): 1256

subLocalData
10.00
Stack start:1047
Stack end:2303
Stack size:1256
Stack Maximum Size (Instrumentation method): 1256

Stack Maximum Size (Painting method): 1761


Ending state of the memory:

Data start:256
Heap start:542
Heap end:542
Stack start:1047
Stack end:2303
Stack size:1256

These values were supposed to change (at least temporarily), correct?

NOTE 3: FreeRam.ino

FreeRam.ino builds with the following warning:

WARNING: library MemoryUsage claims to run on AVR architecture(s) and may be incompatible with your current board which runs on avr architecture(s).
C:\Users\philk\OneDrive\Documents\Arduino\libraries\MemoryUsage\examples\FreeRam\FreeRam.ino: In function 'void setup()':
C:\Users\philk\OneDrive\Documents\Arduino\libraries\MemoryUsage\examples\FreeRam\FreeRam.ino:21:11: warning: unused variable 'p' [-Wunused-variable]
     byte *p = new byte[3000];
           ^
C:\Users\philk\OneDrive\Documents\Arduino\libraries\MemoryUsage\src\MemoryUsage.cpp: In function 'uint16_t mu_StackCount()':
C:\Users\philk\OneDrive\Documents\Arduino\libraries\MemoryUsage\src\MemoryUsage.cpp:76:39: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  while (*p == STACK_CANARY && (int) p <= SP)
                                       ^
Sketch uses 2458 bytes (7%) of program storage space. Maximum is 32256 bytes.
Global variables use 192 bytes (9%) of dynamic memory, leaving 1856 bytes for local variables. Maximum is 2048 bytes.

The sketch output gives values that never change. For example the free RAM size is always 1850 bytes:

Starting state of the memory:

Data start:256
Heap start:448
Heap end:448
Stack start:2297
Stack end:2303
Heap size:0


Free Ram Size: 1850


Ending state of the memory:

Data start:256
Heap start:448
Heap end:448
Stack start:2297
Stack end:2303
Heap size:0


Free Ram Size: 1850

Again, these values were supposed to change (at least temporarily), correct?

FreeRam.ino example "p = new byte[3000]" failure does not show free RAM can change

This is for an Arduino Uno, which has only 2048 bytes RAM available.

The problem is really in examples/FreeRam/FreeRam.ino, but its output is harder to interpret.

The actual issue is on FreeRam.ino line 21:

    ...
   byte *p = new byte[3000];    
    ...

Since there is only 2k RAM available this allocation will fail on an Uno. On failure, nothing gets allocated on the heap, and the heap size does not change. This is not not so interesting for an example.

I found a smaller array size made FreeRam.ino more interesting:

    ...
   byte *p = new byte[300];    
    ...

See #4 for a pull request to make this allocation request successful.

For a more direct demonstration the heap growing and shrinking, I wrote GetMemorySize.ino:

#include <MemoryUsage.h>

// Simple example to report memory sizes

void reportAllocation(int numBytes) {

    Serial.print(F("Allocating for "));
    Serial.print( numBytes );
    Serial.print(F(" bytes; "));
    
    byte *p = new byte[numBytes];

    if (p) {
        Serial.println(F("...success."));
    } else {
        Serial.println(F("...allocation FAILED"));
    }

    MEMORY_PRINT_HEAPSIZE
    FREERAM_PRINT

    Serial.println(F("\ndeleting byte array with delete"));
    delete p;   // don't want a memory leak!
    p = 0;      // don't want a dangling/obsolete pointer

    MEMORY_PRINT_HEAPSIZE
    FREERAM_PRINT
}

void setup() {
    Serial.begin(115200);
    delay(1000);
    Serial.println(F( "Running " __FILE__ ", Built " __DATE__));

    Serial.println(F("\nStarting conditions"));
    MEMORY_PRINT_TOTALSIZE
    MEMORY_PRINT_HEAPSIZE
    FREERAM_PRINT

    Serial.println(F("\nallocate a byte array with new; too big to fit in RAM?"));
    reportAllocation(3000);

    Serial.println(F("\nallocate smaller byte array with new (it should fit)"));
    reportAllocation(300);

    Serial.println(F("\nFinal conditions"));
    MEMORY_PRINT_HEAPSIZE
    FREERAM_PRINT
}

void loop() {
    // User reads output from setup().
}

Tip: Understanding memory usage with the compiler optimizer

(I am pulling out this comment from #3 as its own topic as I think it will be helpful.)

After compiler optimization many expected side effects can disappear:

  • aggressive inlining of functions means the stack pointer may never change with a function call. This can be useful if RAM space is small, and there is plenty of ROM for code -- like for the AVR architecture.
  • the compiler may keep variables in registers, so again the stack pointer may never need to change
  • the compiler seems to detect "unused/unchanged" values and not bother generating code for them.

This is all good in principle. But the optimizations make it difficult to predict how much stack space is needed, just by inspection. Even for a simple example. Often nothing seems to change, especially for simple examples.

I was able to get more predictable results by:

  • declaring functions noinline, for example void __attribute__ ((noinline)) myStackUsingFunction(void) {...};. This ensures the function call will exercise the stack so this library can observe it.
  • declaring variables volatile, which hints to the compiler it should manipulate the variable (and put it on the stack), even if it seems unnecessary.

Note that noinline and volatile declarations make memory usage more predictable, but less efficient. It may be useful while you are still debugging your code. Once you are done debugging your memory allocations, you might want to take the declarations out so the optimizers can help free up RAM storage.

painted stack measure do not work

The routine mu_StackPaint is not executed in section .init1
I use platformio and board = 1284p16m
better results with this approach:
https://www.avrfreaks.net/comment/1314296#comment-1314296
with little modification to take in account heap:

extern uint8_t _end;

void simpleStackPaint(void)
{
    uint8_t *p = &_end;

    while(p < (uint8_t*)&p)
    {
        *p = 0xc5;
        p++;
    }
} 

uint16_t simpleStackCount(void)
{
  const uint8_t *p =  (int) (__brkval == 0 ? (uint8_t *) &__heap_start : __brkval);
  //const uint8_t *p = &_end;
    uint16_t       c = 0;

    while(*p == 0xc5 && p < (uint8_t*)&p)
    {
        p++;
        c++;
    }

    return c;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.