Jump to content

Trying to get memory usage but it is complicated.

I am on Arch with i3wm, and I am customizing my i3bar with i3blocks and scripts. I am trying to add the monitoring for memory usage, but all the tools report different usage. For example, the C code one uses the sysinfo function, and right now, it is reporting 1.8 GB. There is a batch file as well which reports almost a gigabyte less at 0.7 GB. If I use the "free" command in terminal and get the output in GB, the used memory is 1.2 GB with shared being 246 MB and cache being 1.1 GB. Using htop, it says about a gigabyte. Btop says 1.2 GB (converted from gibibytes).

 

I know, some measure the real map-able memory, some measure the cache, some have different ways of getting memory information. I just want a way to get a simple and real memory usage. Not including cache and all that, the real memory which can be used. I would like to have a different monitoring for real amount of memory though.

Microsoft owns my soul.

 

Also, Dell is evil, but HP kinda nice.

Link to comment
Share on other sites

Link to post
Share on other sites

I think free should do what you need already. Check the output of free -hw on my machine:

               total        used        free      shared     buffers       cache   available
Mem:            31Gi       2,8Gi        16Gi        36Mi       711Mi        11Gi        28Gi

The amount of memory reported as free is memory that isn't currently in use at all. While available is the amount of memory that is or can be made available to programs when needed. Which is generally what you'd most care about.

 

Available should roughly match free + buffers + cache (16 + 11 + 0.7 = ~28). Other programs might only report free or available, but call it differently.

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

@Eigenvektor

 

I kind of want to use the C version because it is much more customization, but the memory usage it gives does not match with the batch version or the free command at all. You are saying to use free, but is that even correct? Which one do I trust? Well I guess I can trust any tool, it's just that they report different things and differently. Maybe you could take a look at the C code and perhaps say why it is so different?

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/sysinfo.h>

typedef struct sysinfo sysinfo_t;

typedef struct {
    char bytes[4];
    int size;
} utf8_char;

unsigned int utf8_char_count(const char* str) {
    unsigned int count = 0;
    while(*str) {
        count += (*str & 0xC0) != 0x80;
        str++;
    }
    return count;
}

void load_bar_chars(utf8_char* bar_chars, unsigned int count, char* characters) {
    char* c = characters;
    for (unsigned int i = 0; i < count; i++) {
        int size = 0;
        utf8_char* b = bar_chars + i;
        if (!c[0]) {
            printf("FAILED TO LOAD CHARS CORRECT");
        } else if (!(c[0] & 0x80)) {
            size = 1;
        } else if ((c[0] & 0xE0) == 0xC0) {
            size = 2;
        } else if ((c[0] & 0xF0) == 0xE0) {
            size = 3;
        } else if ((c[0] & 0xF8) == 0xF0) {
            size = 4;
        }
        
        for (unsigned int j = 0; j < size; j++)
            b->bytes[j] = c[j];
        
        b->size = size;
        
        c += size;
    }
}

int clamp(int value, int min, int max) {
    return value < min ? min : (value > max ? max : value);
}

char* calculate_color(float percent) {
    // Gradient from green to red
    int r = (int)(255 * (percent / 100));
    int g = (int)(255 * (1 - percent / 100));
    int b = 0;
    
    static char color[15]; // Assuming the format is "#RRGGBB\0"
    snprintf(color, 15, "#%02X%02X%02X", r, g, b);
    
    return color;
}

int main(int argc, char *argv[]) {
    //char *characters = "▁▂▃▄▅▆▇█";
    char *characters = "▁▏▎▍▌▋▊▉██";
    unsigned int bar_size = 10;
    
    unsigned int count = utf8_char_count(characters);
    utf8_char* bar_chars = (utf8_char*)malloc(count * sizeof(utf8_char));
    
    load_bar_chars(bar_chars, count, characters);
    
    int buffer_size = (bar_size * 4) + 1;
    char* buffer = (char*)malloc(buffer_size);
    
    unsigned int t = 1;
    while (1) {
        sysinfo_t info;
        sysinfo(&info);
        
        float total = info.totalram / (1024.0f * 1024.0f); // Convert to MB
        float free  = info.freeram / (1024.0f * 1024.0f);  // Convert to MB
        float usage = total - free;
        
        float percent = 100 * (usage / total);
        float bar_percent = percent;
        memset(buffer, 0, buffer_size);
        
        char* write_point = buffer;
        float section_size = 100.0f / bar_size;
        for (unsigned int i = 0; i < bar_size; i++) {
            int section_val = clamp((int)bar_percent, 0, count-1);
            utf8_char u_char = bar_chars[section_val];
            for (unsigned int j = 0; j < u_char.size; j++)
                write_point[j] = u_char.bytes[j];
            bar_percent -= section_size;
            write_point += u_char.size;
        }
        
        char* color = calculate_color(percent);
        
        printf(" <span color='%s'>%s %.1f MB / %.1f MB (%.1f%%)</span>\n", color, buffer, usage, total, percent);
        fflush(stdout);
        
        sleep(t);
    }
    free(buffer);
    free(bar_chars);
    return EXIT_SUCCESS;
}

 

This is a modified version of the i3 blocks contrib repo. I guess all it lies is in what free ram the sysinfo function reports. Is there a better way to do this? For example, here is the batch version - 

 

TYPE="${BLOCK_INSTANCE:-mem}"
PERCENT="${PERCENT:-true}"

awk -v type=$TYPE -v percent=$PERCENT '
/^MemTotal:/ {
	mem_total=$2
}
/^MemFree:/ {
	mem_free=$2
}
/^Buffers:/ {
	mem_free+=$2
}
/^Cached:/ {
	mem_free+=$2
}
/^SwapTotal:/ {
	swap_total=$2
}
/^SwapFree:/ {
	swap_free=$2
}
END {
	if (type == "swap") {
		free=swap_free/1024/1024
		used=(swap_total-swap_free)/1024/1024
		total=swap_total/1024/1024
	} else {
		free=mem_free/1024/1024
		used=(mem_total-mem_free)/1024/1024
		total=mem_total/1024/1024
	}

	pct=0
	if (total > 0) {
		pct=used/total*100
	}

	# full text
	if (percent == "true" ) {
		printf("%.1fG/%.1fG (%.f%%)\n", used, total, pct)
	} else {
		printf("%.1fG/%.1fG\n", used, total)
	}
	# short text
	printf("%.f%%\n", pct)

	# color
	if (pct > 90) {
		print("#FF0000")
	} else if (pct > 80) {
		print("#FFAE00")
	} else if (pct > 70) {
		print("#FFF600")
	}
}
' /proc/meminfo

 

I guess it is getting the info from /proc/meminfo as the last line suggests? I can't read batch scripts so I am sorry. I just want a way to get nice and simple memory usage, but you can't expect me to come up with a solution when every source emits a different answer.

Microsoft owns my soul.

 

Also, Dell is evil, but HP kinda nice.

Link to comment
Share on other sites

Link to post
Share on other sites

38 minutes ago, Gat Pelsinger said:

I kind of want to use the C version because it is much more customization, but the memory usage it gives does not match with the batch version or the free command at all.

I don't understand what you mean here, there's a batch version of free? I'm talking about the binary free, which is found at /usr/bin/free on my distribution. I'm not aware of a batch version of that program.

 

cat /proc/meminfo | grep Mem && /usr/bin/free -k

MemTotal:       32,786,756 kB
MemFree:        12,952,520 kB
MemAvailable:   28,230,184 kB

                 total        used          free      shared  buff/cache     available
Mem:        32,786,756     4553320    12,955,772      175140    15916436    28,233,436

(note: I added the thousand separators manually to make it easier to compare numbers)

 

Comparing the output of meminfo to free appears to yield pretty consistent results. Yes, there are a few bytes of difference, which is likely the result of running cat+grep vs free, all of which obviously also influence memory usage (any program that runs needs to be loaded into memory, after all).

 

(edit: yes, the batch script you posted simply uses the output of /proc/meminfo and performs some math on it… which could be the source of difference int vs float in the C program?)

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

@Eigenvektor

 

The C code I gave is from the i3blocks-contrib repository on github, but I modified it a little only for the color grading, that's it. There is also a batch file to do the same. These are to display stuff on the i3bar through i3blocks. All I want is a way to get a simple memory usage, which does not include the cache and all that, just the amount of memory that I can use. 

 

I think I should read from /proc/meminfo, because the C version gives more usage, so it probably is reading more than just usable memory. Also, what is the difference between MemFree and MemAvailable in meminfo?

 

Edit - The sysinfo() man page says - 

Quote
All of the information provided by this system call is also
       available via /proc/meminfo and /proc/loadavg.

 

But I guess the "freeram" variable gives a bit more than pure usable memory. In meminfo, I have more control in what to see.

Microsoft owns my soul.

 

Also, Dell is evil, but HP kinda nice.

Link to comment
Share on other sites

Link to post
Share on other sites

2 minutes ago, Gat Pelsinger said:

Also, what is the difference between MemFree and MemAvailable in meminfo?

Exactly the same one I explained in my first post. Memory that isn't used at all and memory that is available to programs (e.g. free + buffers/cache, which are dropped when needed)

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

@Eigenvektor

 

I think I should probably stick to the used memory outputted by the free command rather going for sysinfo() or /proc/meminfo. Everything outputs different results but I think I trust the free command.

Microsoft owns my soul.

 

Also, Dell is evil, but HP kinda nice.

Link to comment
Share on other sites

Link to post
Share on other sites

On 3/24/2024 at 10:42 AM, Gat Pelsinger said:

@Eigenvektor

 

I think I should probably stick to the used memory outputted by the free command rather going for sysinfo() or /proc/meminfo. Everything outputs different results but I think I trust the free command.

If I told you your system memory is used in different way and every number you read is technically accurate would you believe me?

 

I point to htop as proof in case you ever wanted to learn why CPU usage is shown in green red and blue. Same goes for memory

https://serverfault.com/questions/180711/what-exactly-do-the-colors-in-htop-status-bars-mean

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×