Back To Basics: Finding your stack usage

Beads

Handling stack overflow is a critical requirement for most Virtual Machines. For .NET Compact framework (NETCF) it is more important because it runs on embedded devices with very little memory and hence little stack space.

The .NETCF Execution Engine (EE) needs to detect stack overflows and report it via StackOverflowException. To do this it uses some logic which we internally refer to as StackCheck (that will be covered in a later post). The algorithm needs fair prediction of stack usage for system APIs (e.g. Win32 APIs or for Symbian OS, S60 APIs).

Each time we target a new platform we do some measurements in addition to referring to specs :) to find it's stack characteristics. As we are currently making the NETCF work on Symbian OS we are doing these measurements again. So I thought of sharing how we are going about measuring stack usage using simple watermarking.

The technique

Step:1

On method Entry store the two current and max stack values. This typically available via system APIs which in case of Symbian is available over the TThreadStackInfo class (iBase, iLimit and other members).

                        +---------------+
                       |               |
                       |               |
                       |               |
current stack ------>  +---------------+
                       |               |
                       |   Available   |
                       |    Stack      |
                       |               |
                       |               |
                       |               |
                       |               |
Stack limit ---------> +---------------+
                       |               |
                       |               |
                       .               .
                       .               .
                       .               . 

Step :2

Get a pointer on to the current stack pointer. How to get the pointer will vary based on the target platform. Options include system APIs, de-referencing stack pointer register (e.g. ESP register on x86) or simply creating a local variable on the stack and getting it's pointer.

Then Memset the whole region from current stack to the total available with some known pattern, e.g. 0xDEAD (a larger signature is a better approach to ensure there is no accidental match)

                        +---------------+
                       |               |
                       |               |
                       |               |
current stack ------>  +---------------+
                       |     DEAD      |
                       |     DEAD      |
                       |     DEAD      |
                       |     DEAD      |
                       |     DEAD      |
                       |     DEAD      |
                       |     DEAD      |
                       |     DEAD      |
Stack limit ---------> +---------------+
                       |               |
                       |               |
                       .               .
                       .               .
                       .               . 

Step: 3

Make an OS or whatever call you want to measure.

                        +---------------+
                       |               |
                       |               |
                       |               |
current stack ------>  +---------------+
                       |     1231      | --+
                       |     1231      |   |
                       |     D433      |   +--> Stack usage
                       |     D324      |   |
                       |     3453      | --+
                       |     DEAD      |
                       |     DEAD      |
                       |     DEAD      |
Stack limit ---------> +---------------+
                       |               |
                       |               |
                       .               .
                       .               .
                       .               . 

Step 4:

When the call returns the stack will get modified. Iterate through the memory starting from the current stack pointer looking for the first occurrence of the pattern you’ve set in Step:2. This is the water mark and is the point till which the stack got used by the OS call. Subtract the water mark from the original entry point saved in Step 1 and you have the stack usage.

Comments

  • Anonymous
    October 17, 2008
    As a cf.net programmer working (temporarily) on an S60 c++ project I can only say that it would be very cool to see the cf on s60.  My guess is that MS uses it internally for their s60 apps but is not necessarily going to release it to the developer community.  Is this the case?  Can you comment on this?

  • Anonymous
    October 18, 2008
    Currently there is no .NET Compact for S60 either internally or externally. We are just building the Silver Light Mobile for S60 (this has been jointly announced by MS and Nokia). Just like the Silver Light on the desktop there are a lot of commonality between SL and .NET but they are essentially different in terms of features, scenarios, etc... So we are building the part of the .NET that is required for Silver Light.