Graphical Debugger Call Stack Pane: Significance of arrow sides and gaps in the stack

I’m trying to decode what the call stack pane of the graphical debugger is trying to tell me. Consider this example:
image

I believe that the far left column is the stack and that columns (only one here) to the right of it represent completed goals with open choice points. Three questions about this image:

  1. It seems like each column on the right also represents a particular rule instance and all open choice points that are clauses from that rule get stacked in the same column too. Is this correct?
  2. Is there any significance to which side of a box an arrow originates from? I’m surprised, for example, that the arrow from objectFromName/4 originates on the right side of the box and points to the right side of nameOf/4 when it seems like it could have been on the left side of both (just like the arrow from unknownProperty/3 to not/). That’s why I suspected some significance…
  3. Is there any significance in the gap in the right column between rdf/4 and objectFromName/4?

Let me try to explain :slight_smile: You know a traditional stack, I suppose. That is the left most column for the place you are now. Next, we have choicepoints. These are connected to stack frames. If a stack frame has a connected choice point it is marked with the splitting road icon. The arrows link the most recent choice point to older ones. Now the placement. The Y-coordinate expresses the depth in the call tree. Multiple frames can be at the same level, so we make additional columns to place them.

I think the right-most error should probably have been drawn on the left. Not sure, but it looks like a dubious choice of the placement algorithm in xpce.

Note that you can click on these choice points and see where they come from. Also note that on any of these frame you can select up and get the caller. If the caller is not yet in the picture it will be added.

This view is useful for diagnosing unwanted non-determinism. Typically you simple skip over the predicate that has unwanted determinism and then click the choicepoint and possibly do an up to see the context.

That isn’t really a direct answer to your question. I think you should be able to link this story to your questions though. Keep asking if not :slight_smile:

1 Like

The more I follow your questions and see the answers from Jan W., the more I think that trace and/or gtrace need some enhancements, e.g.

  1. Option to show all heads tried even if they fail, think Prolog Visualizer
  2. Show all heads available based on indexing, even before selection. I am thinking this would be a new panel for gtrace.
  3. Option to show all frames.
  4. Option to order the frames at the same level, (think stack) from left to right or right to left.
  5. Option to highlight the path from the current head back to the original head. This would add missing frames and such if needed. A note on using this should explain why it stops at the level around 9 which as every frame below that is used for the base system, e.g. what existed before gtrace engaged.
  6. One option that I really would like, and might exist but haven’t found it, is that when using with DCGs that are done with codes is to show the bound values as codes and also as strings. Right now they are automatically converted to strings which means one has to manually intervene to see if the value was a string or codes. This caused me much confusion for months on why my DCGs where failing and I even resorted to using format/3 statements instead of gtrace to resolve the problem. Once I learned about how gtrace converts codes to strings before displaying the value, understanding that made using gtrace with DCGs more pleasant.
  7. I agree that the gtrace icons need a higher level of resolution, e.g. I think they are currently 16x16 and 64x64 would be nicer.

While you are doing a wonderful job of digging in and finding nooks and crannies, even some I did not know, and while you plan to document all of this, in a way you are spearheading a design review whether you intended that or not. :slightly_smiling_face:

OK, I think I get the model now and I know where I was getting confused.

I was reading the columns to the right of the “current stack column” (i.e. the first one) as significant in their own right, thinking that the vertical grouping of predicates was somehow meaningful.

Now I think the columns are meaningless in themselves. The right way to read the graphic is as horizontal slices where each horizontal slice represents a stack level (as returned by prolog_stack_frame_property/2). As a new predicate is found with an open choice point, it gets pushed right, FIFO-like, into the horizontal slice that represents the stack level it is at.

So this answers my question about what the “gap” in the second column of the graphic is: It just means there aren’t any open choice points at the same stack level as unknownProperty/3.

BTW: after you press u to see the caller of an open choice point, what do you press to make that go away ? They tend to obscure other choice points. The only way I’ve found is to step, which isn’t usually what I want.

OK, but now I have to ask why the behavior of showing the stack frame level of an open choice point is helpful. What intuition is it designed to give you? Why not just stack up the choice points in newest to oldest order and not even deal with the arrows (at least the arrows that aren’t pointing from/to the current stack)?

Maybe I’m missing something but I’m imagining the stack level is basically arbitrary given the “tree searching” behavior of prolog, and I haven’t found a way to get any useful intuition from that specific feature yet.

Edit: I think I just answered my question: If you press press u until you see the whole call stack of a choice point (as I’ve done below for the two choice points on the right), the behavior above makes it so that you can visually construct what the whole stack will look like when it gets activated by mentally sliding the choice point stack left and merging it with the active stack:

image

This only works if the choice point you click on is not higher than the current highest frame in the stack. The debugger seems to remove empty levels when this happens so this trick won’t work. An example is the rd/4 choice point in the graphic at the top of this thread. That choice point could be 30 levels deeper than the current stack but the debugger just shows it one level below. I assume this is so things don’t visually disappear.

I don’t think that is possible. I must say I’ve never missed it. Shouldn’t be too hard to add. One must always choose between UI complexity and functions though.

We have the conventional stack and a chain of choice points. Each of these have a stack as well, each eventually links up with the current active environment stack. I guess it is better to make a picture, but I do not have time now. Hope you get it. We have two types of choice that can be distinguished: those on my parent frame(s) and those that are not. The ones that are not (and thus stand to the right) are subgoals that succeeded with a choice point. If you seek for deterministic last-call optimized code, these are bad. So yes, this helps.

If I recall well, the frames are ordered by depth, but missing values are removed when assigning Y coordinates. Only the relative depth provides information, the absolute value not (and can be huge).

I think you are pretty close to understanding how the stack view works. Note that I’m not claiming it is perfect. It was my first attempt to visualize both parents and choicepoints and I don’t think it was ever changed. Possibly something smarter can be designed. For me it works pretty well :slight_smile:

The main usability issues I have with the debugger are more in easily examining values, why values do not unify (e.g., why no clause matches some goal) and navigating to the interesting point (maybe we need break/spy points with conditions). Notably finding why a deeply nested recursive call finally misbehaves can be tiresome.

1 Like

One thing I’ve noticed is that this workflow hangs the system if the predicate happens to be the top level query predicate and the system is waiting for input when you press u. I entered an issue here. Let me know if there’s a better way to record this kind of bug.

1 Like