Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Out of local stack? (SWI)

414 views
Skip to first unread message

seguso

unread,
Dec 29, 2003, 2:01:21 PM12/29/03
to
Hi,

I am using swi-prolog for this GPL project:
http://segusoland.sourceforge.net.

After 4-8 hours, my main loop crashes with "Out of local stack"
exception. Why?


mainLoop(Tasks):-
var(Tasks),
writeln(error-var-tasks),
throw(var-tasks).
mainLoop(Tasks):-
nonvar(Tasks),
sleepUntilEventIsRaised(E),
(
E=checkListBoxItemExecuted(checkListBoxOfKind(verb), I)->
onVerbExecuted(I, Tasks, NewTasks);

E=checkListBoxItemSelected(checkListBoxOfKind(verb), I)->
(onVerbSelected(I), NewTasks = Tasks);

% ... [snip] many similar calls...

E=windowDestroyed(mainWindow)->
(onMainWindowDestroyed, NewTasks = Tasks);
(writeln(ignoredEvent(E)), NewTasks = Tasks)),

(E=windowDestroyed(mainWindow)->
writeln('exiting program');
E = menuItemClicked(quitItem)->
writeln('exiting program');
mainLoop(NewTasks)).

I'd like to know if the reason for the leak is to be searched for
in the prolog code, or in the following predicate written in C:


foreign_t sleepUntilEventIsRaised(/* out*/term_t oEvent){
while(gLatestEvents.size()==0){
gGtkMain->iteration(true); // true = blocking.
// If we are here, AT LEAST one gtk event was
// generated, and ZERO OR MORE callbacks I defined
// have been called.
}

// if we are here, then AT LEAST one event is in the queue. We
// pick the first event from the list gLatestEvents, and unify
// oEvent with it.

// REGION if the event is not "timer", output to stdout
string lEvent = gLatestEvents.begin()->ToString(); //maybe it is this that leaks?
if (lEvent != "timer")
cout << "sleepUntilEventIsRaised: raising event " << lEvent << endl;
//END
cout << "sleepUntilEventIsRaised: event queue size = " <<
gLatestEvents.size() << endl;
PL_unify(oEvent,
gLatestEvents.begin()->ToPrologTerm());
gLatestEvents.pop_front();
PL_succeed;
}

Thanks for any help.
--
Best Regards,
Maurizio Colucci
Please remove the uppercase letters "S,P,A,M":
seSgPuAsM...@tin.it

Jan Wielemaker

unread,
Dec 30, 2003, 3:42:48 PM12/30/03
to

If this mainloop terminates on "Out of local stack" this must mean the
system doesn't do last-call optimization on the recursive call to
mainLoop/1. There can only be two reasons for this. One is that you have
the debugger enabled, which causes SWI-Prolog not to do last call
optimization. The other is that something leaves a choicepoint. To find
out, enable the source-level debugger (if this cooperates with your gtk
interface) and step to the recursive call. If there are choicepoints
marked, click on them to find their context. If you can't use the
source-level debugger, the normal tracer defines the command 'A'
(alternatives). Only it is a bit harder to understand the output.

Finally if you consider yourself among the `quick-and-dirty' programmers
(I don't think so considering earlier questions :-) you can insert a cut
just before the recursive call to ensure determinism. Good style
programming demands unwanted choicepoints to be removed as soon as they
are known to be unwanted.

Finally, as a matter of style, I don't really like a giant switch

( E = x
-> ...
; E = y
-> ...

Introducing an intermediate predicate

action(Event, Tasks, NewTasks)

with one clause per event will make your code a lot more readable.

Success --- Jan


seguso

unread,
Dec 30, 2003, 5:25:41 PM12/30/03
to
My reply will probably look a bit dumb...


> If this mainloop terminates on "Out of local stack" this must mean the
> system doesn't do last-call optimization on the recursive call to
> mainLoop/1. There can only be two reasons for this. One is that you have
> the debugger enabled,

But how do I tell if it's enabled? ( I read the manual but there is no
mention :-))
if I put trace inside my code, the text debugger appears in the cli. does
this mean the debugger is enabled?
If so, how do I disable it?

> which causes SWI-Prolog not to do last call
> optimization. The other is that something leaves a choicepoint. To find
> out, enable the source-level debugger (if this cooperates with your gtk
> interface) and step to the recursive call.

1) I can't see why you call the graphical debugger "source-level"...

2) I can't seem activate the graphical debugger. if I enter prolog by
typing "pl", then there is not predicate called guitracer/0. If I enter by
typing "xpce", it is there. But in my program, I invoke prolog from C,
with PL_initialise... can I use the graphical debugger in that case?

int main( int argc, char *argv[] ){
//...
PL_register_extensions(predicates);
if (!PL_initialise(argc, argv))
PL_halt(1);
callPredicate("consult('" + lPathWhereThePrologFileIsLocated + "/segusoLand')");
callPredicate("run('" + lPathWhereTheSubdirectoryImgIsLocated + "')");
PL_halt(0);
}


> If there are choicepoints
> marked, click on them to find their context. If you can't use the
> source-level debugger, the normal tracer defines the command 'A'
> (alternatives). Only it is a bit harder to understand the output.

I'm afraid I need a tutorial about using the debugger...

> Finally if you consider yourself among the `quick-and-dirty' programmers
> (I don't think so considering earlier questions :-) you can insert a cut
> just before the recursive call to ensure determinism. Good style
> programming demands unwanted choicepoints to be removed as soon as they
> are known to be unwanted.


Thanks Jan, if it hadn't been for your constant help I had dropped prolog
long ago. :-)

Jan Wielemaker

unread,
Dec 31, 2003, 5:26:56 AM12/31/03
to
In article <pan.2003.12.30....@in.signature>, seguso wrote:
> My reply will probably look a bit dumb...
>
>> If this mainloop terminates on "Out of local stack" this must mean the
>> system doesn't do last-call optimization on the recursive call to
>> mainLoop/1. There can only be two reasons for this. One is that you have
>> the debugger enabled,
>
> But how do I tell if it's enabled? ( I read the manual but there is no
> mention :-))

Initially (of course) the debugger is disabled. Typing ?- debug. or ?-
trace. enables it. You can find the current status using ?- debugging.

> if I put trace inside my code, the text debugger appears in the cli. does
> this mean the debugger is enabled?

Trace/0 starts the tracer. It will be in debug mode until you give the
`n' (nodebug) command.

> If so, how do I disable it?
>
>> which causes SWI-Prolog not to do last call
>> optimization. The other is that something leaves a choicepoint. To find
>> out, enable the source-level debugger (if this cooperates with your gtk
>> interface) and step to the recursive call.
>
> 1) I can't see why you call the graphical debugger "source-level"...

I often mix the terms. As the graphical debugger highlights the relevant
sourcecode it is also a source level debugger.

> 2) I can't seem activate the graphical debugger. if I enter prolog by
> typing "pl", then there is not predicate called guitracer/0. If I enter by

This is a bit odd. Using standard installation Prolog will (on Unix
systems) recognise the XPCE graphics system if the variable $DISPLAY is
defined. As you are doing graphics yourself I assume this variable is
defined. The binding is achieved through the file pl.rc in the Prolog
home directory.

> typing "xpce", it is there. But in my program, I invoke prolog from C,
> with PL_initialise... can I use the graphical debugger in that case?
>
> int main( int argc, char *argv[] ){
> //...
> PL_register_extensions(predicates);
> if (!PL_initialise(argc, argv))
> PL_halt(1);
> callPredicate("consult('" + lPathWhereThePrologFileIsLocated + "/segusoLand')");
> callPredicate("run('" + lPathWhereTheSubdirectoryImgIsLocated + "')");
> PL_halt(0);
> }

I think that should be fine, unless the Gtk and Xt (on which XPCE is based)
cannot live together. You must tell Prolog to load XPCE. You can do
this by passing the arguments -F xpce to PL_initialise() or by loading
xpce explicitely:

load_xpce :-
ensure_loaded(swi('xpce.rc')).

After that you can use gtrace/0 rather than trace/0 to start the
graphical debugger.



>> If there are choicepoints
>> marked, click on them to find their context. If you can't use the
>> source-level debugger, the normal tracer defines the command 'A'
>> (alternatives). Only it is a bit harder to understand the output.
>
> I'm afraid I need a tutorial about using the debugger...

The standard 4 port debugger is described in Clocksin and Melish and
many other texts about Prolog. The SWI-Prolog reference manual merely
describes the extensions. The command 'A' lists goals that, according to
Prolog, still have a choicepoint. If it lists any predicate called by
your main loop while you are are the call-port of mainLoop/1 you have
choicepoints left and the system cannot perform last call optimization.

>> Finally if you consider yourself among the `quick-and-dirty' programmers
>> (I don't think so considering earlier questions :-) you can insert a cut
>> just before the recursive call to ensure determinism. Good style
>> programming demands unwanted choicepoints to be removed as soon as they
>> are known to be unwanted.
>
> Thanks Jan, if it hadn't been for your constant help I had dropped prolog
> long ago. :-)

Happy hacking :-)

--- Jan

P.s. I keep telling it (people must be getting bored :-), but embedding Prolog
in C is an odd choice as it complicates one of the nice features of
Prolog: the ability to debug interactively, modify and reload the
source while the application remains running. You can also compile
your Gtk (and other extensions) to a SWI-Prolog foreign library, after
which you simply run your program using

== segusoLand.pl ==
:- initialization
load_foreign_library(foreign(mystuff)).

main :-
...


Then you can run

% pl -s segusoLand.pl
?- <set debug options, etc>
?- main.

If you are careful about the organisation of main/0 you can debug, abort
as you find a problem, edit and fix it, type ?- make. and restart main/0
without restarting your application.

For the final application you can use pl -o segusoLand -c segusoLand.pl,
though some care is needed to ensure segusoLand can find mystuff.so


seguso

unread,
Dec 31, 2003, 8:57:12 AM12/31/03
to
Il Wed, 31 Dec 2003 10:26:56 +0000, Jan Wielemaker ha scritto:

Thanks for your patience... with your help, I managed to enter the
graphical debugger.

Yes, something is leaving a choice point... this is the situation after a
few seconds:

http://segusoland.sourceforge.net/img/temp-trace.png

The onTimer/2 precidate is called once per second.

There must be some error in the onTimerAux/4 predicate... but it seems
well written to me... could you please tell me what's wrong (see picture)?
It should only take a minute for you to discover.

I'm afraid I am missing something really basic.

PS: If I insert cuts, as you suggested, the problem does not manifest, but
I'd rather use a declarative style...

> I think that should be fine, unless the Gtk and Xt (on which XPCE is based)
> cannot live together. You must tell Prolog to load XPCE. You can do
> this by passing the arguments -F xpce to PL_initialise() or by loading
> xpce explicitely:
>
> load_xpce :-
> ensure_loaded(swi('xpce.rc')).
>
> After that you can use gtrace/0 rather than trace/0 to start the
> graphical debugger.

This is great. I would like to see that in the manual.

> P.s. I keep telling it (people must be getting bored :-), but embedding
> Prolog
> in C is an odd choice as it complicates one of the nice features of
> Prolog: the ability to debug interactively, modify and reload the
> source while the application remains running.

I would never dare to do that :-)

> You can also compile
> your Gtk (and other extensions) to a SWI-Prolog foreign library, after
> which you simply run your program using
>
> == segusoLand.pl ==
> :- initialization
> load_foreign_library(foreign(mystuff)).
>
> main :-
> ...
>
>
> Then you can run
>
> % pl -s segusoLand.pl
> ?- <set debug options, etc>
> ?- main.
>
> If you are careful about the organisation of main/0 you can debug,
> abort as you find a problem, edit and fix it, type ?- make. and restart
> main/0 without restarting your application.
>
> For the final application you can use pl -o segusoLand -c
> segusoLand.pl, though some care is needed to ensure segusoLand can find
> mystuff.so

That's great, I will convert the program to use this technique.

Jan Wielemaker

unread,
Jan 1, 2004, 1:25:18 PM1/1/04
to
In article <pan.2003.12.31....@in.signature>, seguso wrote:
> Il Wed, 31 Dec 2003 10:26:56 +0000, Jan Wielemaker ha scritto:
>
> Thanks for your patience... with your help, I managed to enter the
> graphical debugger.
>
> Yes, something is leaving a choice point... this is the situation after a
> few seconds:
>
> http://segusoland.sourceforge.net/img/temp-trace.png
>
> The onTimer/2 precidate is called once per second.
>
> There must be some error in the onTimerAux/4 predicate... but it seems
> well written to me... could you please tell me what's wrong (see picture)?
> It should only take a minute for you to discover.

Pictures are a bit hard to quote :-( I'm not going to give a very detailed
description on what is wrong, but I'll mention a few things. A multi-clause
predicate will only be deterministic if first argument indexing gives only
one candidate clause or it succeeds on the last clause or it succeeds on
an earlier clause which has executed a cut. If you don't use cuts, you
should at least make sure later clauses negate the conditions that could
have made earlier clauses succeed (as in:

do(X) :- X > 0, ...
do(X) :- X =< 0, ...

Your code doesn't satisfy these demands, and worse, if you make the
predicate backtrack it will eventually throw the error from the last
clause. This predicate should either be written using if-then-else style
or after passing the conditions for the clause there should be a cut.
Remember you only get last-call optimisation if *Prolog* understands there
are no choicepoints, not if *you* can prove there is only one solution
and standard Prolog is pretty simple minded.

Happy hacking

--- Jan

P.s. The screendumps of segusoland look nice!

seguso

unread,
Jan 3, 2004, 12:04:42 PM1/3/04
to
Il Thu, 01 Jan 2004 18:25:18 +0000, Jan Wielemaker ha scritto:

> This predicate should either be written using if-then-else style
> or after passing the conditions for the clause there should be a cut.
> Remember you only get last-call optimisation if *Prolog* understands there
> are no choicepoints, not if *you* can prove there is only one solution
> and standard Prolog is pretty simple minded.

Thanks a lot for the lesson. That theory is just what I needed (and I
have no idea where I could find it).

I was assuming that tail-recursion was sufficient in order to have
last-call optimization... I am beginning to realize I don't have a good
background in prolog, only your reference manual :-)



> P.s. The screendumps of segusoland look nice!

Thanks! So the choice of using GTK was a good one. Looks are important
nowadays.

---

Many have told me "What? it is not in C? too bad, I would have been
willing to help you if it were..."

If i converted it to C I would have a huge list of helpers...

But I know at least two persons who are studying prolog because of my
program. :-)

djamé

unread,
Jan 14, 2004, 5:36:55 PM1/14/04
to

I've loooked in your code too and what you should consider is to check
that your clauses go from the most spécific case to the most général
one......rembember, order is very important in prolog (that's why peolpe
who are coming from a imperative language love the
( test = x ->
do_x
; test=y ->
do_y
; test = z ->
do_z
; % default
do_defaults
). % I know I should add all the parenthesis but I'm tired now....

in fact, maybe the first clause can match too much stuff....... so the
use of the cut is justified if you consider that you have to check one
and only one choice, so in order to debug maybe you shoulde add a cut to
all the lines 'Ontimer" and see wich one is always choosen.....


Djamé

ps to respond : my email is djame....@NOSPAM.loria.fr

0 new messages