/* mprof_mon.c 1.1 9/14/90 11:59:04 */
/* Copyright (c) 1987, Benjamin G. Zorn */
/* mprof_mon -- code that is attached to executing programs.
int intloc
; /* for use by assembly routines */
char *mprof_filename
= "mprof.data";
bool mprof_initialized
= FALSE
;
int mprof_create_mask
= 0644;
unsigned mp_root_address
= CRT0_ADDRESS
;
int mprof_alloc_bins
[MP_NUM_BINS
];
int mprof_free_bins
[MP_NUM_BINS
];
/* mp_zero_bins() -- initialize the bins to zero
for (i
= 0; i
< MP_NUM_BINS
; i
++)
for (i
= 0; i
< MP_NUM_BINS
; i
++)
/* mp_inc_bin(bin, size) -- increment the bin of the appropriate size.
fprintf(stderr
, "mp_inc_bin -- negative size\n");
} else if (size
< MP_NUM_BINS
- 2) {
bin
[MP_NUM_BINS
- 1] += size
;
/* mp_print_bins(file) -- print the bins to a file
for (i
= 0; i
< MP_NUM_BINS
; i
++) {
sprintf(digits
, "%d\n", mprof_alloc_bins
[i
]);
write(file
, digits
, strlen(digits
));
for (i
= 0; i
< MP_NUM_BINS
; i
++) {
sprintf(digits
, "%d\n", mprof_free_bins
[i
]);
write(file
, digits
, strlen(digits
));
/* mp_note_alloc -- note allocation by bin. There are currently
* four bins with boundaries that are potentially user setable.
if (nbytes
<= mprof_bound1
) {
} else if (nbytes
<= mprof_bound2
) {
} else if (nbytes
<= mprof_bound3
) {
/* mp_note_free -- note when a memory block is released.
if (nbytes
<= mprof_bound1
) {
} else if (nbytes
<= mprof_bound2
) {
} else if (nbytes
<= mprof_bound3
) {
/* mp_note_parent -- record a caller/callee relationship.
* Allocate a data cell and put the parent on the parents list if
mp_note_parent(p
, c
, nbytes
)
/* if yes -- is parent already listed?
ppair
= mp_has_parent(c
, p
);
/* if yes -- increment count of calls from parent
mp_note_alloc((mpdata
) mp_cdr(ppair
), nbytes
);
/* if no -- add this parent to the list of parents
mp_note_alloc(dcell
, nbytes
);
ppair
= mp_cons((int) p
, (mpcell
) dcell
);
fn_parents(c
) = mp_cons((int) ppair
, fn_parents(c
));
/* mp_note_leaf -- note allocation directly in the function.
mp_note_alloc(fn_lcount(l
), nbytes
);
/* variables to record information about the monitoring
mpcell fpcells
[MAXCALLS
];
unsigned short_callstack
[SHORT_CALLSTACK_SIZE
];
unsigned first_local
; /* WARNING -- This MUST be the first
* local variable in this function.
int lookupcount
, samecount
;
if (!mprof_initialized
) {
mprof_initialized
= TRUE
;
mp_inc_bin(mprof_alloc_bins
, nbytes
);
(mprof_allocC
% mprof_autosave
) == 0) {
/* gather return addresses from the callstack
fp
= get_current_fp(first_local
);
ret_addr
= ret_addr_from_fp(fp
);
/* Step back 1 frame (to the caller of malloc)
fp
= prev_fp_from_fp(fp
);
ret_addr
= ret_addr_from_fp(fp
);
while (ret_addr
> mp_root_address
) {
if (no_call_graph
&& (fstk_i
> SHORT_CALLSTACK_SIZE
))
fp
= prev_fp_from_fp(fp
);
ret_addr
= ret_addr_from_fp(fp
);
ret_addr
= getretaddr(&fp
, pdr
); /* fp is changed */
/* Step back 1 frame (to the caller of malloc) */
ret_addr
= getretaddr(&fp
, pdr
); /* fp is changed */
while (ret_addr
> mp_root_address
) {
if (no_call_graph
&& (fstk_i
> SHORT_CALLSTACK_SIZE
))
ret_addr
= getretaddr(&fp
, pdr
); /* fp is updated */
/* note last N addresses (short_callstack) for the leak table
for (i
= 0; i
< SHORT_CALLSTACK_SIZE
; i
++) {
for (i
= 0; ((i
< SHORT_CALLSTACK_SIZE
) && (i
< fstk_i
)); i
++) {
short_callstack
[i
] = fpcs
[i
];
leakdata
= mp_add_leak_table(short_callstack
, nbytes
);
/* note the direct allocation
mp_note_leaf(pc_lookup(fpcs
[0]), nbytes
);
/* note maximum stack depth
if (fstk_i
> mprof_cs_maxdepth
)
mprof_cs_maxdepth
= fstk_i
;
/* determine the overlap with the last callstack
(fpcs
[i
] == last_fpcs
[lasti
])) {
/* i is the index of the first difference of pc's in the stack
* i+1 is the number of pc's that need to be looked up
/* put the new calls in the stack of functions
for (j
= fstk_i
- lookupcount
; j
< fstk_i
; j
++) {
fsyms
[j
] = pc_lookup(fpcs
[fstk_i
- j
- 1]);
samecount
= fstk_i
- lookupcount
;
mprof_cs_sameC
+= samecount
;
/* record the parent/child relations
for (i
= 0; i
< (fstk_i
- 1); i
++) {
printf("%d -> ", fn_addr(parent
));
if (i
< (samecount
- 1)) {
mp_note_alloc((mpdata
) mp_cdr(fpcells
[i
+1]), nbytes
);
fpcells
[i
+1] = mp_note_parent(parent
, child
, nbytes
);
printf("%d\n", fn_addr(child
));
mp_note_leaf(fsyms
[(fstk_i
- 1)], nbytes
);
/* swap the last pc stack with the current one
mprof_note_free(leakdata
, nbytes
)
addr
= leakdata
->sstack
[0];
mp_inc_bin(mprof_free_bins
, nbytes
);
mp_note_free(fn_lcount(f
), nbytes
);
mp_remove_leak_table(leakdata
, nbytes
);
on_exit(mprof_exit
, NULL
);
if (strcmp(mprof_filename
, "") == 0) {
mprof_file
= open(mprof_filename
,
(O_WRONLY
| O_CREAT
| O_TRUNC
),
extern int mprof_fmemC
, mprof_dmemC
, mprof_lmemC
, mprof_smemC
;
ftruncate(mprof_file
, 0);
lseek(mprof_file
, 0L, 0);
sprintf(stats
, "alloc=%d free=%d depth=%d same=%d all=%d\n",
write(mprof_file
, stats
, strlen(stats
));
sprintf(stats
, "fmem=%d dmem=%d lmem=%d smem=%d\n",
(mprof_fmemC
* MPSYM_SIZE
) / 1024,
(mprof_dmemC
* MPDATA_SIZE
) / 1024,
(mprof_lmemC
* MPCELL_SIZE
) / 1024,
(mprof_smemC
* MPSSTK_SIZE
) / 1024);
write(mprof_file
, stats
, strlen(stats
));
mp_print_bins(mprof_file
);
mp_print_leak_table(mprof_file
);
set_mprof_autosave(count) -- set the autosave count of profile data
int count; count = 0 (default) implies no autosave
mprof_stop() -- stop the memory profile in progress
mprof_restart(datafile) -- restart memory profiling
set_mprof_autosave(count
)
"mprof_restart -- restart ingnored; memory profiling in progress\n");
mprof_initialized
= FALSE
;
mprof_filename
= datafile
;
"mprof_stop -- stop ingnored; memory profiling not in progress\n");
extern char **__Argv
; /* hack */
ldptr
= ldopen(__Argv
[0], NULL
); /* hack */
pdrarray
= (pPDR
) malloc (sizeof(PDR
) * SYMHEADER(ldptr
).ipdMax
);
#ifdef notdef /* doesn't work for libraries compiled -O */
for (i
= 0; i
< SYMHEADER(ldptr
).ipdMax
- 1; i
++) {
if (ldgetpd(ldptr
, i
, &pdrarray
[i
]) != SUCCESS
) {
printf("bad pdr %d\n", i
);
/* indirectly read in pdr table through the file descriptor table */
for (pfd
= PFD(ldptr
); pfd
< PFD(ldptr
) + SYMHEADER(ldptr
).ifdMax
;
for (i
= pfd
->ipdFirst
; i
< pfd
->ipdFirst
+ pfd
->cpd
; i
++) {
if (ldgetpd (ldptr
, i
, &pdrarray
[i
]) != SUCCESS
) {
fprintf(stderr
, "can't read pdr %d\n", i
);
if (pdrarray
[i
].isym
!= isymNil
) {
if (ldtbread(ldptr
, pfd
->csym
? pdrarray
[i
].isym
:
pdrarray
[i
].isym
+ SYMHEADER(ldptr
).isymMax
, &asym
)
fprintf(stderr
, "can't read symbol");
pdrarray
[i
].adr
= asym
.value
;
/* This is guaranteed to be between __start and main. */
mp_root_address
= pdrarray
[1].adr
- 1;
int low
= 0, high
= SYMHEADER(ldptr
).ipdMax
- 1, mid
;
/* do binary search on address */
if (loc
< pdrarray
[mid
].adr
) {
} else if (loc
> pdrarray
[mid
].adr
) {
return (&pdrarray
[low
- 1]);
/* return return address and update fp
1. I am told what my current fp and pdr is
2. see what the return register is
3. see if return reg is on stack
4. add the framesize to framereg to get the virtual fp
5. add the frameoffset to fp to get to the save register area
6. read the stack to get the return address
punt("return addreses not in a saved register");
if (!(pdr
->regmask
& (1 << pdr
->pcreg
))) {
/* in a register and register is not saved */
punt("don't know how to get register");
if (pdr
->framereg
!= 29) punt("framereg != 29");
saved31loc
= fp
+ pdr
->regoffset
;
/* assume pcreg is 31, else have to figure out where it is in saved
if (pdr
->pcreg
!= 31) punt("return reg not 31");
retaddr
= *(int *) saved31loc
;
fprintf(stderr
, "%s\n", str
);