Recursion: function stack limit is stifling
BlitzMax Forums/BlitzMax Programming/Recursion: function stack limit is stifling
| ||
Hey guys, This isnt really a bug, per se, but rather it seems to be a limitation of the compiler. Here are two background threads pertaining to my problem: http://www.blitzbasic.com/Community/posts.php?topic=61909 http://www.blitzbasic.com/Community/posts.php?topic=61962 I've developed a test program which you can compile in order to test this problem: Graphics (800,600, 0) 'These variables control the size of the array, as well as dictate the depth of the recursive algorithms: Global x_size:Int = 15 Global y_size:Int = 15 Global Container:Int[x_size,y_size] 'Comment out the first function call, traverseContainer() to get the program to run: '____________________________________________________________________________________ traverseContainer(x_size/2, y_size/2) 'traverseSouthEast(x_size/2, y_size/2) 'traverseNorthWest(x_size/2, y_size/2) '____________________________________________________________________________________ While Not AppTerminate() printContainer() GCCollect() Flip Cls Wend 'recursively goes through the container and changes all of the 0's to 1's: Function traverseContainer(x_coord%, y_coord%) If Container[x_coord, y_coord] <> 1 Then Container[x_coord, y_coord] = 1 Else Return End If If x_coord > 0 Then traverseContainer(x_coord - 1, y_coord) If x_coord < x_size - 2 Then traverseContainer(x_coord + 1, y_coord) If y_coord > 0 Then traverseContainer(x_coord, y_coord - 1) If y_coord < y_size - 2 Then traverseContainer(x_coord, y_coord + 1) End Function 'recursively traverses the container in the north and west directions only: Function traverseNorthWest(x_coord%, y_coord%) If Container[x_coord, y_coord] <> 1 Then Container[x_coord, y_coord] = 1 Else Return End If If x_coord > 0 Then traverseContainer(x_coord - 1, y_coord) If y_coord > 0 Then traverseContainer(x_coord, y_coord - 1) End Function 'recursively traverses the container in the south and east directions only: Function traverseSouthEast(x_coord%, y_coord%) If Container[x_coord, y_coord] <> 1 Then Container[x_coord, y_coord] = 1 Else Return End If If x_coord < x_size - 2 Then traverseContainer(x_coord + 1, y_coord) If y_coord < y_size - 2 Then traverseContainer(x_coord, y_coord + 1) End Function 'print the container to the screen: Function printContainer() Local k:Int Local j:Int For k=0 To x_size - 1 For j=0 To y_size - 1 DrawText Container[k,j], 225 + k * 30, 100 + j * 30 Next Next End Function edit: argh, nevermind, looks like I have to tweak my test case a bit more in order to get to the conditions which I found in my original program. |
| ||
Actually, it seems that this is the magic number in this particular test case:Global x_size:Int = 418 Global y_size:Int = 418 I'm having problems with this algorithm on a 12x16 array in my game program though :( |
| ||
With 417 x 417 your example reaches a stack depth of 86739. That should be enough for a 12 x 16 array. Graphics 800 , 600 , 0 Global PendingCalls:Int = 0 ' calls to traverseContainer without a matching Return Global MaxPending:Int = 0 Global x_size:Int = 417 Global y_size:Int = 417 Global Container:Int[x_size,y_size] traverseContainer(x_size/2, y_size/2) While Not AppTerminate() printContainer() GCCollect() Flip Cls Wend Function traverseContainer(x_coord% , y_coord%) PendingCalls :+ 1 maxPending = Max( PendingCalls, MaxPending ) If Container[x_coord, y_coord] <> 1 Then Container[x_coord, y_coord] = 1 Else PendingCalls :- 1 Return End If If x_coord > 0 Then traverseContainer(x_coord - 1, y_coord) If x_coord < x_size - 2 Then traverseContainer(x_coord + 1, y_coord) If y_coord > 0 Then traverseContainer(x_coord, y_coord - 1) If y_coord < y_size - 2 Then traverseContainer(x_coord , y_coord + 1) PendingCalls :- 1 Return End Function Function printContainer() Local k:Int Local j:Int DrawText "x_size = " + x_size + " y_size = " + y_size, 250 , 20 DrawText " Maximum stack depth = " + MaxPending, 250, 50 For k=0 To x_size - 1 For j=0 To y_size - 1 DrawText Container[k,j], 225 + k * 30, 100 + j * 30 Next Next End Function |
| ||
Ok, After further investigation, this does appear to be yer basic stack overflow. You can rebuild bmk to extend the stack - change this line in bmk_util.bmx... cmd=CQuote(BlitzMaxPath()+"/bin/ld.exe")+" -s" ...to... cmd=CQuote(BlitzMaxPath()+"/bin/ld.exe")+" -s -stack 4194304" ...or use the stack size of your choice - the above will give you a 4M stack. I think this is reserved stack mem, not commited - ie: it will only use memory if it has to, so you should be able to make it fairly large. Not sure, have to do a bit more research here as my previous assumptions appear to have been quite wrong! In addition, debugger.stdio.bmx in appstub.mod does NOT handle recursive code well! Will be publishing a syncmods fix for this soon. |
| ||
Could you make the stack size an option in bmk? |
| ||
...accessible via the IDE, preferably. You took the words right out of my mouth, Mark Tiffany! Excellent idea. Russell |
| ||
Anyone needing such a big stack should seriously rethink their algorithm. Given bukky's approach no amount of stack space (or processor speed) is going to save that algorithm at higher resolutions. |