Memory Status and Monitoring

Status
Not open for further replies.

cyborgv2

Member
Hi all,

I am developing a project using a Teensy 3.1; using a lot of dynamic memory allocations. With this in mind, I've written a small class that provides memory information simply. Using the initialize() and run() functions, the class monitors stack usage, simulates stack allocation and provides a low memory warning.

I'm wondering if this class would be of use to anyone else projects...

Cheers,
Adrian

Update: Now on SourceForge -
https://sourceforge.net/projects/teensy-3-x-rammonitor

class RamMonitor {
int32_t unallocated() const; // space between heap and stack (current): negitive if heap/stack crash
uint32_t stack_used() const; // stack size (current): grows into unallocated
uint32_t heap_total() const; // heap (dynamic mem) size: can grow into unallocated
uint32_t heap_used() const; // heap allocated
uint32_t heap_free() const; // free heap

int32_t free() const; // free ram: unallocated and unused heap
uint32_t total() const; // physical ram

// these functions (along with initialize and run)
// create the ellusion of stack allocation.
uint32_t stack_total() const; // stack size (historical)
int32_t stack_free() const; // calc stack usage before next stack growth
int32_t adj_unallocd() const; // space between heap and "alloc'd" stack: negitive if heap/stack crash
int32_t adj_free() const; // free ram: adjusted unallocated and unused heap

bool warning_lowmem() const; // returns true if stack and heap get close
bool warning_crash() const; // returns true if stack is in danger of overwriting heap

void initialize(); // initializes stack monitoring
void run(); // monitors stack and adjusted unallocated
};
 
Last edited:
Hey, that's awesome, so thanks for contributing it. I may have a use for it as I investigate why the LC running Roxanne, our humidifier, seems to get hung from time to time.
 
Hi,

That's cool Constantin (no pun intended! lol) Don't know the LC but I understand my code would work on a 3.0... so I see no reason it shouldn't work on the LC. Code still needs a tickle and better comments needed, if I'm to post it.
 
yes, I would love to check it out! I am running into memory problems and it would be great to have another tool to use.
 
It was the watchdog... Once I started kicking it every 10ms instead of every second, the system became stable.
 
I've tried to follow the wiki but I'm just learning...
Do I just add this code to my sketch or should it be "included as a dot h file.
Does initialize require the parameters StackAllocation and Lowmem and what sort of typical values?
For raw memory information can I just ... Serial.print(free);

Update
I have included it in my main sketch but this has introduced an error referring to the use of "min" function elsewhere in my code:

error: 'min' was not declared in this scope
 
Last edited:
Hey muggins

I've tried to follow the wiki but I'm just learning...
Do I just add this code to my sketch or should it be "included as a dot h file.
It's a c++ header, it is a .h file and as you say it's #include'd. Either copy to your project directory or may be in to a RamMonitor directory in your libraries. Using it as a library, means you don't have to copy it in to every project but (for older Arduino IDEs) you should (need) to add a #include <RamMonitor.h> to your .ino

Does initialize require the parameters StackAllocation and Lowmem and what sort of typical values?
Initialize method does not take any parameters!?. STACKALLOCATION and LOWMEM are static const within my code and are set with reasonable default values (for Teensy 3.1/3.2), the values I use.

For raw memory information can I just ... Serial.print(free);
Yes, raw memory info can be retrieved without init and run calls. Values returned by the extended functions tend to be more useful.
Code:
RamMonitor ram;

void report_mem() {
  Serial.print("free RAM: ");
  Serial.print(ram.free() / 1024);
  Serial.println("Kb");
};

Update
I have included it in my main sketch but this has introduced an error referring to the use of "min" function elsewhere in my code:

error: 'min' was not declared in this scope
??? My code doesn't play around with namespaces ("scope") nor has anything to do with a min function... my guess, you're missing a close bracket ('}') somewhere in your code. Personally, so meny different implementations of the min and max functions, some not compatible, that I tend to use to avoid those and use high and low instead ;)
 
Last edited:
I really appreciate your comprehensive response. I've got it now. As for the extended set do I use ram.initialize?
Just for interest I still have the strange max/min error which only happens when I include the class. There are several items on the net referring to "broken" min/max. I have found a workaround. Thanks

#include "RamMonitor.h"
void setup() {
}
void loop() {
}
void CalcMax(){
int m;
m=max(5,7);
}
Hi
 
There is a conflict with the Audio library through <SD.h>

Code:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\SD/utility/SdFatUtil.h:39:15: error: type mismatch with previous external decl of 'int* __brkval' [-fpermissive]
extern int* __brkval;
 
Once I changed

Code:
extern char* __brkval;

to

Code:
extern int* __brkval;

and fixed all the subsequent type errors, it works well - thank you.
 
I really appreciate your comprehensive response. I've got it now. As for the extended set do I use ram.initialize?
Just for interest I still have the strange max/min error which only happens when I include the class. There are several items on the net referring to "broken" min/max. I have found a workaround. Thanks
Thank you, try to be helpful.

Yes, extended methods require initialization... calling run method regularly, speeds other extended methods and updates memory warnings.

As for your max/min error; wonder if it has anything to do with malloc.h... no longer really supported but works on Teensy, Linux and Android!? Out for interest and may be nail this problem, what libraries are you using and how did you get around the min/max problem?

Cheers
 
The little bit of example code I uploaded breaks the min/max functionality ie no other libraries.
I found a workaround on the web
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
thanks
 
Once I changed

Code:
extern char* __brkval;

to

Code:
extern int* __brkval;

and fixed all the subsequent type errors, it works well - thank you.

Great, thanks for the compatibility mod... I'm using SdFat.h and didn't get this problem. Thanks to a failing power pack, my Teensy has been fried, they don't work at 9v! lol Ordering a 3.2 tomorrow; I'll check the int* compatiblity as soon as I can and update the header :)
 
The little bit of example code I uploaded breaks the min/max functionality ie no other libraries.
I found a workaround on the web
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
thanks
Thanks... that's basically the default def, old school.
 
Last edited:
There is a conflict with the Audio library through <SD.h>

Code:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\SD/utility/SdFatUtil.h:39:15: error: type mismatch with previous external decl of 'int* __brkval' [-fpermissive]
extern int* __brkval;
Could SD.h be using unallocated memory for buffers; would save allocation time but break RamMonitor once free memory got below the buffer size!
 
The little bit of example code I uploaded breaks the min/max functionality ie no other libraries.

Are you going to actually share the location of this code?

I found a workaround on the web
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))

Originally we had this in Teensyduino. Arduino's core library still had it.

The problem with this code is either "a" or "b" gets evaluated twice. If they're simple variables, that's fine. But when they're function calls, the function gets called twice. Likewise for volatile hardware registers.

For example:

int size = min(Serial.read(), 10);

You'd expect this code to read 1 byte, and give you either the byte, or 10 if the byte is higher than 10. But instead, it actually reads 2 bytes!

You might say "well don't do that", but indeed this problem has come up. That's why Teensyduino now uses this for min and max:

Code:
#define min(a, b) ({ \
  typeof(a) _a = (a); \
  typeof(b) _b = (b); \
  (_a < _b) ? _a : _b; \
})
#define max(a, b) ({ \
  typeof(a) _a = (a); \
  typeof(b) _b = (b); \
  (_a > _b) ? _a : _b; \
})
 
Very good point Paul :)

My high/low is implemented as templated inlined functions; the beauty of that is you can overload them for complex types, ie vectors. Also allow lhs but I've never found a reason to do that!

Code:
template <typename TYPE>
inline TYPE& low(TYPE& a0, TYPE& a1) { return (a0 < a1) ? a0 : a1; };
template <typename TYPE>
inline const TYPE& low(const TYPE& a0, const TYPE& a1) { return (a0 < a1) ? a0 : a1; };

In my mapping code I have 2D and 3D vector overloads:

Code:
inline Vector2D& low(Vector2D& a0, Vector2D& a1) { return (a0.size2() < a1.size2()) ? a0 : a1; };
 
Last edited:
Paul forgive me if I'm being stupid, but since I am compiling in Teensyduino why do I get the error.
 
but since I am compiling in Teensyduino why do I get the error.

I don't know. But as you can see in this other thread:

https://forum.pjrc.com/threads/33760-SD-card-issues-with-3-2?p=100782&viewfull=1#post100782

I compiled all 6 of the SD library examples without any errors.

So something must be different about what you're doing. If you want me to investigate, you have to post the complete code to reproduce the problem (the "Forum Rule" which appears in red at the top of every page). If you're using any other libs that don't come with Teensyduino, you have to post their code or give links to their downloads. Please, if you ask me to look into this, take an extra moment to make sure the info in your message really has *all* the necessary code and details. I'm crazy busy right now, and guessing what's missing is incredibly time consuming.
 
Hey Paul,

Know you're a busy man. Going to put some time in to this problem as soon as I can get to my desktop... nothing in my code would produce the results muggins is getting; best guess it's malloc.h
 
Paul
I am very grateful for help that you provide to all of us and really don't want to waste your valuable time.. I already posted a simple sketch in post #11 which throws up
" 'max' was not declared in this scope"
I was initially requesting help from "cyborgv2" who is the author of the RamMonitor class and instigator of this thread.
I have a workaround now so no worries.
thanks
PS I'm not using any SD libraries.
 
I just looked into this anyway.

Seems the trouble is caused by this line in RamMonitor.h:

Code:
#include <cstdint>

I'm not familiar with this file, or why it would interfere with the max() define from Arduino.h. But it does.

Commenting out that include seems to have no harmful effects. Maybe RamMonitor doesn't actually use it?
 
Status
Not open for further replies.
Back
Top