View Full Version : How are clips passed to functions?
martin53
13th December 2012, 21:37
Please excuse if I repeat a silly question here that has been asked for a dozen times and help me with a link.
The documentation says about user functions (http://avisynth.org/mediawiki/User_defined_script_functions), "Functions always produce a new value and never modify an existing one. What that means is that all arguments to a function are passed "by value" and not "by reference"; in order to alter a variable's value in AviSynth script language you must assign to it a new value."
Might that be true for clips also???
I had to change one of my user functions, so it gets not only a clip, but also the much larger MSuper() super clip. Also, that function calls itself recursively five times. But not much happens inside. Only a very small area of the big super clip is processed in every recursion. In fact, the whole thing should be faster than the predecessor, which was a loop that processed the whole clip for about five or more times.
All that is running inside the RTE, i.e. inside a ScriptClip() function. (The function definitions are outside the ScriptClip function, just called from there, because the performance considerations page (http://avisynth.org/mediawiki/The_script_execution_model/Performance_considerations) advises to avoid that).
But I make the observation that it is extremely slow.
Could maybe one of the AviSynth gurus give me some insight into how the definition of a user defined function affects performance with respect to writing inline code? :thanks:
(btw: if you almost wrote me a supportful response of the kind 'I have no idea about that stuff, so I contribute another problem', thank you for backing off.)
Gavino
13th December 2012, 22:15
Could maybe one of the AviSynth gurus give me some insight into how the definition of a user defined function affects performance with respect to writing inline code?
From the filter graph wiki page (http://avisynth.org/mediawiki/The_script_execution_model/The_filter_graph):
A function call generates a filter graph corresponding to the evaluation of the function body with its arguments set to the values passed in the call. (Consequently, there is no run-time overhead in calling a function - the same filter graph will be generated as if the function body had been written 'in-line'.)
Not sure if this answers your question.
It may be easier to help if you post your script (or an outline of it).
johnmeyer
13th December 2012, 22:50
When trying to speed up a script, I found the information in this thread:
Cannot get Autolevels() to multithread (http://forum.doom9.org/showthread.php?p=1406681#post1406681)
very useful. The title may seem irrelevant to your problem, but the issue that was described may shed light on what you are seeing. Basically, the idea is that, with some functions -- because of internal caching -- it can make a difference where these functions are called within your script. The discussion focused on multi-threading, but I think that some things might still come into play even if you are not multi-threading.
My thought is that when you re-wrote portions of code and put that code into functions, you might have changed the order of when code gets loaded.
Just a thought ...
StainlessS
13th December 2012, 22:50
all arguments to a function are passed "by value" and not "by reference"
The clip that gets passed is just a reference to the actual clip,
so although it is passed by value, the value is itself a reference
(just a sort of pointer to the real thing).
EDIT: If you edit the passed clip in some way, a duplicate is made and you edit the duplicate.
When you edit a passed clip you are editing a duplicate, irrespective as to whether the original
clip is ever used on return from the function.
Above may seem a little strange, but you cannot edit a clip that belongs to someone (a function) else.
(edit meaning change, if you just want to read a clip, it is not duplicated).
martin53
14th December 2012, 19:14
Thank you all for the hints and aspects you added.
I am a bit confused and can not fully depict in my mind what happens in the script.
The said recursive filter function deals with two clips and some ordinary variables, and returns an ordinary float (its purpose is to provide a motion estimation value).
According to what StainlessS once wrote (http://forum.doom9.org/showthread.php?p=1594454#post1594454), during the ScriptClip compile stage, the filter function will build to the point it is called again because it needs the ordinary return value. This will repeat about 5 or 6 times. Then the last instance in the recursive chain will be able to evaluate some clip properties - and need the partial graph for that task.
So the 4 or 5 instances in the recursion chain are then nodes in the partial filter graph, as Gavino quoted from the filter graph wiki page - and they are doing nothing with that clip at this time, the alternative inline code would be empty. I guess that the about 5 frames of the super clip are then being processed through the partial graph i.e. memcpy'ed and cached, which could explain the delay?
That would mean, however, that there is in fact a severe influence of a user function: it creates at least a 'null transform' node in the graph. Unless such null transform nodes are being optimized out even from partial graphs? I never came across any information on that. I already wondered if
b=a #a is a clip
c=b
or even
a=a
a=a
a=a
compile to a more complicated graph than
c=a
Edit: StainlessS says that only a reference to the clip is passed to the user function, so it should be the same that this reference is passed 5 times; and the 5th function should still read from the original clip - no copies, no caching. My function does not modify the super clip, that's for sure. Then, there is no influence, and the AviSynth design is clever. But I have no clue why it is so slow then.
Your comments?
Gavino
14th December 2012, 19:22
I already wondered if
b=a #a is a clip
c=b
or even
a=a
a=a
a=a
compile to a more complicated graph than
c=a
Assignments like that don't generate any graph at all.
They are purely compile-time actions (and take virtually no time to perform).
martin53
15th December 2012, 10:22
I rewrote the script with two while() loops instead of the recursion. The speed is about the same. So I close this case, because the processing time seems to come from the script operations. Thank you again for the substantiated contributions.
Gavino
15th December 2012, 11:36
I rewrote the script with two while() loops instead of the recursion. The speed is about the same.
That's what I would expect (though I haven't done any timing tests).
In fact, if anything, a (GScript) loop should be slightly faster than using recursion since on each iteration it doesn't have to evaluate the recursive function call (just the loop body, which would be equivalent to the function body).
So I close this case, because the processing time seems to come from the script operations.
Note that filters which have high 'startup' costs (eg setting up lookup tables) will run slowly inside ScriptClip, since they have to be instantiated afresh for every frame. As an extreme example, mt_lutxyz would be impractical to use. Another example is Subtitle(), which will show a noticeable slowdown as the text drawing has to be redone for every frame instead of just once.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.