/* mprof.c 2.6 9/14/90 16:01:20 */
/* Copyright (c) 1987, 1990, Benjamin G. Zorn */
/* mprof.c -- code to analyse and print out mprof data
#if defined(mips) || defined(vax)
char *result
= malloc(strlen(s
) + 1);
(void) strcpy(result
, s
);
extern void mprof_graph_ops(); /* from mpgraph.c */
#define check_fscanf(x) \
fprintf(stderr, "fscanf -- can't read input\n"); \
struct leakpair path
[SHORT_CALLSTACK_SIZE
];
lte_str_compar(lte1
, lte2
)
struct leakentry
*lte1
, *lte2
;
struct leakpair
*path1
, *path2
;
for (i
= 0; i
< SHORT_CALLSTACK_SIZE
; i
++) {
if (strcmp(path1
[i
].func
, path2
[i
].func
) != 0) {
return strcmp(path1
[i
].func
, path2
[i
].func
);
struct leakpair
*path1
, *path2
;
for (i
= 0; i
< SHORT_CALLSTACK_SIZE
; i
++) {
if (strcmp(path1
[i
].func
, path2
[i
].func
) != 0) {
lte_size_compar(lte1
, lte2
)
struct leakentry
*lte1
, *lte2
;
if ((lte1
->all_by
- lte1
->fre_by
) <
(lte2
->all_by
- lte2
->fre_by
)) {
} else if ((lte1
->all_by
- lte1
->fre_by
) >
(lte2
->all_by
- lte2
->fre_by
)) {
#define TYPE_GREATERTHAN 1
result
= (char *) malloc(strlen(buf
) + 1);
if ((intpart
== 0) && (frac
== 0)) {
} else if (intpart
== 0) {
} else if (intpart
== 100) {
result
= (char *) malloc(strlen(buf
) + 1);
/* functions for uniquely recording recording each structure type
struct stconscell
*numlist
;
struct sthash
*sthmem
[STHASH_SIZE
];
struct sthash
**read_and_sort_types();
sthash_compar(ste1
, ste2
)
struct sthash
**ste1
, **ste2
;
if ((*ste1
)->size
< (*ste2
)->size
) {
} else if ((*ste1
)-> size
> (*ste2
)->size
) {
return strcmp((*ste1
)->str
, (*ste2
)->str
);
struct stconscell
*newcons
;
newcons
= (struct stconscell
*) malloc(sizeof(struct stconscell
));
struct stconscell
*stlist
;
struct stconscell
*s
= stlist
;
struct stconscell
*l1
, *l2
;
struct stconscell
*s1
, *s2
;
for (len1
= 0, s1
= l1
; s1
!= STNIL
; len1
++, s1
= s1
->cdr
) ;
for (len2
= 0, s2
= l2
; s2
!= STNIL
; len2
++, s2
= s2
->cdr
) ;
for (s1
= l1
; s1
!= STNIL
; s1
= s1
->cdr
) {
if (stmember(s1
->car
, l2
) == STNIL
) {
*mpf_new_stlink(kind
, str
, size
, numlist
, next
)
struct stconscell
*numlist
;
new_stl
= (struct sthash
*) malloc(sizeof(struct sthash
));
new_stl
->numlist
= numlist
;
for (i
= 0; i
< len
; i
++) {
hash
= hash
^ (((int) *(s
+i
)) << (i
% 6));
return ((hash
>> 3) % STHASH_SIZE
);
char *struct_exceptions
[] = {
mpf_intern_type(s
, size
, structsize
, tnumber
)
int hash
= mpf_sthash(s
, size
);
struct sthash
*ste
= sthmem
[hash
];
for (i
= 0; i
< N_EXCEPTIONS
; i
++) {
if (strncmp(s
, struct_exceptions
[i
],
strlen(struct_exceptions
[i
])) == 0) {
if ((strncmp(s
, ste
->str
, size
) == 0) &&
(*((ste
->str
)+size
) == NULL
)) {
/* add the number to the list of numbers
if (stmember(tnumber
, ste
->numlist
) == STNIL
)
ste
->numlist
= stcons(tnumber
, ste
->numlist
);
newstr
= malloc((unsigned) (size
+ 1));
strncpy(newstr
, s
, size
);
*(char *) ((int) newstr
+ size
) = NULL
;
ste
= mpf_new_stlink(T_STRUCT
,
mpf_intern_typedef(s
, size
, tnumber
)
int hash
= mpf_sthash(s
, size
);
struct sthash
*ste
= sthmem
[hash
];
if ((strncmp(s
, ste
->str
, size
) == 0) &&
(*((ste
->str
)+size
) == NULL
)) {
/* add the number to the list of numbers
if (stmember(tnumber
, ste
->numlist
) == STNIL
)
ste
->numlist
= stcons(tnumber
, ste
->numlist
);
newstr
= malloc(size
+ 1);
strncpy(newstr
, s
, size
);
*(char *) ((int) newstr
+ size
) = NULL
;
ste
= mpf_new_stlink(T_TYPEDEF
,
read_and_sort_types(number
)
struct sthash
*ste
, *ste1
;
struct stconscell
*typedefs
, *tl
, *structs
, *sl
;
/* first, make a list of all typedefs and structs
for (i
= 0; i
< STHASH_SIZE
; i
++) {
if (ste
->kind
== T_TYPEDEF
) {
typedefs
= stcons((int) ste
, typedefs
);
} else if (ste
->kind
== T_STRUCT
) {
structs
= stcons((int) ste
, structs
);
/* for each typedef, if it points to a struct, change to a struct,
* add the size, and remove the struct
ste
= (struct sthash
*) tl
->car
;
tnum
= ste
->numlist
->car
;
ste1
= (struct sthash
*) sl
->car
;
if ((stmember(tnum
, ste1
->numlist
) != STNIL
) &&
(stmatchlist(ste
->numlist
, ste1
->numlist
))) {
* First, count how many there are
for (i
= 0; i
< STHASH_SIZE
; i
++) {
if (ste
->kind
== T_STRUCT
) {
* Allocate a vector containing that many entries.
result
= (struct sthash
**) malloc(sizeof(struct sthash
*) * pair_count
);
for (i
= 0; i
< STHASH_SIZE
; i
++) {
if (ste
->kind
== T_STRUCT
) {
result
[pair_count
] = ste
;
qsort((char *) result
, pair_count
, sizeof(struct sthash
*), sthash_compar
);
#define stab_name(x) (stab[(x)].name)
#define stab_addr(x) (stab[(x)].addr)
struct finfo stab
[ST_SIZE
];
#define stab_incr(idx) (((idx) < ST_SIZE) ? (idx)++ : \
(fprintf(stderr, "stab_incr -- stab table overflow (%d)\n", \
void st_read_structure();
if (e1
->addr
< e2
->addr
) {
} else if (e1
-> addr
> e2
-> addr
) {
extern char *ldgetname(); /* why isn't this in some header file? */
extern pAUXU
ldgetaux(); /* why isn't this in some header file? */
ldptr
= ldopen(exec_name
, NULL
);
ldreadst(ldptr
, ST_PSYMS
| ST_PAUXS
| ST_PFDS
| ST_PPDS
);
for (pfd
= PFD(ldptr
); pfd
< PFD(ldptr
) + SYMHEADER(ldptr
).ifdMax
;
for (i
= pfd
->ipdFirst
; i
< pfd
->ipdFirst
+ pfd
->cpd
; i
++) {
if (ldgetpd (ldptr
, i
, &pdr
) != SUCCESS
) {
fprintf(stderr
, "can't read pdr %d\n", i
);
if (pdr
.isym
!= isymNil
) {
if (ldtbread(ldptr
, pfd
->csym
? pdr
.isym
:
pdr
.isym
+ SYMHEADER(ldptr
).isymMax
, &asym
) != SUCCESS
) {
fprintf(stderr
, "can't read symbol");
/* fill in finfo array */
if (pdr
.isym
== isymNil
) {
stab
[i
].name
= "<stripped>";
stab
[i
].name
= ldgetname(ldptr
, &asym
);
stab_name(i
) = "unknown";
stab_addr(i
) = stab_addr(i
- 1) + 0x10000;
stab_name(i
) = "end_marker";
stab_addr(i
) = 0xffffffff;
this mips symbol table is extremely esoteric */
#define err_print(str, index) fprintf(stderr, str, index)
#define err_print(str, index)
if (ldtbseek(ldptr
) == SUCCESS
) {
for (i
= 0; i
< SYMHEADER(ldptr
).isymMax
+ SYMHEADER(ldptr
).iextMax
- 1;
if (ldtbread(ldptr
, i
, &asym
) != SUCCESS
) {
err_print("can't read symbol, index = %d\n", asym
.index
);
* check locals and globals for possible structures and unions
if (asym
.st
== stLocal
|| asym
.st
== stGlobal
) {
if (asym
.index
== indexNil
)
if (!(aux
= ldgetaux(ldptr
, asym
.index
))) {
err_print("can't read aux symbol, index = %d\n", asym
.index
);
localaux
= *aux
; /* have to make copy before swapping */
fdindex
= ld_ifd_iaux(ldptr
, asym
.index
);
if (LDAUXSWAP(ldptr
, fdindex
))
swap_aux(&localaux
, ST_AUX_TIR
, gethostsex());
/* see if it's a struct or union */
if (localaux
.ti
.bt
== btStruct
|| localaux
.ti
.bt
== btUnion
) {
/* if width specified, skip it */
if (localaux
.ti
.fBitfield
) {
ldgetrndx(ldptr
, fdindex
, aux
+ 1, &rfd
, &aux2
);
if (!aux2
.rndx
.index
|| aux2
.rndx
.index
== ST_ANONINDEX
)
rfi
= ldgetrfd(ldptr
, PFD(ldptr
)[fdindex
].rfdBase
+ rfd
);
symindex
= PFD(ldptr
)[rfi
].isymBase
+ aux2
.rndx
.index
;
if (ldtbread(ldptr
, symindex
, &asym2
) != SUCCESS
) {
err_print("can't read symbol, index = %d\n", symindex
);
name
= ldgetname(ldptr
, &asym2
);
mpf_intern_type(name
, strlen(name
), asym2
.value
, asym2
.index
);
} else if (asym
.st
== stTypedef
) {
if (asym
.index
== indexNil
)
if (!(aux
= ldgetaux(ldptr
, asym
.index
))) {
err_print("can't read aux symbol, index = %d\n", asym
.index
);
localaux
= *aux
; /* have to make copy before swapping */
fdindex
= ld_ifd_iaux(ldptr
, asym
.index
);
if (LDAUXSWAP(ldptr
, fdindex
))
swap_aux(&localaux
, ST_AUX_TIR
, gethostsex());
/* if width specified, skip it */
if (localaux
.ti
.fBitfield
) {
ldgetrndx(ldptr
, fdindex
, aux
+ 1, &rfd
, &aux2
);
if (!aux2
.rndx
.index
|| aux2
.rndx
.index
== ST_ANONINDEX
)
rfi
= ldgetrfd(ldptr
, PFD(ldptr
)[fdindex
].rfdBase
+ rfd
);
symindex
= PFD(ldptr
)[rfi
].isymBase
+ aux2
.rndx
.index
;
if (ldtbread(ldptr
, symindex
, &asym2
) != SUCCESS
) {
err_print("can't read symbol, index = %d\n", symindex
);
name
= ldgetname(ldptr
, &asym
);
mpf_intern_typedef(name
, strlen(name
), asym2
.index
);
int aout_file
= open(exec_name
, (O_RDONLY
));
read(aout_file
, &hdr
, sizeof(hdr
));
fprintf(stdout
, "st_read -- no symbols in executable\n");
/* read in the string table
lseek(aout_file
, N_STROFF(hdr
), L_SET
);
read(aout_file
, &string_size
, 4);
st_strings
= malloc(string_size
);
lseek(aout_file
, N_STROFF(hdr
), L_SET
);
read(aout_file
, st_strings
, string_size
);
/* read in the symbols one at a time
lseek(aout_file
, N_SYMOFF(hdr
), L_SET
);
for (i
= 0; i
< hdr
.a_syms
/ sizeof(struct nlist
); i
++) {
read(aout_file
, &asym
, sizeof(asym
));
/* check for functions compiled with -g
if (asym
.n_type
== N_FUN
) {
stab_name(stab_i) = (char *) (st_strings + asym.n_un.n_strx);
stab_addr(stab_i) = asym.n_value;
stmp = index(stab_name(stab_i), ':');
} else if ((asym
.n_type
== N_LSYM
) ||
(asym
.n_type
== N_GSYM
)) {
/* a local symbol that may be a structure definition
st_read_structure((char *) (st_strings
+ asym
.n_un
.n_strx
));
/* here's a candidate for a function name
if ((type
& N_TYPE
) == N_TEXT
) {
fname
= (char *) (st_strings
+ asym
.n_un
.n_strx
);
if ((*fname
== '_') & !index(fname
, '.')) {
/* since there is not '.' in the name, its probably a
stab_name(stab_i
) = (char *) ((int) fname
+ 1);
stab_addr(stab_i
) = asym
.n_value
;
stab_name(stab_i
) = "unknown";
stab_addr(stab_i
) = stab_addr(stab_i
- 1) + 0x10000;
stab_name(stab_i
) = "end_marker";
stab_addr(stab_i
) = 0xffffffff;
qsort(stab
, stab_i
, sizeof(struct finfo
), stab_compare
);
if ((eqp
== NULL
) && (*(colp
+1) == 't')) {
* Check for a Sun stabs type definition.
commap
= index(symp
, ',');
tnum
= atoi((char *) index(symp
, '(')+1);
tnum
= atoi((char *) (colp
+2));
mpf_intern_typedef(symp
, colp
- symp
, tnum
);
} else if ((eqp
!= NULL
) && *(eqp
+1) == 's') {
/* we have a structure entry...
* 1. get the size, number, and name
* 3. enter into the structure hash table
/* get the size (follows eqp+1)
ssize
= atoi((char *) eqp
+2);
* Get the number (follows :T)
* Check for a Sun stabs type definition.
commap
= index(symp
, ',');
tnum
= atoi((char *) index(symp
, '(')+1);
tnum
= atoi((char *) colp
+2);
/* enter the name into the structure hash table
mpf_intern_type(symp
, (index(symp
, ':') - symp
), ssize
, tnum
);
int middle
= (upper
+ lower
) / 2;
while (!((stab_addr(middle
) <= addr
) && (stab_addr(middle
+ 1) > addr
))) {
if (middle
== upper
|| middle
== lower
) {
if (stab_addr(middle
) > addr
) {
middle
= (upper
+ lower
) / 2;
if (middle
>= (stab_i
- 2)) {
printf("function symbol table:\n");
for (i
= 0; i
< stab_i
; i
++) {
printf(" %d %-15s %10d\n", i
,stab_name(i
), stab_addr(i
));
increment_data(dt
, d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
, d9
, d10
, d11
, d12
)
int d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
, d9
, d10
, d11
, d12
;
st_convert(data_filename
)
FILE *f
= fopen(data_filename
, "r");
int d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
, d9
, d10
, d11
, d12
;
* read the prolog containing stats
* handle the stats data first as a special case
check_fscanf(fscanf(f
, "alloc=%d free=%d depth=%d same=%d all=%d\n", &d1
, &d2
, &d3
, &d4
, &d5
));
check_fscanf(fscanf(f
, "fmem=%d dmem=%d lmem=%d smem=%d\n", &d6
, &d7
, &d8
, &d9
));
printf("--c%2s+--v3.0+--m%d+--+--+--+--+--+--+--+--+ MPROF +--+--+--+--+--+--+--s%d+--f%d+--d%d+--l%d+\n\n\n",
percent(d4
, d5
), d3
, d9
, d6
, d7
, d8
);
print_bin_table(f
, stdout
);
print_leak_table(f
, stdout
);
while (fscanf(f
, "%d\n", &faddr
) != EOF
) {
fsym
= pc_lookup(stab_addr(fx
));
fn_name(fsym
) = stab_name(fx
);
fscanf(f
, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
&d1
, &d2
, &d3
, &d4
, &d5
, &d6
, &d7
, &d8
, &d9
, &d10
, &d11
, &d12
);
increment_data(fn_lcount(fsym
),
d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
, d9
, d10
, d11
, d12
);
fscanf(f
, "%d\n", &paddr
);
while ((int) paddr
!= MP_NIL
) {
psym
= pc_lookup(stab_addr(px
));
ppair
= mp_has_parent(fsym
, psym
);
ppair
= mp_cons((int) psym
, (int) dcell
);
fn_parents(fsym
) = mp_cons((int) ppair
,
fscanf(f
, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
&d1
, &d2
, &d3
, &d4
, &d5
, &d6
,
&d7
, &d8
, &d9
, &d10
, &d11
, &d12
);
increment_data(mp_cdr(ppair
),
d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
, d9
, d10
, d11
, d12
);
fscanf(f
, "%d\n", &paddr
);
print_bin_table(infile
, outfile
)
int type_count
, type_index
= 0;
struct sthash
**type_table
;
int alloc_bins
[MP_NUM_BINS
];
int free_bins
[MP_NUM_BINS
];
int big_alloc_count
, big_alloc_bytes
;
int big_free_count
, big_free_bytes
;
int alloc_count
= 0, alloc_bytes
= 0, free_count
= 0, free_bytes
= 0;
int other_alloc_count
= 0, other_alloc_bytes
= 0;
int other_free_count
= 0, other_free_bytes
= 0;
* Read in and print out the Bin table information.
type_table
= read_and_sort_types(&type_count
);
/* read in the bins and save the data
for (i
= 0; i
< (MP_NUM_BINS
- 2); i
++) {
check_fscanf(fscanf(infile
, "%d\n", &alloc_bins
[i
]));
alloc_count
+= alloc_bins
[i
];
alloc_bytes
+= alloc_bins
[i
] * i
;
check_fscanf(fscanf(infile
, "%d\n", &big_alloc_count
));
alloc_count
+= big_alloc_count
;
check_fscanf(fscanf(infile
, "%d\n", &big_alloc_bytes
));
alloc_bytes
+= big_alloc_bytes
;
for (i
= 0; i
< (MP_NUM_BINS
- 2); i
++) {
check_fscanf(fscanf(infile
, "%d\n", &free_bins
[i
]));
free_count
+= free_bins
[i
];
free_bytes
+= free_bins
[i
] * i
;
check_fscanf(fscanf(infile
, "%d\n", &big_free_count
));
free_count
+= big_free_count
;
check_fscanf(fscanf(infile
, "%d\n", &big_free_bytes
));
free_bytes
+= big_free_bytes
;
byte_difference
= alloc_bytes
- free_bytes
;
"%11d%10d%10d %-4s%10d%10d %-4s "
"%11s%10d%10d %-4s%10d%10d %-4s "
#define abin_titles_template \
"%11s%10s%10s %-4s%10s%10s %-4s %-8s\n"
fprintf(outfile
, "--------- Allocation Bins with possible Types ------------\n\n");
fprintf(outfile
, abin_titles_template
,
"size:", "allocs", "bytes", "(%)", "frees", "kept", "(%)", "types");
for (i
= 0; i
< (MP_NUM_BINS
- 2); i
++) {
* Print things depending on the level of verbosity.
if (((verbosity
== V_VERBOSE
) &&
((abin
> 0) || (fbin
> 0)))
((verbosity
== V_NORMAL
) &&
(((abin
> 0) && (i
> 100)) ||
(((double) abin
/ alloc_count
) > 1.0/500.0) ||
((type_index
!= type_count
) &&
(((double) abin
/ alloc_count
) > 1.0/100.0) &&
((type_table
[type_index
])->size
== i
))))
((verbosity
== V_TERSE
) &&
((((double) abin
/ alloc_count
) > 1.0/50.0) ||
((type_index
!= type_count
) &&
(((double) abin
/ alloc_count
) > 1.0/100.0) &&
((type_table
[type_index
])->size
== i
))))) {
fprintf(outfile
, abin_template
,
percent_string(i
* abin
, alloc_bytes
),
fbin
, (i
* abin
) - (i
* fbin
),
percent_string((i
* abin
) - (i
* fbin
),
* Print out relevant types.
print_type_list(outfile
, type_table
, TYPE_EQUAL
, i
,
type_count
, &type_index
);
other_alloc_count
+= abin
;
other_free_count
+= fbin
;
other_alloc_bytes
+= abin
* i
;
other_free_bytes
+= fbin
* i
;
* Print the things at the end of the table.
fprintf(outfile
, abin_template2
,
"> 1024", big_alloc_count
, big_alloc_bytes
,
percent_string(big_alloc_bytes
, alloc_bytes
),
big_free_count
, (big_alloc_bytes
- big_free_bytes
),
percent_string((big_alloc_bytes
- big_free_bytes
),
print_type_list(outfile
, type_table
, TYPE_GREATERTHAN
, 1024,
type_count
, &type_index
);
fprintf(outfile
, "\n\n");
if ((other_alloc_count
> 0) ||
(other_free_count
> 0)) {
fprintf(outfile
, abin_template2
,
"other bins", other_alloc_count
, other_alloc_bytes
,
percent_string(other_alloc_bytes
, alloc_bytes
),
other_free_count
, (other_alloc_bytes
- other_free_bytes
),
percent_string((other_alloc_bytes
- other_free_bytes
),
fprintf(outfile
, abin_template2
,
"<TOTAL>", alloc_count
, alloc_bytes
, "",
free_count
, byte_difference
, "");
fprintf(outfile
, "\n\f\n\n");
print_type_list(outfile
, tlist
, compar
, binsize
, type_count
, type_index
)
int compar
, binsize
, type_count
;
((i
< type_count
) && (tlist
[i
]->size
<= binsize
));
if (compar
== TYPE_EQUAL
) {
cond
= (tlist
[i
]->size
== binsize
);
} else if (compar
== TYPE_GREATERTHAN
) {
cond
= (tlist
[i
]->size
> binsize
);
if ((pcount
> 0) && ((pcount
% 3) == 0)) {
fprintf(outfile
, "\n%64s", "");
fprintf(outfile
, "%-12s ", tlist
[i
]->str
);
#define leak_titles_template1 \
"%10s %-4s%10s%10s %-4s%10s%10s %-4s %-8s\n"
#define leak_titles_template2 \
"%10s %-4s%10s%10s %-4s %-8s\n"
"%10d %-4s%10d%10d %-4s%10d%10d %-4s "
"%10d %-4s%10d%10d %-4s "
print_leak_table(infile
, outfile
)
int total_allocs
= 0, bytes_alloced
= 0;
int total_frees
= 0, bytes_freed
= 0;
struct leakentry
*lt_root
= NULL
, *lte
= NULL
, *lt_vec
= NULL
;
int d1
, d2
, d3
, d4
, d5
, i
, j
, real_i
;
/* read in the leak table and print it back out
check_fscanf(fscanf(infile
, "%d %d %d %d\n", &d1
, &d2
, &d3
, &d4
));
* Gather the path for a single leak table entry.
lte
= (struct leakentry
*) malloc(sizeof(struct leakentry
));
for (i
= 0; i
< SHORT_CALLSTACK_SIZE
; i
++) {
check_fscanf(fscanf(infile
, "%d\n", &d5
));
fsym
= pc_lookup(stab_addr(fx
));
fn_name(fsym
) = stab_name(fx
);
lte
->path
[SHORT_CALLSTACK_SIZE
- (i
+ 1)].func
= fn_name(fsym
);
lte
->path
[SHORT_CALLSTACK_SIZE
- (i
+ 1)].offset
= d5
- stab_addr(fx
);
lte
->path
[SHORT_CALLSTACK_SIZE
- (i
+ 1)].func
= "";
lte
->path
[SHORT_CALLSTACK_SIZE
- (i
+ 1)].offset
= 0;
* Add to the list of leak entries.
check_fscanf(fscanf(infile
, "%d %d %d %d", &d1
, &d2
, &d3
, &d4
));
byte_diff
= bytes_alloced
- bytes_freed
;
if ((lte_count
== 0) || (leak_level
== LEAK_NONE
)) {
fprintf(outfile
, "--------- Partial Dynamic Call Paths for Memory Leaks ------------\n\n");
fprintf(outfile
, "Total bytes not freed: %d\n\n", byte_diff
);
fprintf(outfile
, leak_titles_template1
,
"kept bytes", "(%)", "allocs", "bytes", "(%)",
"frees", "bytes", "(%)", "path");
fprintf(outfile
, leak_titles_template2
,
"kept bytes", "(%)", "allocs", "bytes", "(%)", "path");
* Here we put the leak table entries into a vector so we can
lt_vec
= (struct leakentry
*) malloc(sizeof(struct leakentry
) * lte_count
);
if (leak_level
== LEAK_SHOW
) {
* Sort the entries so that duplicate paths are together.
qsort((char *) lt_vec
, lte_count
, sizeof(struct leakentry
), lte_str_compar
);
for (i
= 1; i
< lte_count
;) {
if (path_equal(lt_vec
[real_i
].path
, lt_vec
[i
].path
)) {
* Merge the data from identical paths together.
lt_vec
[real_i
].all_no
+= lt_vec
[i
].all_no
;
lt_vec
[real_i
].all_by
+= lt_vec
[i
].all_by
;
lt_vec
[real_i
].fre_no
+= lt_vec
[i
].fre_no
;
lt_vec
[real_i
].fre_by
+= lt_vec
[i
].fre_by
;
* First, copy the data, compressing out bubbles
lt_vec
[real_i
] = lt_vec
[i
];
qsort((char *) lt_vec
, lte_count
, sizeof(struct leakentry
), lte_size_compar
);
for (i
= 0; i
< lte_count
; i
+=1) {
if (verbosity
== V_TERSE
) {
if (((double) lte
.all_by
/ bytes_alloced
) < 0.01) {
} else if (verbosity
== V_NORMAL
) {
if (((double) lte
.all_by
/ bytes_alloced
) < 0.005) {
fprintf(outfile
, leak_template1
,
(lte
.all_by
- lte
.fre_by
),
percent_string((lte
.all_by
- lte
.fre_by
), byte_diff
),
percent_string(lte
.all_by
, bytes_alloced
),
percent_string(lte
.fre_by
, bytes_freed
));
fprintf(outfile
, leak_template2
,
(lte
.all_by
- lte
.fre_by
),
percent_string((lte
.all_by
- lte
.fre_by
), byte_diff
),
percent_string(lte
.all_by
, bytes_alloced
));
if ((strcmp(lte
.path
[0].func
, "") == 0) ||
(strcmp(lte
.path
[0].func
, "main") == 0)) {
for (j
= 0; j
< SHORT_CALLSTACK_SIZE
; j
++) {
if (strcmp(lte
.path
[j
].func
, "") != 0) {
if (leak_level
== LEAK_SHOW
) {
fprintf(outfile
, "> %s ", lte
.path
[j
].func
);
} else if (leak_level
== LEAK_OFFSETS
) {
fprintf(outfile
, "> %s+%d ", lte
.path
[j
].func
, lte
.path
[j
].offset
);
fprintf(outfile
, "\n\f\n\n");
fprintf(stderr
, "usage: mprof [-leaktable | -noleaktable] \n\
[-verbose | -normal | -terse] \n\
[a.out-name] [data-name]\n");
#define str_equal(s1, s2) (strcmp((s1), (s2)) == 0)
char *exec_file
= "a.out";
char *data_file
= "mprof.data";
for (i
= 1; i
< argc
; i
++) {
if (str_equal(argv
[i
], "-leaktable")) {
} else if (str_equal(argv
[i
], "-noleaktable")) {
} else if (str_equal(argv
[i
], "-offsets")) {
leak_level
= LEAK_OFFSETS
;
} else if (str_equal(argv
[i
], "-verbose")) {
} else if (str_equal(argv
[i
], "-normal")) {
} else if (str_equal(argv
[i
], "-terse")) {
} else if (i
== (argc
- 1)) {
} else if (i
== (argc
- 2)) {
for (i
= 0; i
< ST_SIZE
; i
++) {