How do you walk a BSP without recursion?..

Started by
13 comments, last by monkeyman 23 years, 4 months ago
Also recursion is bad for a branch-prediction.
All current CPU have a small return-address stack (usually 8..16 entries).

from AMD Athlon Processor x86 Code Optimization Guide :
quote:
Avoid recursive functions due to the danger of overflowing the return address stack. Convert end-recursive functions to iterative code.

When the 12 entry return-address stack gets out of
synchronization, the latency of returns increase. The return-address stack becomes out of sync when:
- calls and returns do not match
- the depth of the return-address stack is exceeded because
of too many levels of nested functions calls
Advertisement
Thread the BSP tree.
Use the Next pointer (threaded trees do !).

Good luck, dynamic tree threading is hard. I mean hard .
Look up Threaded AVL trees for some pointers...

no stacks, no recurrsion; just another 4bytes a node and a lot of programmer's grease.

Have none of you never heard of threaded trees!? Or am I on acid, and dreaming of something that doesn't exist?

...
quote:
In order to program any [unthreaded] binary tree traversal without explicit recursion (not just a BSP), you need to manually maintain a stack


...
I believe the end result of that recursion discussion ended (for me at least) with the empirical data of recursion costing you about 0.137Hz per node more than non-recursion.... don't remember the number exactly...
So that'd turn into 0.137 per node per frame for a bsp tranversals. And it's that per frame part that suddenly makes a difference. It's not huge, but might be a couple of %... not sure if I'd consider it worth it, but I'm curious to see the actually performance gain (or loss )
On 33MHz it could be a huge difference... but not so much on a 1GHz...


...
Hey monkeyman, using COMdomized code is a bit easier than creating COMdomized code! And when I was a newbie, I could have made pong! I made my own acsii qbasic Bomb! game :p


...
quote:
[MSCV optimizes] tail recursion into a simple loop.

Using the stack as a non-recursive stack implementation? or how? You mentioned this before, I'm just curious how it does it...


...
Doesn't a bsp's do most of its work by virtual of the transversal? ie little work to do when visiting a node, it's either in or out, next node?

Edited by - Magmai Kai Holmlor on December 5, 2000 2:11:24 AM
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
quote:Original post by Magmai Kai Holmlor
Thread the BSP tree.
Use the Next pointer (threaded trees do !).

Good luck, dynamic tree threading is hard. I mean hard .
Look up Threaded AVL trees for some pointers...

no stacks, no recurrsion; just another 4bytes a node and a lot of programmer''s grease.

Have none of you never heard of threaded trees!? Or am I on acid, and dreaming of something that doesn''t exist?

...
In order to program any [unthreaded] binary tree traversal without explicit recursion (not just a BSP), you need to manually maintain a stack

If you want to get technical, then you might say that you are maintaining the stack by threading the tree.... After all by threading the tree you''re maintaining a linked list layer on top of the tree which stores traversal order....

And of course, in order to thread a non-threaded tree you have to do an inorder traversal anyway.

quote:
------------
[MSCV optimizes] tail recursion into a simple loop.
------------
Using the stack as a non-recursive stack implementation? or how? You mentioned this before, I''m just curious how it does it...

Given
class Node {  public:    Node * left;    Node * right;    int data;};void Traverse(Node * root) {  if (root == NULL) return;  Traverse(root->left);  printf("%d\n", root->data);  Traverse(root->right);} 

(Yes, it''s a brain-dead traversal implementation, but it''s the code that most clearly illustrates how the tail-recursion is handled.)
MSVC on /Ox will turn it into
_root$ = 8?Traverse@@YAXPAVNode@@@Z PROC NEAR			; Traverse; File node.cpp; Line 10	push	esi; Line 11	mov	esi, DWORD PTR _root$[esp]	test	esi, esi	je	SHORT $L551$L548:; Line 12	mov	eax, DWORD PTR [esi]	push	eax	call	?Traverse@@YAXPAVNode@@@Z		; Traverse; Line 13	mov	ecx, DWORD PTR [esi+8]	push	ecx	push	OFFSET FLAT:$SG539	call	_printf; Line 14	mov	esi, DWORD PTR [esi+4]	add	esp, 12					; 0000000cH	test	esi, esi	jne	SHORT $L548$L551:	pop	esi; Line 15	ret	0?Traverse@@YAXPAVNode@@@Z ENDP				; Traverse 

So basically what it does, rather than pushing the arguments and using a call on the second call to Traversal, it just replaces the original argument on the stack with the new argument and jumps to the top of the call.
However, the first call to traversal still has the normal calling overhead. So a completely psycho hand coded assembly implementation will still beat out the MSVC optimized version, but the MSVC optimized version still beats a naive assembly implementation of the code.

quote:
Doesn''t a bsp''s do most of its work by virtual of the transversal? ie little work to do when visiting a node, it''s either in or out, next node?

If I understand what you''re saying (by virtual??) then usually to use a BSP, you start at the top and move to one side or the other, and don''t need to do a full in-order traversal. However, traversals are still useful. Ex: dumping debugging information to a log file.
quote:Original post by monkeyman
Gee, you don''t sound like such a dick after all


Yeah, well, I was in a pretty bad mood for a month before and after I posted that rant. It wasn''t meant to be constructive at all.

I still get pissed off at stupid questions, but implementing a recursive algorithm iteratively is hardly a stupid question.

Anyway, glad I could help.

MSN
I beleive I ment virtue, not virtual...

...
You don't thread the tree right before you transverse it!

You have to thread the tree as you build it, whenever you add something or remove soemthing, you have to manipulate the next pointers that are effected by the change. Thats that hard part of the threading.



And I don't think threading a tree is in any way like a stack; it is a linked list of all the bsp nodes, intertwined with the tree itself. ...because you twiddle the next pointers during the manipulation of the tree, it's not a stack. Stuff doesn't just go on one end and come off the same end. It gets twiddled all over the place, mostly in the middle, which is not the behavior of a stack. It is a good way to transverse a tree in-order (which recursion does not do at all!), but that doesn't help with a BSP.


...
Wait a minute, why do you have to transverse the *BSP* tree?
ooooohhhhhhh.... I'm not sure threading the tree will solve this problem. You only need to transverse a portion of the BSP tree, not the whole thing.
The BSP should always be in order, correct? It's not like a BST where the next node could be damn near anywhere. In a BSP are not all neighbooring nodes are either a child or a parent?

If I was more familar with BSP'ing I might be of more help...

Exactly what kind of transversal is needed? It seems to me that you first need to search the tree, then iterate a sub-tree. Depending on the search criteria, you may be able to search with a simple loop. If the iteration needs to be in-order by the traditional notion of an in-order transveral, then you need to thread the tree. If you can use any 'ole transversal, so long as you get everything in the sub-tree, I think you can use a while and a bunch of if's.

Edited by - Magmai Kai Holmlor on December 5, 2000 10:11:41 PM
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

This topic is closed to new replies.

Advertisement