View Full Version : Non implicit Last is quicker (in Scripclip) !
StainlessS
13th September 2013, 16:14
I came across something a little startling,
Colorbars(pixel_type="YV12").KillAudio().ScriptClip("AverageLuma() return Last")
About 595 FPS according to Groucho2004 AvsMeter v1.60.
and
Colorbars(pixel_type="YV12").KillAudio().ScriptClip("AverageLuma(Last) return Last")
About 1682 FPS.
Other non defaulted args give a speed hit.
No question, just an observation that might be of use.
EDIT: Avisynth v2.6a4 Groucho2004 ICL version.
Guest
13th September 2013, 17:39
I hope IanB weighs in on this. It's reminiscent of an early bug in Avisynth in which omission of empty parentheses caused a cache to not be created, and the function ran slower without a cache.
It should be fixed if possible because that is a big hit to performance resulting from what should be a harmless syntax variation. What else could this bug be affecting?
johnmeyer
13th September 2013, 17:40
I did most of my programming when FORTRAN and ALGOL were popular. Compilers were just starting to let you treat variables implicitly, but we were taught that bad things would happen if you left decisions up to the compiler. There were global/local issues, variable typing issues, and memory allocation issues. So while I agree this is startling and unexpected, it is not entirely unprecedented. Thanks for the heads up.
FWIW, I never use the "last" variable, either explicitly or implicitly, because I have been burned several times when the frame that I thought was "last" was different than what AVISynth used as the last frame. I guess it is my bad for not fully understanding how AVISynth operates, but I eliminated the problem by using my own variables.
StainlessS
13th September 2013, 17:44
On a timetest for MYStats (Masked Y Stats, similar to one given in RT_Stats thread comparing RT_Stats and built-in runtime funcs)
giving args eg MYInRange(lo=128,hi=255) produced about 1/2 frame rate of same func without args (given args identical to defaults).
EDIT: Hang on, think I better check that again, not sure if I used Last or not.
Groucho2004
13th September 2013, 17:49
FWIW, I never use the "last" variable, either explicitly or implicitly, because I have been burned several times when the frame that I thought was "last" was different than what AVISynth used as the last frame.
I'm slightly confused by that since "last" refers to a clip, not a frame.
StainlessS
13th September 2013, 18:00
Here using RT_Stats version func (MYStats takes an optional 2nd clip so thought I'd use simpler func)
RT_YInRange(lo=128,hi=255) 334 FPS
RT_YInRange() 514 FPS
RT_YInRange(Last,lo=128,hi=255) 1154 FPS
RT_YInRange(Last) 1158 FPS
Curiouser and Curiouser.
EDIT: I got about a dozen or more windows/programs open but that should make no difference to the ratios.
EDIT: Perhaps I should mention that it's on Avisynth v2.6a4 Groucho2004 ICL version.
Groucho2004
13th September 2013, 18:10
Maybe this (from conditional.cpp) explains it:
/**************************
* ScriptClip.
*
* Returns the value of a script evaluated at each frame.
*
* Implicit last, and current frame is set on each frame.
**************************/
ScriptClip::ScriptClip(PClip _child, AVSValue _script, bool _show, bool _only_eval, bool _eval_after_frame, IScriptEnvironment* env) :
GenericVideoFilter(_child), script(_script), show(_show), only_eval(_only_eval), eval_after(_eval_after_frame) {
}
PVideoFrame __stdcall ScriptClip::GetFrame(int n, IScriptEnvironment* env) {
AVSValue prev_last = GetVar(env, "last"); // Store previous last
AVSValue prev_current_frame = GetVar(env, "current_frame"); // Store previous current_frame
env->SetVar("last",(AVSValue)child); // Set explicit last
Anyway, I guess Ian knows better what's happening.
Groucho2004
13th September 2013, 18:12
Perhaps I should mention that it's on Avisynth v2.6a4 Groucho2004 ICL version.
I tried several DLLs down to 2.58, same behaviour throughout.
StainlessS
13th September 2013, 18:18
If this is fixed, that would be a real good reason to switch to v2.6a5, goodbye v2.58.
EDIT: Out of interest Grouchy, did you try any of the MT versions ?
Groucho2004
13th September 2013, 18:42
Out of interest Grouchy, did you try any of the MT versions ?
Yes, the latest from Set.
johnmeyer
13th September 2013, 18:54
I'm slightly confused by that since "last" refers to a clip, not a frame.Badly worded by me.
Gavino
13th September 2013, 20:10
When implicit 'last' is used, the function has to be passed twice to env->Invoke(), the first time with the explicitly supplied args, and then, when that fails, again with 'last' as an extra first argument. (see ExpFunctionCall::Call in expression.cpp.)
So the overhead of function lookup and argument matching is incurred twice.
Since this is a compile-time activity, it would normally go unnoticed, but inside ScriptClip() it is happening on every frame.
I think the tests are a bit misleading, since they don't use any filters (only run-time functions) inside the ScriptClip calls. Normally, you would incur significant filtering time on each frame so the relative overhead of the extra function lookup would be much less.
Maybe this (from conditional.cpp) explains it:
No, because that code is executed for all frames, whether or not implicit last is used.
StainlessS
13th September 2013, 21:01
Thank you Gavino, just exactly where I got to when I saw your answer, not quite so startling then:
AVSValue ExpFunctionCall::Call(IScriptEnvironment* env)
{
AVSValue result;
AVSValue *args = new AVSValue[arg_expr_count+1];
try {
for (int a=0; a<arg_expr_count; ++a)
args[a+1] = arg_exprs[a]->Evaluate(env);
}
catch (...)
{
delete[] args;
throw;
}
// first try without implicit "last"
try {
result = env->Invoke(name, AVSValue(args+1, arg_expr_count), arg_expr_names+1);
delete[] args;
return result;
}
catch (IScriptEnvironment::NotFound) {
// if that fails, try with implicit "last" (except when OOP notation was used)
if (!oop_notation) {
try {
args[0] = env->GetVar("last");
result = env->Invoke(name, AVSValue(args, arg_expr_count+1), arg_expr_names);
delete[] args;
return result;
}
catch (IScriptEnvironment::NotFound) { /* see below */ }
catch (...)
{
delete[] args;
throw;
}
}
}
catch (...)
{
delete[] args;
throw;
}
delete[] args;
env->ThrowError(env->FunctionExists(name) ? "Script error: Invalid arguments to function \"%s\""
: "Script error: there is no function named \"%s\"", name);
return 0;
}
EDIT: Still, if it takes takes about twice as long to do a failed invoke followed by a successful one,
than it does to do a sole successful scan (in RT_YInRange, counting all luma pixels in a frame
[into a 256 element array]), I think I'll try to use explicit last from now on.
Perhaps it's the catch of try/catch that hogs CPU.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.