modify freeRam() to find fragmentation

Is it possible to modfiy freeRam() to find the percent of freeRam that is fragmented?
To my understanding, freeRam finds out the total amount of free ram available, but it doesn't tell you jack about the largest space available which is frustrating.

I've seen a lot of post where people think fragmentation is the problem of their crashes, and it probably is, but I realize how helpful freeRam() is, and I think this would be a very helpful piece of code for a lot of people.

Heres what I was thinking create a function called fragmentedRam() which first uses freeRam() to find out total freeRam finds and then it runs a modified verson of freeRam which finds the largest whole chunk of memory available. So if freeRam() returned 100, and the modifed verson of freeRam found that the largest chunk of whole memory was 80 then it would find the percentage of fragmentedRam by 100/(100-80) which is 20 then it would return that value.

To sum it up, fragmentedRam() returns the amount of freeRam fragmented, or you could make it so it returns 80 so you know the actual largest chunk size of memory you have left to play with.

I'm still learning though, I don't quite understand how freeRam works, so I cant modify it myself yet. Is this possible to do though? Here are my notes that i've taken from Bucky's Buckys youtube c++ classes

void loop() {}

  int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);  
}
/* 
// extern means the file is located in an external library
// & is an address reference. When you see & it isn't returning a copy, it's sending the acutal address
// * is called pointer and is basically  memory address and is needed before the name of an int is to send the reference
// example 
void passByReference(int *x);
int main()
{
  int betty = 13;
  int sandy = 13;
  passByValue(betty);
  passByReference(&sandy); // symbol for memory address long hex address on computer
  Serial.print(F("betty is now"));
  Serial.println(betty);
  Serial.print(sandy is now);
  Serial.println(sandy);
  // Serial monitor will print betty is now 13
  //                           sandy is now 66
}

void pass ByValue(int x)
{ x = 99;
}
void passByReference(int *x) // 
{
  *x=66;
}
   */
 /* another thing to remember, if you increment address pointer (*) it doesn't change the address it changes the element that it points to
    int main(){
    int bucky[5];
    int *bp0 = &bucky[0];
    int *bp1 = &bucky[1];
    int *bp0 = &bucky[2];
    Serial.print(F("bp0 is at "));
    Serial.println(bp0);
    Serial.print(F("bp1 is at "));
    Serial.println(bp1);
    Serial.print(F("bp2 is at "));
    Serial.println(bp2);
    bp0+=2;
    Serial.print(F("bp0 is now at "));
    Serial.println(bp0);
   
    // Serial monitor will say bp0 is at 0x28ff00 // each int takes up four bytes
    //                         bp1 is at 0x28ff04 
    //                         bp2 is at 0x22ff08
    //                         bp0 is at 0x28ff08 // it didn't increment address, it only incremented element. so intead of adding 2 to the address itsef, it looked for 2 past the current element
    */

I also know that anything with a __ in front of it is private, or suppose to be anyway.

So using

int freeRam() {
extern int
int v;
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);
}

I know that int freeRam() returns an int.
extern int means that it's an int from an extern library (probably arduino.h) but its strange that it doesn't list the name of the int beside it...
int v creates an int but the interesting part is the bottom line
freeRam() returns the memory address of v (which it just created) minus... and that's as much as I know right now. I know (int)&__heap_start is the memory address of the heap start but I don't understand how the red below works.
(__brkval == 0 ? (int)&__heap_start : (int) __brkval); I haven't finished the videos yet, i'm only on number 48, but I figured I'd go ahead and ask if this was possible, and if anyone would be interested in helping.

Look what's on my ctrl-V buffer: https://www.arduino.cc/en/Tutorial/Memory You've probably read that already.

Do you know the difference between heap and stack? They start at opposite ends of memory and grow towards each other as memory is consumed. freeRam() just finds out how big the gap is. It actually doesn't report the total size of the gaps available.

To find out how big the largest piece of unallocated memory is, you just progressively malloc() and free() bigger and bigger chunks until malloc() returns a failure code.

All of that is academic. For an Arduino program, you should know what chunks you have malloc()ed and free()d so you should be able to determine what gaps got created just by looking at the code. Your memory management needs to be a lot more basic than just running until the operating system tells you you're out of memory. (Hint: there is no operating system.)

MorganS:
To find out how big the largest piece of unallocated memory is, you just progressively malloc() and free() bigger and bigger chunks until malloc() returns a failure code.

That is about the least efficient way possible to do it. Heap memory is pretty much always managed with a linked list. Each block of free memory will be preceded by a structure that describes that block, and links to any other blocks. By malloc'ing a single block of even a single byte, and knowing what that structure looks like, you can access the structure, and walk the list, to see how many blocks there are, how large they are, and where in memory they are. To be able to do that, you need to look at the malloc source code in the Arduino core code.

Regards,
Ray L.

This thread could be interresting: Avrheap class - peek into the heap

Look what's on my ctrl-V buffer: https://www.arduino.cc/en/Tutorial/Memory You've probably read that already.

I have read that, and just re-read it twice. I didn't see a reference to ctrl-V though and I do have a question about the link. It says

an int takes up two bytes, while a byte uses only one (but can store a smaller range of values).

I was under the impression that ints on the uno took up 16 bytes, and 32 bytes on the Due. Is that a typo or am I mistaken? And how can a byte store a smaller range of values than a byte?

Do you know the difference between heap and stack?

I knew the basics of top and bottom and somewhat how they worked. I am watching a youtube Series now that explains it in very good detail which I have a question about. example from this youtube video (at 4:01 into video) I am trying to do the example on the arduino as I watch the video. I can't get this to compile. Odviously there is a difference in arduino.h and stdio.h but I don't know how to make it compatible. Can anyone point me in the right direction?

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {
int a = 10;
int *p;
p = &a;
//Serial.print("%d\n",p);  // Method used in example
Serial.print("%d\n");      // tried to break it up to make compiler work
Serial.print(p);           // this is where compiler complains
//Serial.print("%d\n",*p); // second part of example
}

They start at opposite ends of memory and grow towards each other as memory is consumed. freeRam() just finds out how big the gap is. It actually doesn't report the total size of the gaps available.

Is freeRam accurate then? for example

address 0 // used
address 1 // used
address 2 // first block free
address 3 // free
address 4 // free
address 5 // free
address 6 // used (at one point 7 and 8 were used, then they cleared up but by then 6 was used)
address 7 // free
address 8 // first block free
address 9 // used
address 10 // used

so you are saying free ram measures the distance from the first free block on both sides which are 2, and 8 so freeRam thinks 6 are available, but it doesn't check to see if any in between are used (in this case 6 is used) so the real freeRam would be 5?

Heap memory is pretty much always managed with a linked list.

At the top correct?

This thread could be interesting: Avrheap class - peek into the heap

Looks like someone beat me to it. I like this! I will not stop until I understand what everything in this library does though. By the way... Is there a way to save quick references to pages on the arduino forum that you decide are worth saving, with notes beside them? I would like to be able to reference this page quickly in the future, as well as Robins Tutorials, but I don't like having to go back and look at all the past message threads I've reponded to to find them. Is there a way to post them so that it's something like (updated post) that shows you which threads you decided were worth bookmarking?

I was under the impression that ints on the uno took up 16 bytes, and 32 bytes on the Due. Is that a typo or am I mistaken?

No. That page was not updated after the Due was developed.

And how can a byte store a smaller range of values than a byte?

That quote does not say that. It says that a byte is smaller than an int. Hence, a byte can store a smaller range of values than an int.

Integers take 16 bits, not 16 bytes (on the Uno). It's architecture dependent though. 16 bits on a 16 bit architecture, 32 bits on 32 bit architecture. Longs are the next step up and double size of integers. To make it more complicsted, there are also short integers :wink:

I have seen systems though where long and int are the same size. Possibky a case of compatibility in the C language. I always check using the sizeof() operator.

sterretje:
Integers take 16 bits, not 16 bytes (on the Uno). It's architecture dependent though. 16 bits on a 16 bit architecture, 32 bits on 32 bit architecture. Longs are the next step up and double size of integers. To make it more complicsted, there are also short integers :wink:

I have seen systems though where long and int are the same size. Possibky a case of compatibility in the C language. I always check using the sizeof() operator.

The c language specification does NOT define the size of any data types - that is left up to the specific compiler implementation. An int could be 13 bits, and a char 37 bits, if someone cared to implement it that way, and it would still comply with the c specifications. This is why non-standard types, like uint16_t, are defined, so you can use platform and compiler independent types. a uint16_t will be ALWAYS be 16 bits, regardless of what "int" is on a particular platform.

Regards,
Ray L.

regarding the youtube video question I had, how do I print the address using arduino?
This is what i'm trying, but it doesn't change the address even if I add another int before I put in int a.

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {
// int b =20; // add to try to change address of a
int a=10;

int *p;
p = &a;
//Serial.print("%d\n",p); // Method used in example
//Serial.print("%d\n");      // tried to break it up to make complier work
//Serial.print(p);  
 // for (int i = 0; i < 10; i++)
 // {
 //   p[i] = (int*) malloc(i * 3);  // all different sizes
 //   *p[i] = 0;
 //   Serial.print(i);
 //   Serial.print('\t');
    Serial.println((int)p/*[i]*/, DEC);
 // }
Serial.println();
// this is where complier complains
//Serial.print("%d\n");
Serial.println(*p); // second part of example
}
//Serial.print("%d\n",p); // Method used in example

The method used in what example? That is nonsense on the Arduino. Quit trying to do this shit.

Whandall:
This thread could be interresting: Avrheap class - peek into the heap

+1 (of course)

The method used in what example?

post 4 that youtube video I referenced with the code below where i was trying to follow it. I don't want to do it that way anyway. It's confusing that way. I'm just trying to find a tutorial that can help me figure out how the fragmentation library works. Most tutorials for pointers are written for standard C++ and not for the arduino.

How do I print the address of the memory used?

How do I print the address of the memory used?

int thisVariableHasAnAddress;
Serial.print(&thisVariableHasAnAddress);
int *thisIsAPointer = thisVariableHasAnAddress;
// It now points to thisVariableHasAnAddress

Which address do you now want to print? That of the pointer or that of what it points to?

RayLivingston:
The c language specification does NOT define the size of any data types - that is left up to the specific compiler implementation. An int could be 13 bits, and a char 37 bits, if someone cared to implement it that way, and it would still comply with the c specifications.

Not quite.

An int must support the range -32767..32767, which effectively means it must be at least 16 bits wide on a binary computer. Similarly, a long must support the range -2147483647..2147483647, or at least 32 bits wide. (Those ranges easily allow for one's complement and sign/magnitude systems.)

Also, there are constraints on the relative sizes of types: sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long) <= sizeof (long long).

RayLivingston:
This is why non-standard types, like uint16_t, are defined, so you can use platform and compiler independent types. a uint16_t will be ALWAYS be 16 bits, regardless of what "int" is on a particular platform.

I believe that true unless (and there is alway an 'unless') the smallest addressable unit of memory is larger than 16 bits (using your example).

Which address do you now want to print? That of the pointer or that of what it points to?

Both preferably. But I figured out how to print what it points to, I need to figure out how to print the pointer.

int thisVariableHasAnAddress;
Serial.print(&thisVariableHasAnAddress);

I tried that before I asked on here. The youtube examples do it this way too. But I get this error message

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:66:12: note: size_t Print::print(long unsigned int, int)

size_t print(unsigned long, int = DEC);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:66:12: note: no known conversion for argument 1 from 'int*' to 'long unsigned int'

exit status 1
call of overloaded 'print(int*)' is ambiguous

christop:
Not quite.

An int must support the range -32767..32767, which effectively means it must be at least 16 bits wide on a binary computer. Similarly, a long must support the range -2147483647..2147483647, or at least 32 bits wide. (Those ranges easily allow for one's complement and sign/magnitude systems.)

Also, there are constraints on the relative sizes of types: sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long) <= sizeof (long long).

Not so fast... There are as many c specifications as Carter has little liver pills. You're talking about some of the many later c specifications (C99, ANSI, etc.), which differ greatly even from each other. Original K&R c contained only a few simple types, with no hard and fast definitions of their sizes. In fact, IIRC, it ran on a DEC PDP-8, which was a 12-bit machine, so would not likely have used a 16-bit data type for much of anything.

From Kernighans "The C Programming Language":

2.2 Data Types and Sizes

There are only a few basic data types in C:
char a single byte, capable of holding one character in the local character set
int an integer, typically reflecting the natural size of integers on the host machine
float single-precision floating point
double double-precision floating point

Remember, c was first implemented on a DEC PDP-8, which has a
Regards,
Ray L.

RayLivingston:
You're talking about some of the many later c specifications (C99, ANSI, etc.), which differ greatly even from each other.

All of the standards (C89, C99, C11) are virtually identical in the size limits of the basic types.

In fact, IIRC, it ran on a DEC PDP-8, which was a 12-bit machine, so would not likely have used a 16-bit data type for much of anything.

It was born on the PDP-11, a 16-bit machine.

The PDP-8 is not very well suited to C--for one, it has no stack--but a C compiler for the PDP-8 would likely have a 12-bit char, 24-bit short and int, and either a 36-bit or 48-bit long. Or it might have a 36-bit short, int, and long. It depends on the implementer.

Thomas499:
Both preferably. But I figured out how to print what it points to, I need to figure out how to print the pointer.
I tried that before I asked on here. The youtube examples do it this way too. But I get this error message

void setup()
{
  Serial.begin(115200);
  int a = 45;
  Serial.println((unsigned long)&a);
}

void loop()
{
}

Compiles, at least.

It does complie, but it doesn't run correctly.

void setup()
{
  Serial.begin(115200);
  int b = 77;
  int a = 45;
  Serial.println((unsigned long)&a);
}

void loop()
{
}

whether you take int b out or leave it in, the Serial monitor will say 2296. Because b complies before a taking b out all together should change the address of a. but it doesn't.