|
Can I track
stack usage with Aprobe?
/* Windows stack usage probe:
This probe will report the stack size and
usage for each thread in the application under test. The probe works by
hooking the entry of each thread and writing a known value to the unused
portion of the stack. On the exit of each thread the stack is examined to find the first byte from the top
that is not the known value.
Notes:
-
This probe has the effect of finding
many uses of uninitialized local variables (as the stack is now
dirty instead of zeroed). In the unlikely event that the program uses the value defined for
DIRTYWORD at its highest stack usage the wrong value for the stack
usage will be reported. If you suspect this, change the DIRTYWORD
value.
-
If thread 0 (the main thread) exits before another thread the stack
results for the other thread will not be reported. This is the
result of the main thread calling exit and the still-running threads
never getting a chance to execute. To fix this problem a more
elaborate bookkeeping scheme would be necessary. This problem will
be fixed in Aprobe versions 3.2 and above.
-
Aprobe adds a small (currently 2k bytes) buffer at the beginning of
each thread for exception handling. This amount is subtracted from
each usage size.
-
This probe will have the effect of slowing thread creation
times. The thread stack must be faulted in and written with
the DIRTYWORD value.
-
Remember on Windows-Intel the stack grows from high addresses to low
addresses.
*/
#include <stdio.h>
#define DIRTYWORD 0xDEADBEEF
probe thread
{
on_entry
{
int *StkHi, *StkLow, *StkCur, *i;
/* go get this
thread's stack values from
the windows thread local data area.
*/
__asm {
mov EAX,FS:[8]
mov StkHi,EAX
mov EAX,FS:[4]
mov StkLow,EAX
mov StkCur,ESP
}
printf("Thread
[%d] Stack Top: 0x%x, "
"Stack
Bottom: 0x%x, "
"Size:
0x%x bytes\n",
ap_ThreadIdToInteger
(ap_ThreadId()),
StkHi, StkLow,
((int)StkLow - (int)StkHi));
/* Dirty up the
unused portion of the stack: */
for (i = StkHi; i < StkCur; i++)
{
*i = DIRTYWORD;
}
}
on_exit
{
int *StkHi, *StkLow, *StkCur, *i;
int AprobeThreadAdjust;
/* Get this thread's
stack values again: */
__asm {
mov EAX,FS:[8]
mov StkHi,EAX
mov EAX,FS:[4]
mov StkLow,EAX
mov StkCur,ESP
}
/* Scan from the top
of the stack until we
find a word that isn't the
DIRTYWORD.
*/
if (ap_ThreadIdToInteger
(ap_ThreadId()) == 0)
AprobeThreadAdjust =
MAIN_THREAD_EXCEPTION_BUFFER_POOL_SIZE;
else
AprobeThreadAdjust =
NEW_THREAD_EXCEPTION_BUFFER_POOL_SIZE;
for (i =
StkHi; i
< StkCur; i++)
{
if (*i != DIRTYWORD)
{
printf(
"Thread [%d]
last unused address: "
"0x%x, used:
0x%x bytes\n",
ap_ThreadIdToInteger
(ap_ThreadId()),
i,
((int)StkLow - (int)i
-
AprobeThreadAdjust));
break;
}
}
}
}
|