home *** CD-ROM | disk | FTP | other *** search
- {***********************************************************
- Stack5 - A unit to report stack usage information
-
- by Richard S. Sadowsky
- version 2.0 10/16/88
- for Turbo Pascal version 5.0
- released to the public domain
-
- Inspired by an idea by Kim Kokkonen and Brian Foley.
-
- This unit, when used in a Turbo Pascal 5.0 program, will
- automatically report information about stack usage. This
- is very useful during program development. The following
- information is reported about the stack automatically when
- the program terminates (just add this unit to your USES
- clause):
-
- Total stack space
- Unused stack space
- Stack spaced used by your program
-
- This unit is extremely similar to the file STKUSE.ARC
- in BPROGA LIB 6 on Compuserve. The difference is that
- this file has been adapted for use with Turbo Pascal 5,
- whereas STKUSE works with TP4. Since this program
- uses a hacker's technique to get the total stack value,
- it is somewhat version specific.
-
- The unit's initialization code handles three things, it
- figures out the total stack space, it initializes the
- unused stack space to a known value, and it sets up an
- ExitProc to automatically report the stack usage at
- termination. The total stack space is calculated by
- adding 8 to the current stack pointer on entry into
- the unit.
-
- The ExitProc StackReport handles the math of calculating
- the used and unused amount of stack space, and displays
- this information. Note that the original ExitProc
- (Sav_ExitProc) is restored immediately on entry to
- StackReport. This is a good idea in ExitProc in case
- a runtime (or I/O) error occurs in your ExitProc!
-
- Despite the fact that Brian Foley has pointed out some
- flaws in the method's used by this program, and uploaded
- his own TPSTACK unit which handles things somewhat
- differently (and also reports heap usage), I've decided to
- post this update. The reason is that Brian's TPStack
- reprograms the timer, and therefore can't be used (as
- currently implemented) with other units or programs
- that reprogram the timer. While in development, I often
- use TPTimer for high resolution timing, but also need to
- know the stack usage. The main flaw in my technique
- that Brian has pointed out is that it will not catch
- stack space reserved by a routine but not used.
- Consider the following:
-
- procedure EatTheStack;
- var
- BigLocalVar : Array[1..MAXINT] of Char;
- begin
- end;
-
- Stack5 will not show that this massive variable used
- any stack space (which of course it does, MAXINT chars
- worth) because the values in BigLocalVar have not been
- modified. Since I generally use any variables I declare
- (otherwise why waste the space), this doesn't present
- a major problem for me in most applications. In apps
- where it matters, I use Brian's TPStack, which reprograms
- the timer to tick more frequently, and "samples" the stack
- and heap sizes. Since SP is actually examined, his
- technique will show the above BigLocalVar's stack usage.
-
- I hope you find this unit as useful as I have!
-
- ***********************************************************}
- {$R-,S-} { we don't need no stinkin range or stack checking! }
- unit Stack5;
-
- interface
-
- const
- StackInitValue = $AA; { the value to initialize the stack to. }
- SAFETY = 20; { This value is used as a safety buffer }
- { when initializing the stack to the }
- { StackInitValue. This default of 20 }
- { is safe and shouldn't be lowered. }
- var
- Sav_ExitProc : Pointer; { to save the previous ExitProc }
- StartSPtr : Word; { holds the total stack size }
-
- implementation
-
- {$F+} { this is an ExitProc so it must be compiled as far }
- procedure StackReport;
-
- { This procedure may take a second or two to execute, especially }
- { if you have a large stack. The time is spent examining the }
- { stack looking for our init value (StackInitValue). }
-
- var
- I : Word;
-
- begin
- ExitProc := Sav_ExitProc; { restore original exitProc first }
-
- I := 0;
- { step through stack from bottom looking for StackInitValue,}
- { stop when found }
- while I < SPtr do
- if Mem[SSeg:I] <> StackInitValue then begin
- { found StackInitValue so report the stack usage info }
- WriteLn;
- WriteLn('Total stack space : ',StartSPtr);
- WriteLn('Unused stack space: ', I);
- WriteLn('Stack space used : ',StartSPtr - I);
- I := SPtr; { end the loop }
- end
- else
- inc(I); { look in next byte }
- end;
- {$F-}
-
- begin
- StartSPtr := SPtr + 8; { grab the current SP and account for used space }
- FillChar(Mem[SSeg:0], SPtr - SAFETY, StackInitValue); { init the stack }
- Sav_ExitProc := ExitProc; { save exitproc }
- ExitProc := @StackReport; { set our exitproc }
- end.
-