commit
a840cc0a5d
|
@ -0,0 +1,20 @@
|
|||
#!/bin/sh
|
||||
gcc -O2 mtrack.c -shared -o mtrack.so -ldl -pthread -fPIC -g
|
||||
gcc -O2 mtdump.c -o mtdump -g `pkg-config --cflags --libs eina`
|
||||
gcc -O2 mtshow.c -o mtshow -g `pkg-config --cflags --libs eina`
|
||||
|
||||
sudo rm -f /usr/local/bin/mtshow
|
||||
sudo rm -f /usr/local/bin/mtdump
|
||||
sudo rm -f /usr/local/lib/mtrack.so
|
||||
sudo rm -f /usr/local/bin/mtf
|
||||
sudo rm -f /usr/local/bin/mtt
|
||||
sudo cp mtshow /usr/local/bin/mtshow
|
||||
sudo cp mtdump /usr/local/bin/mtdump
|
||||
sudo cp mtrack.so /usr/local/lib/mtrack.so
|
||||
sudo cp mtf /usr/local/bin/mtf
|
||||
sudo cp mtt /usr/local/bin/mtt
|
||||
sudo cp mtd /usr/local/bin/mtd
|
||||
|
||||
#rm -f mtrack.so
|
||||
#rm -f mtdump
|
||||
rm -f *~
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
export MTRACK=debug
|
||||
export MTRACK_ALLOC_FILL=2
|
||||
export MTRACK_FREE_FILL=1
|
||||
export MTRACK_CANARY_SIZE=16
|
||||
export MTRACK_CANARY=3
|
||||
export LD_PRELOAD=/usr/local/lib/mtrack.so
|
||||
exec $@
|
|
@ -0,0 +1,219 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <Eina.h>
|
||||
|
||||
static char *
|
||||
pstr(const char *cmd, int lines)
|
||||
{
|
||||
FILE *f;
|
||||
char *str = NULL;
|
||||
char buf[4096];
|
||||
int str_len = 0;
|
||||
int n = 0;
|
||||
int count = 0;
|
||||
|
||||
f = popen(cmd, "r");
|
||||
if (!f) return NULL;
|
||||
while (fgets(buf, sizeof(buf) - 1, f))
|
||||
{
|
||||
int len = strlen(buf);
|
||||
if ((len > 1) && (buf[len - 1] == '\n'))
|
||||
{
|
||||
buf[len - 1] = 0;
|
||||
len--;
|
||||
}
|
||||
str_len += len;
|
||||
str = realloc(str, str_len + 1);
|
||||
if (count == 0) str[0] = 0;
|
||||
strcat(str, buf);
|
||||
n++;
|
||||
count++;
|
||||
if (n >= lines) break;
|
||||
}
|
||||
pclose(f);
|
||||
return str;
|
||||
}
|
||||
|
||||
static char *
|
||||
addr2func(const char *file, const char *addr)
|
||||
{
|
||||
char *s;
|
||||
char cmd[4096], buf[4096];
|
||||
static Eina_Hash *hash = NULL;
|
||||
|
||||
if (!hash) hash = eina_hash_string_superfast_new(NULL);
|
||||
snprintf(buf, sizeof(buf), "%s %s", file, addr);
|
||||
s = eina_hash_find(hash, buf);
|
||||
if (s) return strdup(s);
|
||||
snprintf(cmd, sizeof(cmd), "addr2line -f -e %s", buf);
|
||||
s = pstr(cmd, 1);
|
||||
eina_hash_add(hash, buf, s);
|
||||
return strdup(s);
|
||||
}
|
||||
|
||||
static FILE *outf = NULL;
|
||||
|
||||
#define OUT(fmt, args...) fprintf(outf, fmt, ##args)
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[4096];
|
||||
int items = 0;
|
||||
int btnum = 0;
|
||||
int expected = 0;
|
||||
time_t t0;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("usage: mtdump MTLOGFILE OUTFILE\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
f = fopen(argv[1], "r");
|
||||
if (!f)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
outf = fopen(argv[2], "w");
|
||||
if (!outf)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf) - 1, f))
|
||||
{
|
||||
if (!strncmp(buf, "== ", 3)) expected++;
|
||||
}
|
||||
fseek(f, 0, SEEK_SET);
|
||||
t0 = time(NULL);
|
||||
while (fgets(buf, sizeof(buf) - 1, f))
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(buf);
|
||||
if (len < 2) continue;
|
||||
if ((len > 1) && (buf[len - 1] == '\n'))
|
||||
{
|
||||
buf[len - 1] = 0;
|
||||
len--;
|
||||
}
|
||||
if (!strncmp(buf, "== ", 3))
|
||||
{
|
||||
unsigned long size;
|
||||
char type[4096] = "";
|
||||
unsigned long alloctime;
|
||||
|
||||
if (sscanf(buf, "%*s %s %lu %*s %lu", type, &size, &alloctime)
|
||||
== 3)
|
||||
{
|
||||
time_t t;
|
||||
struct tm *tmp;
|
||||
char out[256] = "??";
|
||||
int eta;
|
||||
|
||||
if (items > 0) OUT("\n");
|
||||
items++;
|
||||
t = time(NULL) - t0;
|
||||
eta = (expected * (int)t) / items;
|
||||
printf("%i/%i -- ETA %i min %i sec \r",
|
||||
items, expected, eta / 60, eta % 60);
|
||||
fflush(stdout);
|
||||
btnum = 0;
|
||||
t = alloctime;
|
||||
tmp = localtime(&t);
|
||||
if (tmp)
|
||||
strftime(out, sizeof(out), "%F/%T", tmp);
|
||||
else
|
||||
strcpy(out, "??");
|
||||
OUT("%lu %s %s |", size, type, out);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (btnum > 0)
|
||||
{
|
||||
if (strchr(buf, '['))
|
||||
{
|
||||
// 1 of:
|
||||
// /usr/local/lib/libeina.so.1(+0x16ab8)[0x7fdaccc4cab8]
|
||||
// /lib/x86_64-linux-gnu/libc.so.6(__strdup+0x22)[0x7fdace0732f2]
|
||||
// ello[0x402d8c]
|
||||
// /usr/local/bin/ello[0x402d8c]
|
||||
if (strchr(buf, '('))
|
||||
{
|
||||
char file[4096], addr[4096];
|
||||
// 1 of:
|
||||
// /usr/local/lib/libeina.so.1(+0x16ab8)[0x7fdaccc4cab8]
|
||||
// /lib/x86_64-linux-gnu/libc.so.6(__strdup+0x22)[0x7fdace0732f2]
|
||||
if (sscanf(buf, "%[^(](%[^)])%*s", file, addr) == 2)
|
||||
{
|
||||
if (addr[0] == '+')
|
||||
{
|
||||
char *s = addr2func(file, addr + 1);
|
||||
if (s)
|
||||
{
|
||||
OUT(" %s", s);
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
OUT(" ??");
|
||||
}
|
||||
else
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = strchr(addr, '+');
|
||||
if (s) *s = 0;
|
||||
OUT(" %s", addr);
|
||||
}
|
||||
}
|
||||
else
|
||||
OUT(" ??");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1 of:
|
||||
// ello[0x402d8c]
|
||||
// /usr/local/bin/ello[0x402d8c]
|
||||
if (buf[0] == '/')
|
||||
{
|
||||
char file[4096], addr[4096];
|
||||
|
||||
if (sscanf(buf, "%[^\\[][%[^]]]", file, addr) == 2)
|
||||
{
|
||||
char *s = addr2func(file, addr);
|
||||
if (s)
|
||||
{
|
||||
OUT(" %s", s);
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
OUT(" ??");
|
||||
}
|
||||
else
|
||||
OUT(" ??");
|
||||
}
|
||||
else
|
||||
OUT(" ?main?");
|
||||
}
|
||||
}
|
||||
else
|
||||
OUT(" ??");
|
||||
}
|
||||
btnum++;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
fclose(outf);
|
||||
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
export MTRACK=fill
|
||||
export LD_PRELOAD=/usr/local/lib/mtrack.so
|
||||
exec $@
|
|
@ -0,0 +1,197 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <Eina.h>
|
||||
|
||||
enum {
|
||||
BYTES, KB, MB, SIZE, COUNT
|
||||
};
|
||||
|
||||
typedef struct _Group Group;
|
||||
|
||||
struct _Group
|
||||
{
|
||||
char *trace;
|
||||
unsigned long total;
|
||||
unsigned long count;
|
||||
};
|
||||
|
||||
static Eina_Hash *groups = NULL;
|
||||
static Eina_List *sorted = NULL;
|
||||
static int size = BYTES;
|
||||
static int sort = SIZE;
|
||||
|
||||
static int
|
||||
listsort(const void *data1, const void *data2)
|
||||
{
|
||||
Group *g = (Group *)data1;
|
||||
Group *gg = (Group *)data2;
|
||||
if (sort == SIZE) return (int)(g->total - gg->total);
|
||||
else if (sort == COUNT) return (int)(g->count - gg->count);
|
||||
return (int)(g->total - gg->total);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
hashwalk(const Eina_Hash *hash, const void *key, void *data, void *fdata)
|
||||
{
|
||||
Group *g = data;
|
||||
sorted = eina_list_append(sorted, g);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
FILE *f;
|
||||
char *file;
|
||||
char buf[4096];
|
||||
int i;
|
||||
int group = 0;
|
||||
Group *g;
|
||||
Eina_List *l;
|
||||
unsigned long total_count = 0, total_size = 0;
|
||||
|
||||
eina_init();
|
||||
if (argc < 1)
|
||||
{
|
||||
printf("usage: mtdump MTOUTFILE [OPT]\n"
|
||||
"OPT can be 0 or more of:\n"
|
||||
" -f N - group by trace of up to N functions in backtrace (0 == unlimited)\n"
|
||||
" -m - show size in Mb\n"
|
||||
" -k - show size in Kb\n"
|
||||
" -b - show size in bytes\n"
|
||||
" -s - sout by size\n"
|
||||
" -c - sout by count\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "-f"))
|
||||
{
|
||||
i++;
|
||||
group = atoi(argv[i]);
|
||||
}
|
||||
else if (!strcmp(argv[i], "-m"))
|
||||
{
|
||||
size = MB;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-k"))
|
||||
{
|
||||
size = KB;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-b"))
|
||||
{
|
||||
size = BYTES;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-s"))
|
||||
{
|
||||
sort = SIZE;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-c"))
|
||||
{
|
||||
sort = COUNT;
|
||||
}
|
||||
else
|
||||
file = argv[i];
|
||||
}
|
||||
f = fopen(file, "r");
|
||||
if (!f)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
groups = eina_hash_string_superfast_new(NULL);
|
||||
while (fgets(buf, sizeof(buf) - 1, f))
|
||||
{
|
||||
int len;
|
||||
unsigned long bytes = 0;
|
||||
char *p;
|
||||
|
||||
len = strlen(buf);
|
||||
if (len < 2) continue;
|
||||
if ((len > 1) && (buf[len - 1] == '\n'))
|
||||
{
|
||||
buf[len - 1] = 0;
|
||||
len--;
|
||||
}
|
||||
sscanf(buf, "%lu", &bytes);
|
||||
p = strchr(buf, '|');
|
||||
if (p)
|
||||
{
|
||||
char trace[4096] = "", *t;
|
||||
|
||||
p += 2;
|
||||
if (group == 0)
|
||||
{
|
||||
strcpy(trace, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = group;
|
||||
t = trace;
|
||||
while (*p)
|
||||
{
|
||||
if (isspace(*p))
|
||||
{
|
||||
i--;
|
||||
if (i == 0) break;
|
||||
}
|
||||
*t = *p;
|
||||
t++; p++;
|
||||
}
|
||||
*t = 0;
|
||||
}
|
||||
g = eina_hash_find(groups, trace);
|
||||
if (!g)
|
||||
{
|
||||
g = calloc(1, sizeof(Group));
|
||||
g->trace = strdup(trace);
|
||||
eina_hash_add(groups, trace, g);
|
||||
}
|
||||
g->total += bytes;
|
||||
g->count++;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
eina_hash_foreach(groups, hashwalk, NULL);
|
||||
printf("|-- MEM --|- COUNT --|----------------------------------------------\n");
|
||||
sorted = eina_list_sort(sorted, eina_list_count(sorted), listsort);
|
||||
EINA_LIST_FOREACH(sorted, l, g)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case MB:
|
||||
printf("%10lu [%8lu] %s\n", g->total / (1024 * 1024), g->count, g->trace);
|
||||
break;
|
||||
case KB:
|
||||
printf("%10lu [%8lu] %s\n", g->total / 1024, g->count, g->trace);
|
||||
break;
|
||||
default:
|
||||
printf("%10lu [%8lu] %s\n", g->total, g->count, g->trace);
|
||||
break;
|
||||
}
|
||||
total_count += g->count;
|
||||
total_size += g->total;
|
||||
}
|
||||
printf("|-- MEM --|- COUNT --|----------------------------------------------\n");
|
||||
printf("Total allocs: %lu\n", total_count);
|
||||
switch (size)
|
||||
{
|
||||
case MB:
|
||||
printf("Total memory: %lu Mb\n", total_size / (1024 * 1024));
|
||||
break;
|
||||
case KB:
|
||||
printf("Total memory: %lu Kb\n", total_size / 1024);
|
||||
break;
|
||||
default:
|
||||
printf("Total memory: %lu bytes\n", total_size);
|
||||
break;
|
||||
}
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue