[comp.lang.lisp.x] xlisp 2.1 tc

cwhitley@mole.gnu.ai.mit.edu (Cecil H. Whitley) (04/25/91)

Hi,
I am having some trouble with xlisp 2.1 tc.  I compiled the source
using tc++ 1.0 and it apparently runs fine.  The problem comes up when 
I try to use a recursive function.  I wrote a recursive version
of factorial with one parameter x.  On the 53 iteration it runs out
of argument stack space.  Did I compile it wrong?  I used the
makefile that came with the source.  The only other possibility is
the differences between tc 2.0 and tc++ 1.0.
Any suggestions of where to look would be appriciated.
Cecil
cwhitley@mole.ai.mit.edu
|
cwhitley@gnu.ai.mit.edu

toma@sail.LABS.TEK.COM (Tom Almy) (04/25/91)

In article <15243@life.ai.mit.edu> cwhitley@mole.gnu.ai.mit.edu (Cecil H. Whitley) writes:
>Hi,
>I am having some trouble with xlisp 2.1 tc. [...] The problem comes up when 
>I try to use a recursive function. [...] On the 53 iteration it runs out
>of argument stack space.  Did I compile it wrong?

You did it right. That's all the depth you get. Its all a funtion of the
compilation constants EDEPTH and ADEPTH, and the stack size (_stklen) 
specified for Turbo-C. Here is a report on this and other tuning factors
that I posted in January 1989. If you are running XLISP that has passed
through my hands, then the situation is much improved over the distribution,
but you may want to change the constants:
**************
The following problems apply, in part, to XLISP running on any system.  In
my case, I am running on an 80386, MS-DOS system (with PharLap DOS Extender
being used for native 80386 operation).  I had noticed that the distributed
(Turbo-C) version of XLISP would crash upon "too much" recursion, rather
than give an error. I discovered that the default stack size (4k, I
believe) was used, and the size of argument stack (ADEPTH in xlisp.h) and
evaluation stack (EDEPTH) were far bigger than could ever be utilized. 
Also, the argument stack would overflow well before the evaluation stack
when using a large program stack.

                              Setting EDEPTH

The growth of the system (C language) stack roughly parallels that of the
evaluation stack.  For a simple recursive function of the form "(defun foo
(...) (cond (..(foo ..))))"  seven evaluation stack cells are used per
recursion.  With an 8086 style compiler, roughly 200 bytes are used on the
system stack per recursion, while in the 80386 environment 270 are used (I
would expect a 68000 would be about the same as an 80386).  Thus, there
should be 28 or 38 bytes per cell.  With the default EDEPTH of 2000, which
allows 280 deep recursion, an 8086 compiler needs a stack of 56k bytes,
while an 80386 (or 68000?) needs 76000 bytes.  Considering the scarcity of
avalailable memory under MSDOS, EDEPTH should probably be reduced instead
in this environment!  With a stack size of 16k, EDEPTH could be set to 580,
allowing about 80 deep recursion.

                              Setting ADEPTH

With the above simple recursive function, the argument stack grows at the
rate of 6 + #arguments per recursion, or typically the same rate as the
evaluation stack.  Heavy use of local variables in an iterative program
will cause the argument stack to grow much faster.  Yet the default ADEPTH
value is 1000, or half of EDEPTH!  ADEPTH should be at least as large as
EDEPTH!

                          Performance Measurement


;;;;; NOTE: THIS IS VERY DATED. ALL OF THE COMPILERS ARE IMPROVED, AND
;;;;; I'VE ACHIEVED PERFORMANCE ENHANCEMENTS IN THE CODE!!!
;;;;; IN THE 16 BIT WORLD, THE ZORTECH 2.1 COMPILER DOES BEST, FOLLOWED
;;;;; BY THE BORLAND C++ 2.0 (AS A C COMPILER). THE METAWARE COMPILER
;;;;; STILL IS BEST FOR 32 BIT OPERATION.

I compared XLISP 2.0 compiled under 5 different compilers.  In each case,
compiler options were used to specify floating point coprocessor, maximum
speed optimizations, word aligned data, and most advanced processor (80386,
80286, in that order).  During execution, the minimum system configuration
was used, allowing maximum memory (of 8 megabytes) to be used by XLISP. 
The execution time measured was of a program which plays a game of akalah
with itself (as good as any benchmark I would guess).

Compiler       executable     maximum   stack used     execution
               size           nodes     per recursion  time
Turbo 1.5      123878         40640     202            83.5 sec
Zortech 1.07   137806         40640     204            85
Microsoft 5.0  141536         36640     200            86.5
Microway NDP 1.4e
(80386)        200888 + stack 594640    248            58.5
Metaware HighC 1.4
(80386)        203275         592640    268            57.5

Notes:
Turbo-C compiled without a hitch (after all, that was how it was
distributed).  Zortech (was Datalight) would not compile xldmem.c with
optimization (compiler bug reported).  The Zortech compiler choked on some
expressions where types did not match (this is actually good).  Microsoft
optimization had to be disabled to generate a working executable.  Microway
did not provide longjmp support (I had to write it in assembler), and their
"shell escape" code could not be used because it gave unresolved routines
in the linker.  Microway also didn't provide a primitive DOS call
mechanism, so I had to write the keyboard/display primitives in assembler.
Only the Microway compiler would compile the sources without warnings. 
Metaware didn't provide a "shell escape" call, so I wrote one which I also
used for Microway.  The primitive DOS call mechanism was different than
that of the three 8086 compilers.  Like Zortech, this compiler was finicky
about types matching, and choked on several modules.  Metaware allows
turning off allignment, which drops the size of nodes from 12 to 10 bytes. 
In this case, the maximum nodes jumps to 708,640, and execution time goes
up to 59.5 seconds.

Draw your own conclusions.






-- 
Tom Almy
toma@sail.labs.tek.com
Standard Disclaimers Apply