Created
September 11, 2014 01:45
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(®ex, 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(®ex, 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, ®ex, 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(®ex); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment