Go Down

Topic: modify freeRam() to find fragmentation (Read 10400 times) previous topic - next topic

Thomas499

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

Code: [Select]
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
Quote
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.

MorganS

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.)
"The problem is in the code you didn't post."

RayLivingston

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.

Whandall

Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

Thomas499

Quote
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
Quote
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?
Quote
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?
Code: [Select]
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
}


Quote
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
Code: [Select]
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?

Quote
Heap memory is pretty much always managed with a linked list.
At the top correct?

Quote
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?

PaulS

Quote
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.

Quote
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.
The art of getting good answers lies in asking good questions.

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 ;)

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.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

RayLivingston

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 ;)

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.

Thomas499

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.

Code: [Select]
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
}

PaulS

Code: [Select]
//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.
The art of getting good answers lies in asking good questions.

robtillaart

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Thomas499

#11
Dec 16, 2015, 07:40 pm Last Edit: Dec 16, 2015, 07:43 pm by Thomas499
Quote
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?

PaulS

#12
Dec 16, 2015, 08:10 pm Last Edit: Dec 16, 2015, 08:11 pm by PaulS
Quote
How do I print the address of the memory used?
Code: [Select]
int thisVariableHasAnAddress;
Serial.print(&thisVariableHasAnAddress);


Code: [Select]
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?
The art of getting good answers lies in asking good questions.

christop

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).

BulldogLowell

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).

Go Up