[comp.sys.amiga] Is she c:Stack'd

ba@m2-net.UUCP (Bill Allen) (09/29/89)

"Up your stack..."

What causes certain prgs to work just fine in 4K of stack
(or less) while others need 10K?  I've seen several that
require 20K, 30K, 40K.  Can other programming techniques be
used to prevent this?  The record is 60K and a "if it
crashes, increase it more".  Is this "poor" programming or
are there legitimate needs for unavoidable minimum 60,000+
byte stack.
-- 
---------------------------------------------------------
Reply-To: ba@m2-net.UUCP (Bill Allen Beogelein) M-NET, Ann Arbor, MI
or call Sharewarer's BBS at 313-473-2020 24hrs, PCP thru MIDET, 100% Amiga
---------------------------------------------------------

cmcmanis%pepper@Sun.COM (Chuck McManis) (09/30/89)

In article <3944@m2-net.UUCP> ba@m-net.UUCP (Bill Allen) writes:
>What causes certain prgs to work just fine in 4K of stack
>(or less) while others need 10K?  I've seen several that
>require 20K, 30K, 40K. 

Depends on what they put there. Some programs, like anything compiled
with Lattice 5.x will adjust the stack when they start up, others just
take what you give them.  

> Can other programming techniques be used to prevent this?  

Usually they can. A really common programmer error is to have a program
that does something like :
main()
{
	unsigned char	image1[640][200], image2[640][200];
	...
}
Or something equally innocent in appearance. What in fact happens is that
these two arrays, being local to the main function, get allocated on the
stack and that blow 256K of memory. Or even more common is a recursive
function that has some fairly large number of local variables. Anyway
those all eat up stack. 


> Is this "poor" programming or are there legitimate needs for 
> unavoidable minimum 60,000+ byte stack.

There are legitimate reasons why you might need lots of stack space
but I can't think of any off the top of my head :-). 

--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
These opinions are my own and no one elses, but you knew that didn't you.
"If I were driving a Macintosh, I'd have to stop before I could turn the wheel."

daveh@cbmvax.UUCP (Dave Haynie) (10/02/89)

in article <3944@m2-net.UUCP>, ba@m2-net.UUCP (Bill Allen) says:

> "Up your stack..."

> What causes certain prgs to work just fine in 4K of stack
> (or less) while others need 10K?  I've seen several that
> require 20K, 30K, 40K.  Can other programming techniques be
> used to prevent this?  

The difference usually amounts to something like this:

// Stack Wasting Example

void thing1(void) {
   char temporary[200000];

   // Do the interesting stuff

}

// Doesn't waste stack

void thing2(void) {
   char *temporary = malloc(200000);

   // Do the interesting stuff

   free(temporary);
}

// Doesn't waste stack

void thing3(void) {
   static char temporary[200000];

   // Do the interesting stuff
}


These functions would each do the same thing, only the first allocates
it's temporary buffer on the stack, and would take 200,000 bytes of stack
memory to run, the second allocates it's temporary buffer from the 
memory pool upon entry to the function, and returns that memory upon exit.
The third function allocates that temporary statically, for the life of the
program.  That doesn't take stack memory, but it might take more system 
memory at any given time than absolutely necessary, and of course will
cause trouble if the programmer expected a new "temporary" to be allocated
upon each entry to the function (often the case if you're using recursion).

The programmer should be sentitive to this.  Small allocations on the stack
are certainly no problem, but large ones are.  In most, though not every
case, programs that use lots of stack could be using less with more clever
programming.

> Is this "poor" programming or are there legitimate needs for unavoidable 
> minimum 60,000+ byte stack.

Chances are, that programmer never even thought about how much stack was 
being used.

> ---------------------------------------------------------
> Reply-To: ba@m2-net.UUCP (Bill Allen Beogelein) M-NET, Ann Arbor, MI
> or call Sharewarer's BBS at 313-473-2020 24hrs, PCP thru MIDET, 100% Amiga
> ---------------------------------------------------------
-- 
Dave Haynie Commodore-Amiga (Systems Engineering) "The Crew That Never Rests"
   {uunet|pyramid|rutgers}!cbmvax!daveh      PLINK: hazy     BIX: hazy
                    Too much of everything is just enough

UH2@PSUVM.BITNET (Lee Sailer) (10/03/89)

Would it be useful for Amiga compilers to at least partially detect
things like
   main() { int x[200000]; ... }
and WARN the user that this will use up a lot of stack?

sjk@ut-emx.UUCP (bob) (10/03/89)

Dave Haynie writes:
> in article <3944@m2-net.UUCP>, ba@m2-net.UUCP (Bill Allen) says:
> 
> 
  > What causes certain prgs to work just fine in 4K of stack
  > (or less) while others need 10K?  I've seen several that
  > require 20K, 30K, 40K.  Can other programming techniques be
  > used to prevent this?  
  
> The difference usually amounts to something like this:
> [exampes deleted]

Dave, you're probably right, the average programmer probably does
not know how much stack he is using, or even wonder, perhaps.  So
what constructs are there that require stack use?  I am a novice
C programmer and while I am capable of writing some relatively
complex code, I don't yet know enough about the internal operations
to know what structures use how much stack and why.  Where can I
learn this kind of stuff?  I think it would prove quite useful.  I
already have a few programs that need stacks ~50K and have no idea
why; it would be great to be able to change this!

Thanks,
Scot
sjk@astro.as.utexas.edu
Bdah!- M

new@udel.edu (Darren New) (10/03/89)

As far as I know, in Lattice C only automatic variables
live on the stack.  If there are other things on the
stack, you would have to change the run-time support
or maybe even the compiler in order to eliminate them.
Keeping large buffers off the stack is the easiest
way to cut stack usage.  However, it usually isn't
worth it unless you can cut the stack size
down to where the program will run with the default 
stack size (4K, I think), as the user will have to
set the stack anyway.  Usually the run-time routines and
the OS and libraries and ... will use some stack too,
but I don't remember how much; usually a few hundred
bytes is enuf for well-designed libraries. The secret is
to calculate and KNOW how much stack you need.
Just look at the nesting tree for your program and
add up all the automatic space used (plus alignment
and such) and find the branch that uses the most
stack space. That (plus a few K) is how big to make
your stack.  For recursive functions, you will need to
add some for the automatic variables of the recursive
function.  But basically, in C, automatic variables
are what use stack space.   -- Darren

usenet@cps3xx.UUCP (Usenet file owner) (10/04/89)

In article <620@nigel.udel.EDU> new@udel.edu (Darren New) writes:
>way to cut stack usage.  However, it usually isn't
>worth it unless you can cut the stack size
>down to where the program will run with the default 
>stack size (4K, I think), as the user will have to
>set the stack anyway.  Usually the run-time routines and
>the OS and libraries and ... will use some stack too,
>but I don't remember how much; usually a few hundred
>bytes is enuf for well-designed libraries. The secret is
>to calculate and KNOW how much stack you need.

Probly the best way is for the CLI to set the stack 
like the Workbench does.....

What I do for my own programs is have them set the stack themselves.
I use the technique by Werner Guenther (not sure about spelling) to
detach from the CLI by splitting the first segment away from the
rest, then do a CreateProc and have it set the
stack size this way.

How do I know how much stack?
(This works well for non-recursive, or limited recursion)
In the startup code (in the slipt off part) the first thing
it does is clear the stack to a constant (non-zero). It
then calls _main, and then counts the number of bytes on
the stack still containing that pattern, and prints
out info about stack usage. This is for development only.
Once the program is 'finished', then remove or disable
the stack counting stuff. ( i simply use a cmd line
arg "debug" to turn it on when I want).

For this to work proerly the program must be taken trough
all its functions, or at least the deepest (procedural wise)
functions.

REAL NAME: Joe Porkka   porkka@frith.egr.msu.edu

8610681@maven.u.washington.edu (10/04/89)

In article <19086@ut-emx.UUCP>, sjk@ut-emx.UUCP (bob) writes:
> Dave Haynie writes:
>> in article <3944@m2-net.UUCP>, ba@m2-net.UUCP (Bill Allen) says:
>> 
>> 
>   > What causes certain prgs to work just fine in 4K of stack
>   > (or less) while others need 10K?  I've seen several that
>   > require 20K, 30K, 40K.  Can other programming techniques be
>   > used to prevent this?  
>   
>> The difference usually amounts to something like this:
>> [exampes deleted]
> 
> Dave, you're probably right, the average programmer probably does
> not know how much stack he is using, or even wonder, perhaps.  So
> what constructs are there that require stack use?  I am a novice
> C programmer and while I am capable of writing some relatively
> complex code, I don't yet know enough about the internal operations
> to know what structures use how much stack and why.

	While it's certainly good for programmers to have knowledge
of the specifics of a machine, and understanding stack usage is a legitimate
exercise, it does seem rather silly to force applications to be written
quite differently on one machine than another. If I want to write code
like:

  int routine()
  {
    int big_space_waster[100000];
    { whatever}
  }

I should be able to. Now, it seems that on a non-virtual memory machine (or
any machine with a fixed stack space), that the compiler ought to be able to
optimize such large requests for local stack into a malloc() on entry
and free() on return itself. I should not be have to concerned with such
implementation details. Perhaps a flag on the compilation line would dictate
whether this behaviour was appropriate and what size of memory to start doing
this at.

Cheers,
Joe Meadows	joe@fhcrcvax.bitnet

fnf@estinc.UUCP (Fred Fish) (10/11/89)

In article <4837@cps3xx.UUCP> porkka@frith.UUCP (Joe Porkka) writes:
>What I do for my own programs is have them set the stack themselves.
>I use the technique by Werner Guenther (not sure about spelling) to
>detach from the CLI by splitting the first segment away from the
>rest, then do a CreateProc and have it set the
>stack size this way.

I just had a need to set my own stack also, in a program that was being
run from another program via Execute().  It turns out that the child
process was getting a 4K stack no matter what stack the parent process had.
Following a tip from John Toebes (thanks John!) I changed the call to
the Execute() command to look something like:

	Execute ("stack 40000\nmyprogram", ...)

which worked just fine.

-Fred
-- 
# Fred Fish, 1835 E. Belmont Drive, Tempe, AZ 85284,  USA
# 1-602-491-0048           asuvax!{nud,mcdphx}!estinc!fnf

walker@sas.UUCP (Doug Walker) (10/13/89)

In article <125522@sun.Eng.Sun.COM> cmcmanis@sun.UUCP (Chuck McManis) writes:
>In article <3944@m2-net.UUCP> ba@m-net.UUCP (Bill Allen) writes:
>Depends on what they put there. Some programs, like anything compiled
>with Lattice 5.x will adjust the stack when they start up, others just
>take what you give them.  
Not quite true, Chuck.  If you link with cres.o or cback.o it adjusts
your stack for you;  if you link with the normal c.o it doesn't.  However,
Lattice does CHECK your stack size for you unless you specify -v;  if your
program overruns the stack, a requester will pop up.

>
>> Can other programming techniques be used to prevent this?  
>
Sure.  Allocate everything with AllocMem, or declare variables static or
extern.  The following items get put on the stack:

1) Local variables (autos)
2) Function parameters
3) Function return values
4) Register saves
5) Temporary values that spill out of registers (generally a VERY small 
   number, less than 20 bytes).

The deeper your nesting level, the more stack you will need.  Thus,
recursive programs can be a problem.  I once had an application using 
N-way trees (each node can have 1-n children) and I walked the tree
using


   callmyself(rightsibling);
   callmyself(leftmostson);
   processmyself();

I thought this worked great!  Very little code, really efficient, right?
WRONG!  The trees I was dealing with were perhaps 4-5 levels deep, but
very broad.  The callmyself(rightsibling) was pushing itself onto the
stack once for each sibling at a given level.  I very quickly discovered
that stack size IS a problem!  I changed the code to

   for(current=me; current != NULL; current=current->rightsibling)
      callmyself(current->leftmostson);
   processmyself();

This relatively small code change saved THOUSANDS OF BYTES of stack,
while doing exactly the same thing as the previous code.


>> Is this "poor" programming or are there legitimate needs for 
>> unavoidable minimum 60,000+ byte stack.
>
>There are legitimate reasons why you might need lots of stack space
>but I can't think of any off the top of my head :-). 

The only reason would be very deep, legitimate recursion.  (By 'legitimate'
I mean 'unavoidable by simple tricks like above').  Cases that require
this kind of recursion are extremely rare.  99% of the time the 60K stack
requirement is due to the programmer allocating large auto arrays.
Remember, folks, any arrays you allocate in main() remain on the stack
the whole time you are running;  if you can do your parsing in a subroutine
instead of main(), for example, all the auto variables you used during parsing
will go away when you return.

>
>--Chuck McManis

--Doug Walker