Log in

View Full Version : Stack Overflow


vion11
12th June 2003, 13:57
I've build some recursive functions which forces VirtualDubMod and Avisynth Editor to disappear traceless if call level is too deep. Is stack limited to 64k? How can I catch this error?

WarpEnterprises
12th June 2003, 21:31
Example of your functions?

vion11
13th June 2003, 00:11
Function BlurMore (clip c , int nTimes )
{return ( nTimes == 0 ? c : BlurMore (Blur(c, 1), nTimes - 1))}

Tell me your maximum integer for parameter nTimes, please

WarpEnterprises
13th June 2003, 07:07
Ok I see.

version()
blurmore(500)
return last

Function BlurMore (clip c , int nTimes )
{return ( nTimes == 0 ? c : BlurMore (Blur(c, 1), nTimes - 1))}


is most I can get.

sh0dan!

Nic
13th June 2003, 15:10
VC6's stacksize by default is 1MB (IIRC)...If you actually need it bigger then you could probably use EditBin.exe that comes with VC6
(i.e.) EditBin /STACK:<number-of-bytes> avisynth.dll

But I don't actually know how you detect if the stacks going to run out (well, without exception handling)...ill look into that. Interesting :)

-Nic

vion11
13th June 2003, 17:09
Actually my intention is not blurring existing videos. But it works as a example. I'm more in automation of video content creation .

The following code extends the Subtitle() function and may interest whoever localizes video. For me it documents how slow avisynth is and its lack of a file reading function. A handling for userdefined optional parameter could avoid these wrapper functions.

But Avisynth has power..!! Hopefully I'm waiting for updates. And please, don't start with syntactic sugar like loop, while, for, next nor wend.

### Words2Video | vion11 | c/cologne/2003

### Some help with lists
Function ListGet(int nNum, string sList)
{ nPos1 = GWSWrap(nNum, sList)
nPos2 = GWSWrap(nNum + 1, sList + " !")
nReturn = nPos1 * nPos2
return (nReturn == 0 ? "" :
\ MidStr(sList, nPos1, nPos2 - npos1 - 1))}

Function ListCount(string sList, int nCounter)
{ return (ListGet(nCounter + 1, sList) == "" ? nCounter : ListCount(sList,nCounter + 1))}

Function GWSWrap (int nSearchPos, string slist)
{ return (GetWordStart(nSearchPos, sList + " ", 1))}

Function GetWordStart(int nSearchPos, string slist, int nCurPos)
{ return (sList == "" ? 0 :
\ nSearchPos == 0 ? 0 :
\ FindStr(sList," ") == 0 ? 0 :
\ FindStr(sList," ") == 1 ? GetWordStart(nSearchPos, MidStr(sList,2), nCurPos + 1) :
\ nSearchPos == 1 ? nCurPos :
\ GetWordStart(nSearchPos - 1, MidStr(sList,FindStr(sList," ")+1), nCurPos + FindStr(sList," ")))}

### getting prolific
Function MakeWordClip(sWords)
{ v = Blackness (ListCount (sWords, 0), 720, 576, "RGB24", 25)
return (PrintWordSequence (v, sWords, 0))}

Function PrintWordSequence (clip c, string sWords, int nCurrent)
{return (nCurrent == ListCount(sWords, 0) + 1 ? c :
\ PrintWordSequence (SubTitleFrameMid (c, nCurrent, ListGet (nCurrent + 1, sWords)), sWords, nCurrent + 1))}

Function SubTitleFrameMid (clip c, int frame, string sPhrase)
{ return (SubTitle(c,
\ sPhrase,
\ (c.width / 2) - (StrLen(sPhrase) * 16),
\ c.height / 2,
\ frame,
\ frame,
\ "Courier New",
\ 60, $FFFFFF, 0))}

MakeWordClip("AviSynth is a powerful tool for video post-production. It provides almost unlimited ways of editing and processing videos. AviSynth works as FrameServer, providing instant and very fast editing without the need for temporary files.")

sh0dan
14th June 2003, 11:31
Since the filter chain, and function calls are put on the stack, the length of the filter chain is limited by stack size.

I don't know if the size can be changed - or if it is really needed. In most cases very long filter chains are mostly expressing something that is either better to be done in a plugin, or suboptimal solutions.

Nic
14th June 2003, 13:17
That sounds right to me, if your using all the stack, then there's normally a better way...but if necessary the stack can be raised higher in the linker options when compiling AviSynth.dll

-Nic

Bidoche
14th June 2003, 14:07
We could use filter refactorisation to lower the filter chain depth and so the number of functions calls stacked.

For example :Trim(Trim(clip)) could be changed into Trim(clip)

and (which is the case in your script example) :Splice(Splice(Splice(Splice(... ...clip4), clip3), clip2), clip1)
changed into MultiSplice(clip1, clip2, clip3, clip4....)

sh0dan
14th June 2003, 21:00
@Bidoche: Right! Splice actually already accepts any number of clips.

Bidoche
14th June 2003, 23:46
Yes, but it does not integrate a splice clip into its own list.
That's what I am talking about.

vion11
15th June 2003, 20:59
When stacksize is 1MB why 500 function calls overflow it?

About 1500-2000 nested calls should be possible. Most games and AI problems can be rendered within this deepness. Any chance to adjust stacksize like SetMemoryMax()?

Bidoche
15th June 2003, 22:23
Actually 500 filters would make at least 1000 calls since cache filters are intercaled between them .

vion11
16th June 2003, 15:56
OK, every call pushes 2000 bytes onto the stack, right? That makes sense: values, environment data... .

Isn't it a good idea to save data in memory and to push pointers to these blocks onto stack? Stack efficiency could be 100+ times better.

Bidoche
16th June 2003, 17:55
2000 bytes per call ? isn't that a bit much...
How do you find that number.

vion11
17th June 2003, 12:22
Stacksize = 1MB = 1,000,000 bytes
max Calls = 500
bytes per call = 1,000,000 / 500 = 2000 bytes / call

Whats wrong with this calculation? Or what else is wasting stack?

Bidoche
17th June 2003, 18:36
It's more like the amount that should be wasted by calls for the stack to overflow with only that.

But it can't be that much. It's just stacking ret address and function arguments. It should be a matter of a few tens of bytes at most.

vion11
18th June 2003, 17:01
To get more specific I've tested this stuff:

Function SumAll (int nSum)
{return ( nSum == 0 ? 0 : nSum + SumAll(nSum - 1))}

MessageClip (String (SumAll (533))) # Works
MessageClip (String (SumAll (534))) # Works not

On the other hand:

Function BlurMore (clip c , int nTimes )
{return ( nTimes == 0 ? c : BlurMore (Blur(c, 1), nTimes - 1))}

BlurMore (Colorbars (400,300), 551) # Works
BlurMore (Colorbars (400,300), 552) # Works not

BlurMore uses more parameters and tolerates a few more calls, SumAll does not use filters. Both have different recursive style, but tolerate the same amount of calls within a range. Now i think not the stack limiting , something else is playing around. Can anybody determine if more stack enable more calls?

Bidoche
19th June 2003, 12:11
It occured to me that it probably fails at execute time (when building the graph) and not at render time.

If the recursive script functions you use, create many temporary objects (on the stack) before calling next level, it may explain the overflow.

vion11
20th June 2003, 19:46
Originally posted by Bidoche
It occured to me that it probably fails at execute time (when building the graph) and not at render time.
that seems to be right, can't see any frames
If the recursive script functions you use, create many temporary objects (on the stack) before calling next level, it may explain the overflow.
There are a lot of examples in this thread, what are "temporary objects" and for what reason stack is wasted with temporary stuff?

As a high level application designer, I'm interested in a stable development plattform able to meet the challenge of building interactive new media applications for all people loving DVD content.

The DVD-specs provide interactive movies with up to a million pieces of video and audio. To achieve a storytelling authoring tool proofing a tree structure is essential. For now avisynth equals a status less then 1 percent of the possibilitys.

What is your vision of avisynth? Is it really enough to have a tool making perfect copies of media in fastest possible time?

But I don't what to affront somebody, let's stop this thread and let the max-500-calls-ghost have his castle in code.

Bidoche
20th June 2003, 20:20
Objects created through new (or in memory allocated by malloc) are created on the heap, and others are created on the stack.

Each time you write : int i = .... in the code you consume the size of an int on the stack (which is regained when i goes out of scope)

Of course it's the same with a custom class.
Look at this piece of code :void example(int count)
{
MyVeryBigObject i = 1;
if (count > 0)
example(--count);
}

if sizeof(MyVeryBigObject) = 2000 the stack will overflow with count around 500. Because each call will create its own i on the stack.

It's probably the same sort of things here, script functions create too much temporaries per call. And to waste that much, it may even be the worst case scenario, ie that everything is created on the stack at each call : needed variables (necessary) and the manipulating code (which should be shared)...

I will look into it. (Does anybody know where the code for that stuff is located ?)

vion11
20th June 2003, 23:56
It may help to know version 2.5.2 allows one more call(533) of function SumAll than version 2.06 (532).

Bidoche
25th June 2003, 11:37
The related code is ok, nothing to gain there.
So there is no easy way to improve the recursion limit (besides increasing stack size).


The solution would be to implement terminal recursivity, but since it has to be recognized by the parser, it would be quite hard.

Unless we use a keyword to tell him we want it. Maybe....