[m-users.] How to write stack-friendly mercury-code?

Paul Bone paul at bone.id.au
Tue Mar 29 23:07:12 AEDT 2016

On Tue, Mar 29, 2016 at 01:30:17PM +0200, Dirk Ziegemeyer wrote:
> Hi Paul,
> > Am 28.03.2016 um 12:51 schrieb Paul Bone <paul at bone.id.au>:
> > 
> > On Mon, Mar 28, 2016 at 11:51:52AM +0200, Dirk Ziegemeyer wrote:
> >> Hi,
> >> 
> >> when I increase the data volume that is processed by a mercury application, the windows-version (asm_fast.gc/i686-w64-mingw32.static) stops at runtime with this error message:
> >> 
> >> *** Mercury runtime: caught segmentation violation ***
> >> This may have been caused by a stack overflow, due to unbounded recursion.
> >> exiting from signal handler
> >> 
> >> The Mac OS X version (hlc.gc/x86_64-apple-darwin14.5.0) still works.
> > 
> > Hi Dirk,  There's a couple of things you can do.
> Thank you for explaining the options to improve stack usage and especially the examples of non-obvious non-tail-recursive code.
> I’m running through these options to see what helps.
> > + Enable --last-call-modulo-recursion optimisation (LCMC).
> > 
> >    This will make map tail recursive by performing the construction [Y | Ys]
> >    before the recursive call, and filling in the value Ys in this term
> >    within the recursive call.
> I wasn’t successful yet with the best option of all: to make the code tail recursive. Call the compiler with command
> „mmc --make --optimize-constructor-last-call“
> didn’t solve it and the problematic part of the code was not apparent to me yet. Is this the option you mean with „--last-call-modulo-recursion“?

yes, that's it.  I didn't remember the name properly.

> > + Use a segmented stack
> > 
> >    If you use --stack-segments (an stseg grade component, compatible with
> >    low level C grades) then a segmented stack will be used, a segmented
> >    stack grows and shrinks as necessary.  Unbounded recursion can now cause
> >    your computer to thrash, rather than just crashing your program. This
> >    is the easiest option, but it doesn't reduce your program's memory usage.
> >    It's a good option if the limit is the size of the stack, and not how
> >    much RAM you have.
> I’ll try the stseg-grade next. This will take me some time because I first need to install this grade for the MingGW-Cross-Compiler.
> > + Increase the size of the stack.
> > 
> >    In low-level graces, like asm_fast, put MERCURY_OPTIONS="--detstack-size
> >    N" in your environment.  Check the Mercury user's guide.
> A fruitless try was to put this in the last line of file Mercury.options:
> MERCURY_OPTIONS = --detstack-size 8192

MERCURY_OPTIONS is an environment veriable.  On Linux/BSD/OS X you would do
something like:

    $ MERCURY_OPTIONS="--detstack-size 8192" ./my_program


    $ export MERCURY_OPTIONS="--detstack-size 8192"
    $ ./my_program

I know that windows has environment variables but I don't know how to
set/use them.

> > I've been working on some changes to Mercury that will make it easier for
> > developers to find which parts of their program are potentially causing
> > crashes due to stack exhaustion.
> Are your changes available in a recent rotd already? I have to make a new install of Mercury with stseg anyway.

Some of them are in this year's ROTDs.  All versions have a
--warn-non-tail-recursion option.  However this option isn't very smart
about what it reports as a lack of tail recursion.  I've tried to improve it
to help it catch the not-obvious things, without reporting the definitly
obvious things.

This option is still likely to be very noisy, so I've added a pragma that
helps control the amount of warnings you will get.

Firstly you can tell it that you _know_ some code is not tail recursive and
you don't want to see a warning for it, because you know it can't be fixed
or isn't why your program crashes.

    :- pragma require_tail_recursion(harmless_predicate_name/2, [none]).

Or, if you only want warnings for one or two predicates in your whole
module, then you can add this predicate without the "[none]" option to those
predicates and _not_ execute mercury with --warn-non-tail-recursion:

    :- pragma require_tail_recursion(problematic_predicate/2).

There are other things you can do, more information is in the reference
manual, but commented out until the feature is stable:


Paul Bone

More information about the users mailing list