Skip to content

Instantly share code, notes, and snippets.

@zeph1e
Created September 11, 2014 01:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeph1e/094c40b02d9435df9374 to your computer and use it in GitHub Desktop.
Save zeph1e/094c40b02d9435df9374 to your computer and use it in GitHub Desktop.
parse smaps & collect memory usage by owner. It can dump all result or make a spread sheet entry for specific category (like PSS)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include <errno.h>
#include <vector>
#include <unistd.h>
#include <unordered_map>
#define LINEBUFMAX 1024
#define PATTERN "^([[:xdigit:]]+\\-[[:xdigit:]]+ [rwxsp\\-]+ [[:xdigit:]]{1,8} [[:xdigit:]]{2}\\:[[:xdigit:]]{2} [[:digit:]]+[[:space:]]*){1}([[:alnum:][:punct:]]+)?"
using namespace std;
struct SMAPSENTRY {
unsigned size,
rss,
pss,
shared_clean,
shared_dirty,
private_clean,
private_dirty,
referenced,
anonymous,
anonhugepages,
swap,
kernelpagesize,
mmupagesize,
locked;
void add(const SMAPSENTRY* op) {
size += op->size;
rss += op->rss;
pss += op->pss;
shared_clean += op->shared_clean;
shared_dirty += op->shared_dirty;
private_clean += op->private_clean;
private_dirty += op->private_dirty;
referenced += op->referenced;
anonymous += op->anonymous;
anonhugepages += op->anonhugepages;
swap += op->swap;
kernelpagesize += op->kernelpagesize;
mmupagesize += op->mmupagesize;
locked += op->locked;
}
void dump(const char* category) {
printf("%s\nSize: %d, Rss: %d, Pss: %d, Shared_Clean: %d, Shared_Dirty: %d\n"
"Private_Clean: %d, Private_Dirty: %d, Referenced: %d\n"
"Anonymous: %d, AnonHugePages: %d, Swap: %d\n"
"KernelPageSize: %d, MMUPageSize: %d, Locked: %d\n\n",
category, size, rss, pss, shared_clean, shared_dirty, private_clean, private_dirty,
referenced, anonymous, anonhugepages, swap, kernelpagesize, mmupagesize, locked);
}
};
enum EntryItem {
ENone = -1,
ESize = 0,
ERss,
EPss,
ESharedClean,
ESharedDirty,
EPrivateClean,
EPrivateDirty,
EReferenced,
EAnonymous,
EAnonHugePages,
ESwap,
EKernelPageSize,
EMMUPageSize,
ELocked,
};
static void print_usage()
{
}
static void print_sheet_item(const char* name, EntryItem type, SMAPSENTRY* entry)
{
int len = strlen(name) + 2; // column margin
char style[16];
sprintf(style, "%%%ddKB", len);
switch (type) {
case ENone:
entry->dump(name);
break;
case ESize:
printf(style, entry->size);
break;
case ERss:
printf(style, entry->rss);
break;
case EPss:
printf(style, entry->pss);
break;
default:
;
}
}
int main(int argc, char* argv[])
{
regex_t regex;
int r;
char buf[LINEBUFMAX];
char msgbuf[LINEBUFMAX];
typedef vector<string> ORDERVECT;
typedef unordered_map<string, SMAPSENTRY*> SMAP;
ORDERVECT order;
SMAP smap;
bool print_index = false;
EntryItem sheet = ENone;
// option
int opt;
while ((opt = getopt(argc, argv, "s:i")) != -1) {
switch (opt) {
case 's': // spread sheet entry mode
if (!strcmp(optarg, "size")) { sheet = ESize; }
else if (!strcmp(optarg, "rss")) { sheet = ERss; }
else if (!strcmp(optarg, "pss")) { sheet = EPss; }
// blahblah
break;
case 'i': // print index
print_index = true;
break;
default:
print_usage();
exit(0);
}
}
if (regcomp(&regex, PATTERN, REG_EXTENDED | REG_NEWLINE)) {
fputs("Unable to compile regex\n", stderr);
exit(1);
}
regmatch_t part[3];
SMAPSENTRY* entry = 0;
while(fgets(buf, sizeof(buf), stdin)) {
if (!(r = regexec(&regex, buf, 3, part, 0))) {
char * path = 0;
int start;
if (part[2].rm_so > 0) {
start = part[2].rm_so;
buf[part[2].rm_eo] = 0;
for (int i = part[2].rm_eo; i >= start; i--) {
if (buf[i] == '/') {
start = i + 1;
break;
}
}
path = &buf[start];
}
string key = path ? string(path) : string("anonymous");
SMAP::iterator it = smap.find(key);
if (it == smap.end()) {
// make a new entry
entry = new SMAPSENTRY;
memset(entry, 0, sizeof(SMAPSENTRY));
smap.insert(pair<string, SMAPSENTRY*>(key, entry));
if (path)
order.push_back(path);
}
else {
entry = it->second;
}
continue;
}
else if (r == REG_NOMATCH) {
if (!entry) {
fprintf(stderr, "invalid format while no entry defined :%s", buf);
exit(1);
}
else if (!strncmp(buf, "Size:", 5)) { entry->size += atoi(&buf[6]); }
else if (!strncmp(buf, "Rss:", 4)) { entry->rss += atoi(&buf[4]); }
else if (!strncmp(buf, "Pss:", 4)) { entry->pss += atoi(&buf[4]); }
else if (!strncmp(buf, "Shared_Clean:", 12)) { entry->shared_clean += atoi(&buf[12]); }
else if (!strncmp(buf, "Shared_Dirty:", 12)) { entry->shared_dirty += atoi(&buf[12]); }
else if (!strncmp(buf, "Private_Clean:", 13)) { entry->private_clean += atoi(&buf[13]); }
else if (!strncmp(buf, "Private_Dirty:", 13)) { entry->private_dirty += atoi(&buf[13]); }
else if (!strncmp(buf, "Referenced:", 11)) { entry->referenced += atoi(&buf[11]); }
else if (!strncmp(buf, "Anonymous:", 10)) { entry->anonymous += atoi(&buf[10]); }
else if (!strncmp(buf, "Swap:", 5)) { entry->swap += atoi(&buf[5]); }
else if (!strncmp(buf, "AnonHugePages:", 13)) { entry->anonhugepages += atoi(&buf[13]); }
else if (!strncmp(buf, "MMUPageSize:", 12)) { entry->mmupagesize += atoi(&buf[12]); }
else if (!strncmp(buf, "Locked:", 7)) { entry->locked+= atoi(&buf[7]); }
}
else {
regerror(r, &regex, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
exit(1);
}
}
order.push_back("anonymous");
ORDERVECT::size_type sz = order.size();
SMAPSENTRY tot;
memset(&tot, 0, sizeof(tot));
if (print_index) {
for (unsigned i = 0; i < sz; i++) {
printf(" %s", order[i].c_str());
}
puts(" TOTAL");
}
for (unsigned i = 0; i < sz; i++) {
SMAP::iterator it = smap.find(order[i]);
if (it == smap.end()) {
continue;
}
print_sheet_item(order[i].c_str(), sheet, it->second);
tot.add(it->second);
}
print_sheet_item("TOTAL", sheet, &tot);
puts("");
for (SMAP::iterator it = smap.begin(); it != smap.end(); ++it) {
entry = it->second;
delete entry;
it->second = 0;
}
regfree(&regex);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment