From 46086941cdaf6614fd47e033e35950210ea9be8a Mon Sep 17 00:00:00 2001 From: Mikhail Osipov Date: Mon, 13 May 2019 16:50:38 +0300 Subject: print top memory usage --- TODO | 2 +- main.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 194 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index de7d302..9f395a7 100644 --- a/TODO +++ b/TODO @@ -1 +1 @@ -1. print top of memory consumers +1. print top of memory consumers (DONE) diff --git a/main.c b/main.c index 39927f1..2bd6347 100644 --- a/main.c +++ b/main.c @@ -2,16 +2,49 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include +#define TOPMEMCOUNT 8 +#define TOOLFONT "xos4 Terminus" + +struct proc_entry { + char *name; + int rss; +}; + static char SYSPATH[] = "/sys/class/power_supply/BAT0/"; static char charging[] = "↯"; +static struct proc_entry *proc_entry_new(const char *name) +{ + struct proc_entry *e = calloc(1, sizeof(*e)); + + e->name = strdup(name); + + return e; +} + +static void proc_entry_free(struct proc_entry *e) +{ + free(e->name); + free(e); +} + +static int proc_entry_cmp(const void *a, const void *b) +{ +#define PROC_ENTRY_CAST(pp) (*(struct proc_entry **) (pp)) + return PROC_ENTRY_CAST(b)->rss - PROC_ENTRY_CAST(a)->rss; +#undef PROC_ENTRY_CAST +} + static char *readline(char *dir, char *file) { static char *line = NULL; @@ -81,13 +114,166 @@ static void print_battery_status(void) readline(NULL, NULL); } +static bool is_proc_entry(struct dirent *de) +{ + if (de->d_type != DT_DIR) + return false; + + for (int n = 0; de->d_name[n] != '\0'; n++) { + if (!isdigit(de->d_name[n])) + return false; + } + + return true; +} + +static char *get_proc_name(const char *pid) +{ + static char name[PATH_MAX]; + + char path[PATH_MAX]; + ssize_t n; + + snprintf(path, sizeof(path), "/proc/%s/exe", pid); + + if ((n = readlink(path, name, sizeof(name) - 1)) <= 0) + return NULL; + + name[n] = '\0'; + + return name; +} + +static int get_proc_rss(const char *pid) +{ + char path[PATH_MAX]; + FILE *fp; + int rss = -1; + + char *buf = NULL; + size_t buflen = 0; + + snprintf(path, sizeof(path), "/proc/%s/status", pid); + + fp = fopen(path, "r"); + if (!fp) + return -1; + + while (getline(&buf, &buflen, fp) > 0) { + int val; + + if (sscanf(buf, "VmRSS: %d kB", &val) == 1) { + rss = val; + break; + } + } + + fclose(fp); + free(buf); + + return rss; +} + +static int proc_entries_print(struct proc_entry **ee, int nelem, int upto, int width) +{ + int maxwidth = 0; + char buf[512]; + + if (upto > nelem) + upto = nelem; + + for (int n = 0; n < upto; n++) { + struct proc_entry *e = ee[n]; + char *s = strrchr(e->name, '/'); + + if (s) + s++; + else + s = e->name; + + snprintf(buf, sizeof(buf), "%s %d MB", s, e->rss); + int len = strlen(buf); + + if (maxwidth < len) + maxwidth = len; + + if (width) { + if (n) + printf("\n"); + + printf("%s%*s %d MB", s, width - len, "", e->rss); + } + } + + if (!width) + proc_entries_print(ee, nelem, upto, maxwidth); + + return maxwidth; +} + +static void print_top_memory_usage(void) +{ + DIR *dir = opendir("/proc"); + struct dirent *de; + + struct proc_entry **entries = NULL; + int nentry = 0; + + while ((de = readdir(dir)) != NULL) { + const char *pid = de->d_name; + + if (!is_proc_entry(de)) + continue; + + const char *procname = get_proc_name(pid); + if (!procname) + continue; + + int rss = get_proc_rss(pid); + if (rss < 0) + continue; + + struct proc_entry *e = NULL; + + for (int n = 0; n < nentry; n++) { + if (!strcmp(entries[n]->name, procname)) { + e = entries[n]; + break; + } + } + + if (!e) { + e = proc_entry_new(procname); + entries = realloc(entries, sizeof(*entries) * (nentry + 1)); + entries[nentry++] = e; + } + + e->rss += rss; + } + + qsort(entries, nentry, sizeof(*entries), proc_entry_cmp); + + proc_entries_print(entries, nentry, TOPMEMCOUNT, 0); + + for (int n = 0; n < nentry; n++) + proc_entry_free(entries[n]); + + free(entries); + + closedir(dir); +} + int main(int argc, char *argv[]) { struct sysinfo si; + setuid(0); + if (sysinfo(&si) < 0) return 1; + printf(""); + printf("used: %ld", (si.totalram - si.freeram) * si.mem_unit >> 20); printf(", free: %ld", si.freeram * si.mem_unit >> 20); #if 0 @@ -97,7 +283,13 @@ int main(int argc, char *argv[]) print_battery_status(); - printf("\n"); + printf("\n"); + + printf(""); + + print_top_memory_usage(); + + printf("\n"); return 0; } -- cgit v1.2.3-70-g09d2