Debugging: Tracing the Execution of a Specific Goal

Hello,

How do I trace the evaluation of a predicate only when a specified set of arguments is passed to this predicate?

So far I have been using spy(my_predicate) to creep through the evaluation of my_predicate during program execution. However, this has recently become tedious as there are numerous calls to my_predicate, but I am interested in tracing only those where my_predicate is passed the argument MyArgList.

In Sicstus, it is possible to use something like add_breakpoint(goal(my_predicate(MyArgList), _) to only trace execution when the pair (my_predicate, MyArgList) is invoked.

How can I achieve a similar result in SWI Prolog?

Thanks.

Not sure if the SWI-Prolog graphical debugger supports such functionality…?

In case your Prolog code can be wrapped by a Logtalk object (or in case it’s a module that Logtalk is able to compile as an object), you may be able to use the Logtalk debugger context spy points to only spy a specific predicate call template. E.g.

?- debugger::spy(_, _, _, foo(_, bar, _)).

That isn’t really provided. There are two alternatives. If you can point at a specific place in the code you can use the built-in editor facilities to place a break point inside some clause. So, if there is a predicate like this:

p(X) :-
    var(X),
    do_something(X).
9(X) :-
   ...

You can put the cursor on do_something and use the menu Prolog/break at

If that doesn’t help, you simple add this to your code at the place where you want a conditional break and run make/0.

    (some_condition -> gtrace ; true),

That may seem crude, but it works quite ok, especially if you use version control so you can easily check which debug statements you have added and/or reset the source.

With the recently added wrap_predicate/4 we could add conditional spy points easily. Not sure what it is worth though.

1 Like

Thank you @pmoura :slight_smile:
I will look into using this option once I have exhausted (in vain) all SWI-specific debug features to solve my issue.

Thank you @jan,

I have used the conditional tracing as you kindly suggested:
(condition_on_values_of_MyArg -> trace; true)

So now I am able to get directly to the desired predicate with the desired arguments.

Now, can I “leap” to the next evaluation of my_predicate with arguments MyArg? Adding a spy point for my_predicate allows me to leap to the next evaluation of the predicate but with different arguments though.

Is there another trick up your sleeve?

I try to collect them in Wiki: Bug hunting toolbox

2 Likes

Just use n(odebug) (c(ontinue) in the non-GUI tracer) or l(eap)? The next time it traps gtrace it will restart tracing. Note that leap implies debug mode. The debug mode pushes a dummy choice point for each otherwise deterministic predicate such that you can retry a goal. Unfortunately the result can be much slower and run out of memory. In nodebug mode this is no problem, but after the tracer is trapped a lot of parent frames may be missing due to last call optimization and many variables may be reset to <garbage_collected>.

2 Likes

Thanks everybody.

I often find myself adding a test inside a predicate, e.g.

my_pref(A,B,C) :-
    ( some_test(A) -> trace ; true ),  % added for debugging
    % the rest of the predicate ... 

and it would be nice if I could instead set the “trace point” without changing the source code (this is especially true if there are multiple clauses for the predicate).

But I don’t have a nice syntax to suggest; some_test is sometimes a structural test such asA=[_|_], sometimes a predicate such as ground(A), sometimes more complicated,