Log in

View Full Version : Internaly multi-threaded resampling functions


Pages : [1] 2 3 4 5 6 7 8 9

jpsdr
12th August 2016, 13:53
I've made a plugin of the resampling functions, with internal multi-threading.
I can allready ear the "why" ?
The answer is "because"...:D

More seriously, i'll explain my point of view.
For multi-threading in image processing, if you have n cores, you have basicaly two ways :
Case 1 : You process n pictures in parallel.
Case 2 : You process n 1/nth part of the picture in parallel.

The internal core can only offer the case 1, because it has no idea how to handle junction/overlap of the splitted image, neither how to split it (even if the most common way is the vertical split), and even more if splitting is possible.
The case 2 is only possible internaly, because only the filter know how to split, join, handle overlap, etc...

Personnaly, i don't like the case 1, i think case 2 is a way better.
Differences may not be very obvious with few cores, but it will become with a lot of cores.
With case 2, the memory used is always the same, whatever the number of cores you have, when with case 1, it always increases. The more cores you have, the less memory each core is working on => the more chance you have to fit it in lower cache level => the more performance you can get. Forget it with case 1.

For example, if you have an high-end 10 cores with HT CPU, giving you 20 cores.

A UHD 4k YV12 picture has a size of around 12,5MB. The whole picture fit on the L3 cache, so the 20 cores will access their data within it. I'll let you guess the result with case 1...

A FHD 1080p YV12 picture has a size of around 3MB, fit in L3 but 1/20 gives 155KB, this fits on L2 cache, so each core will work with data from his own L2 cache. Case 1 doesn't even fit in L3 cache.

You may not have this point of view, but for those who share it, you can use my multi-threaded version.

This version works on all avs+ version, and on all 2.6.x versions.

Current version : 2.10.0

Sources are here (https://github.com/jpsdr/ResampleMT).
Binaries are here (https://github.com/jpsdr/ResampleMT/releases/download/2.10.0/ResampleMT_v2_10_0.7z).

Version history
2.10.0 : Implement core code update with AVX512.
2.9.8 : Minor changes (more code refactory).
2.9.0 : Revert and remove all ASM code, benchmark not good. Fix SSE crash & Bicubic.
2.8.0 : Add ASM code AVX/AVX2/AVX512.
2.7.1 : Update matrix class.
2.7.0 : Update to new SSE code.
2.6.0 : Update to new AVX2 code.
2.5.1 : Fix for optimized functions.
2.5.0 : Add chroma placement and new filters coeff calcul.
2.4.0 : Add force parameter, fix a crop issue and update Gaussresize.
2.3.9 : Update to new AVS+ headers.
2.3.8 : Add DTL pull-request (update on UserDefined2ResizeMT).
2.3.7 : Update to new AVS+ headers.
2.3.6 : Update on threadpool, no user limit (except memory).
2.3.5 : Fix on threadpool, using prefetch parameter created hang. Add negative prefetch for triming, read Multithreading.txt or Multithreading chapter here. Fix for RGB packed format.
2.3.4 : Fix on threadpool.
2.3.3 : Working fix for too small size vs size filter, update avs headers.
2.3.2 : Add UserDefined2ResampleMT function, fix for too small size vs size filter.
2.3.1 : Add SincLin2Resize function.
2.3.0 : Add SinPowResize function.
2.2.3 : Update of the threadpool, update to new avisynth headers.
2.2.2 : Minor code change after threadpool update, fix in the number of threads,
fix to perfectecly match avs+ output (V/H resize order was sometimes different).
2.2.0 : Update of the threadpool, add ThreadLevel parameter.
2.1.2 : Update of Matrix Class.
2.1.1 : Optimized CPU placement if SetAffinity=true for prefetch>1, SetAffinity back to default false.
2.1.0 : Merge new core resampler code, filter is MT_NICE.
2.0.3 : Fix a bug in the MTData, add check for inverting matrix in desample.
2.0.2 : Minor update on threadpool.
2.0.1 : Desample now handle properly croped and/or high value shifted original.
2.0.0 : Added the Desample functions.
1.5.8 : Fix possible deadlock in threadpool, and fix issue of filter "doing nothing".
1.5.7 : Fix in threadpool.
1.5.6 : Minor fix.
1.5.5 : Minor changes on threadpool.
1.5.4 : Minor update on threadpool.
1.5.3 : Update avs header, fix range mode issue.
1.5.2 : Some fixes, add range mode 4, set range mode default to 1, apply range only on last step.
1.5.1 : Change code to allow the merge of the plugins.
1.5.0 : Add range parameter.
1.4.0 : Add sleep and prefetch parameters.
1.3.0 : Update to the new resample core functions. Update to the new avs header and support of all supported video formats. Build with /MD instead of /MT.
1.2.6 : Use Mutex instead of CriticalSection on some places and some changes in the threadpool interface.
1.2.5 : Fix deadlock case in Threadpool interface. Remove CACHE_DONT_CACHE_ME and small changes in the threadpool interface.
1.2.4 : Add several parameters to allow more specific tuning of the threadpool if necessary.
1.2.3 : Minor change.
1.2.2 : Update of the threadpool and minor change.
1.2.1 : Update the threadpool interface, fix the deadloock on init and other small things.
1.2.0 : Update the threadpool interface.
1.1.0 : Use an external thread pool class but internaly to prevent the thread creation explosion.
1.0.2 : Test of finaly a bad idea...
1.0.1 : Fix Intel compiler warning.
1.0.0 : First release.

==================================================================

Desample

Desample functions added on v2.0.0

DeBilinearResizeMT
DeBicubicResizeMT
DeLanczosResizeMT
DeLanczos4ResizeMT
DeBlackmanResizeMT
DeSpline16ResizeMT
DeSpline36ResizeMT
DeSpline64ResizeMT
DeGaussResizeMT
DeSincResizeMT
DeSinPowResizeMT
DeSincLin2ResizeMT
DeUserDefined2ResampleMT


More information on Desample functions here (http://forum.doom9.org/showthread.php?p=1817097#post1817097).

==================================================================

The functions inside this plugin are :
PointResizeMT
BilinearResizeMT
BicubicResizeMT
LanczosResizeMT
Lanczos4ResizeMT
BlackmanResizeMT
Spline16ResizeMT
Spline36ResizeMT
Spline64ResizeMT
GaussResizeMT
SincResizeMT
SinPowResizeMT
SincLin2ResizeMT
UserDefined2ResampleMT


Parameters are exactly the same than the orignal resampling functions, and in the same order, so they are totaly backward compatible.
For the new kernel functions added, check the ReadMe file.

Several new parameters are added at the end of all the parameters :

threads -

Controls how many threads will be used for processing. If set to 0, threads will
be set equal to the number of detected logical or physical cores,according logicalCores parameter.

Default: 0 (int)

logicalCores -

If threads is set to 0, it will specify if the number of threads will be the number
of logical CPU (true) or the number of physical cores (false). If your processor doesn't
have hyper-threading or threads<>0, this parameter has no effect.

Default: true (bool)

MaxPhysCore -

If true, the threads repartition will use the maximum of physical cores possible. If your
processor doesn't have hyper-threading or the SetAffinity parameter is set to false,
this parameter has no effect.

Default: true (bool)

SetAffinity -

If this parameter is set to true, the pool of threads will set each thread to a specific core,
according MaxPhysCore parameter. If set to false, it's leaved to the OS.

Default: true (bool)

sleep -
If this parameter is set to true, once the filter has finished one frame, the threads of the
threadpool will be suspended (instead of still running but waiting an event), and resume when
the next frame will be processed. If set to false, the threads of the threadpool are always
running and waiting for a start event even between frames.

Default: false (bool)

prefetch -
This parameter will allow to create more than one threadpool, to avoid mutual resources acces
lock/wait if "prefetch" is used in the avs script.
0 : Will set automaticaly to the prefetch value use in the script. Well... that's what i wanted
to do, but for now it's not possible for me to get this information when i need it, so, for
now, 0 will result in 1. For now, if you're using "prefetch" in your script, put the same
value on this parameter.

range -
This parameter specify the range the output video data has to comply with.
Limited range is 16-235 for Y, 16-240 for U/V. Full range is 0-255 for all planes.
Alpha channel is not affected by this paramter, it's always full range.
Values are adjusted according bit depth of course. This parameter has no effect
for float datas.
0 : Automatic mode. If video is YUV mode is limited range, if video is RGB mode is
full range, if video is greyscale (Y/Y8) mode is Y limited range.
1 : Force full range whatever the video is.
2 : Force limited Y range for greyscale video (Y/Y8), limited range for YUV video,
no effect for RGB video.
3 : Force limited U/V range for greyscale video (Y/Y8), limited range for YUV video,
no effect for RGB video.
4 : Force special camera range (16-255) for greyscale video (Y/Y8) and YUV video,
no effect for RGB video.

Default: 1

ThreadLevel -
This parameter will set the priority level of the threads created for the processing (internal
multithreading). No effect if threads=1.
1 : Idle level.
2 : Lowest level.
3 : Below level.
4 : Normal level.
5 : Above level.
6 : Highest level.
7 : Time critical level (WARNING !!! use this level at your own risk)

Default : 6

The logicalCores, MaxPhysCore, SetAffinity and sleep are parameters to specify how the pool of thread will be created and handled, allowing if necessary each people to tune according his configuration.

So, syntax is :
ResampleFunction([original parameters],int threads, bool logicalCores, bool MaxPhysCore, bool SetAffinity, bool sleep, int prefetch,int range)

==================================================================

JincResizeMT

Current version : 1.1.0

Sources are here (https://github.com/jpsdr/JincResizeMT).
Binaries are here (https://github.com/jpsdr/JincResizeMT/releases/download/1.1.0/JincResizeMT_v1_1_0.7z).

JincResizeMT(clip, int target_width, int target_height, float src_left, float src_top, float src_width, float src_height, int quant_x, int quant_y, int tap, float blur, string cplace, int threads, int opt, int initial_capacity, float initial_factor, int range, bool logicalCores, bool MaxPhysCore, bool SetAffinity, bool sleep, int prefetch, int ThreadLevel)
)

Jinc36ResizeMT/Jinc64ResizeMT/Jinc144ResizeMT/Jinc256ResizeMT(clip, int target_width, int target_height, float src_left, float src_top, float src_width, float src_height, int quant_x, int quant_y, string cplace, int threads, int range, bool logicalCores, bool MaxPhysCore, bool SetAffinity, bool sleep, int prefetch, int ThreadLevel)
)

See the ReadMe file for more informations and descriptions of the functions and their parameters.

==================================================================

Multi-threading information

CPU example case : 4 cores with hyper-threading.

If you leave all the multi-threading parameters to their default value, it's set to be "optimal" when you're not using prefetch or if you are under standard avisynth, all the logical CPU will be used.
If you put SetAffinity to true it will allocate the threads on the CPU contiguously. Physical CPU 1 will have threads (0,1), ... physical CPU 4 will have threads (6,7), allowing optimal cache use. Make test to see what's best for you.

Now, if you are using prefetch on your script, things are different !
If you're using it with the max number of CPUs (8 in our exemple case), you still can make tests, but i would strongly advise to disable the internal multi-threading by using threads=1. In this case, there is no threadpool created, and all the other multi-threading related filter parameters have no effect, even prefetch.
If you're using prefetch on your script, with less than your CPU number, you may want to try to mix the external and internal mutli-threading, setting the internal multi-threading to a lower number of threads, and setting the prefetch parameter of the filter. This parameter will set the number of internal threadpool created, the best is to match the prefetch script value. If you don't set it (leave it to 1) or set a lower value than prefetch on your script, you'll have several instances (or GetFrame) created, but they'll not be running efficiently, because each instance (or GetFrame) will spend time waiting for a threadpool to be avaible, if not enough were created.
Unfortunately, as things are now, i have no way of knowing the prefetch value used in the avisynth script at the time i need the information, this is why you have to use the prefetch parameter in the filter.
In our CPU exemple case, you can have things like :

filter(...,threads=1)
prefetch(8)

or

filter(...,threads=2,prefetch=4)
prefetch(4)

or

filter(...,threads=4,prefetch=2)
prefetch(2)

or even

filter(...,threads=3,prefetch=4)
prefetch(4)

if you want to boost and go a little over your total CPU number.

Also, if your prefetch is not higher than your number of physical cores, you can try to put SetAffinity to true, but in that case, you have to set MaxPhysCore to false. The threads of each pool will be set on CPUs by steps.
For exemple, in our case :

filter(...,threads=2,prefetch=4,SetAffinity=true,MaxPhysCore=false)
prefetch(4)

Will create 4 pool of 2 threads, with the following :
pool[0] : threads(0 -> 1) on CPU 1.
pool[1] : threads(0 -> 1) on CPU 2.
pool[2] : threads(0 -> 1) on CPU 3.
pool[3] : threads(0 -> 1) on CPU 4.

filter(...,threads=4,prefetch=2,SetAffinity=true,MaxPhysCore=false)
prefetch(2)
Will create 2 pool of 4 threads, with the following :
pool[0] : threads(0 -> 1) on CPU 1.
pool[0] : threads(2 -> 3) on CPU 2.
pool[1] : threads(0 -> 1) on CPU 3.
pool[1] : threads(2 -> 3) on CPU 4.

Negative prefetch
The possibility to put negative prefecth to tune the prefetch parameter to optimal value has been added. The filter will throw an error if the number is not high enough to avoid waiting when requesting internal threadpool. For this to work properly, you have to put negative prefetch on ALL the filters of your script, and also ALL instances of the same filter.

Exemple :
filter(...,threads=2,prefetch=-2)
prefetch(2)
You'll see an error.

But with :
filter(...,threads=2,prefetch=-3)
prefetch(2)

You'll see no error, so the optimal is :
filter(...,threads=2,prefetch=3)
prefetch(2)

Once you've tune, put back a positive value.

shekh
12th August 2016, 14:38
This is interesting. Do you have any actual timings of slice vs frame performance?
I dont know much low level, but my impression is you are lucky if you are bound by L1 cache (you are already in the fast camp), and L1 caches are per-core anyway. If there is enough computation it can easily dominate over all memory bottlenecks.

jpsdr
12th August 2016, 15:07
L1... 32k max... you can fit only a few lines of pictures pictures, but small pictures more indeed, even better than L2 if lucky(which are also per core).

jpsdr
12th August 2016, 19:49
Need help from C++ expert, why Intel compiler is not happy ?
Of course, no issue with Visual Studio.

Code is :

class ResamplingFunction
/**
* Pure virtual base class for resampling functions
*/
{
public:
virtual double f(double x) = 0;
virtual double support() = 0;

virtual ResamplingProgram* GetResamplingProgram(int source_size, double crop_start, double crop_size, int target_size, IScriptEnvironment* env);
};


class PointFilter : public ResamplingFunction
/**
* Nearest neighbour (point sampler), used in PointResize
**/
{
public:
double f(double x);
double support() { return 0.0001; } // 0.0 crashes it.
};

static PClip CreateResize( PClip clip, int target_width, int target_height, int _threads, const AVSValue* args,
ResamplingFunction* f, IScriptEnvironment* env );


return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(),args[7].AsInt(0), &args[3],
&PointFilter(), env );


Error message is :

1>resample.cpp(2458): error : expression must be an lvalue or a function designator
1> &PointFilter(), env );
1> ^


I also have :

1>resample.cpp(2472): warning #1563: taking the address of a temporary
1> &MitchellNetravaliFilter(args[3].AsDblDef(1./3.), args[4].AsDblDef(1./3.)), env );
1> ^


Expert help needed... :thanks:

feisty2
12th August 2016, 20:03
I'm no c++ expert but what's "&PointFilter()"?
I assume that PointFilter is a class name here, so PointFilter() is the constructor?
You can't take the memory address of constructors...
And you didn't overload (), so not a functor either

jpsdr
12th August 2016, 20:07
Ok, for now just VS builds, no Intel, so you can test, torture, whatever you want.

@feisty2 : Well, VS don't complain, so maybe it's something "acceptable". It's not the 1rst time i encounter some kind of issue where Intel compiler is less tolerant than (or too strict ?) than VS.
But, this is out of my skills, need realy a c++ expert.

feisty2
12th August 2016, 20:15
Ahhh, got it
&PointFilter::PointFilter is taking the address of the constructor which is invalid

&PointFilter() is taking the address of a TEMPORARY object, the object has the type of PointFilter &&, which is an xvalue, and you can't take the address of that either

feisty2
12th August 2016, 20:25
ResamplingFunction *f -> ResamplingFunction &&f
&PointFilter() -> PointFilter()

will probably work...

Edit: you might be using an obsolete msvc which does not feature rvalue reference, a modern c++ feature, so it didn't bitch about nothing

jpsdr
12th August 2016, 20:43
Euh... maybe a little for VS2010, but VS2015 update 3 compile without even a warning... Too much permissive maybe.

feisty2
12th August 2016, 20:54
Well you should probably not write super confusing stuff like "&PointFilter()" in the future, I mean, who the hell even remembers if & has the higher priority or () does...
Modern c++ is nice, so kiss c++98 goodbye

shekh
12th August 2016, 20:57
&PointFilter() is taking address of a temporary object, which has a const qualifier

I would put this on separate line

PointFilter filter;
return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(),args[7].AsInt(0), &args[3], &filter, env );

but I hope CreateResize does not store that pointer somewhere

jpsdr
12th August 2016, 21:11
I've figure out. Some throw error, some throw warning. Those who throw warning are those where a constructor is defined, those with error are those where there is no constructor defined. Default constructor is apparently not enough for the Intel compiler, just adding an empty constructor transform the error in a warning. I'll try also the shekh suggestion, it seems safer to me...

Edit : With skeh suggestion, there not even the warning anymore. I'll update to this, even if maybe it's not realy necessary, i don't like warning if i can avoir them... ;)

feisty2
12th August 2016, 21:13
&PointFilter() is taking address of a temporary object, which has a const qualifier

I would put this on separate line

PointFilter filter;
return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(),args[7].AsInt(0), &args[3], &filter, env );

but I hope CreateResize does not store that pointer somewhere

Nah, you're passing out an address on stack, &filter is a dangling pointer!
The object is meant to be on the stack of CreateResize, not the stack of the function that calls CreateResize!

jpsdr
12th August 2016, 22:08
Anyway, it's working... Update the 1rst post with a 1.0.1 version, you can torture, test, etc...

feisty2
12th August 2016, 22:38
Fine, I was wrong and delusional and half asleep, "return" gave me a false illusion as if it jumped out of the function that called CreateResize and continued at CreateResize and therefore filter was freed, but it indeed jumped to CreateResize, just never out of the outer function, it will go back to that outer function when CreateResize is done so filter was never freed
Hopefully next time I won't reply when I'm taking a nap..

ultim
13th August 2016, 15:22
Bonus points for using a thread pool and not starting new threads each frame. Now when IScriptEnv2 finalizes, this plugin only needs to use the internal pool of Avs+ to make it better :D

I am also not convinced by the caching arguments, but I can see other ways this kind of threading is helpful. Most obvious example, for large frames (4K or 8K) where memory needs for frame-based threading become prohibitive for normal users, the lower memory needs of slice-based threading may come to the rescue, which will certainly be faster than swapping memory to disk.

jpsdr
13th August 2016, 17:55
this plugin only needs to use the internal pool of Avs+ to make it better :D
I'm not closed to it, if it's possible (i'm not against a link to something using it providing an exemple), and if it doesn't break the compatibility with running "the same way" under any avs+ and any avs 2.6.x. (which may probably need to keep the actual code, and create another code specific to the use of this thread pool, increasing complexity, but, again, why not... It's something i have to see):D
After, for the thread pool, i've just used and adapted what Tritical has done under nnedi3.
Personnaly, i'll never allocated/create/etc... on each frame !
You do this once for all on constructor. Well, it's also of course my personnal point of view.
The other thing i'll try to see if it improve speed, is to test the "trick" i've used on nnedi3 on RGB24. It helped on it, i have to check to see if it can also help on this case.

ultim
13th August 2016, 21:26
well it's in an unstable interface which is why there are no real examples yet for its usage. it's also why you should wait a little more. once it's deemed ready, I'll announce it and provide descriptions+examples of the most useful features.

TheFluff
13th August 2016, 23:16
Stephen R. Savage posted this earlier but since he loves deleting his own posts I'll repeat what I remember of it:

There's no evidence that slice-based threading is any faster than frame-based threading for a convolution filter like a resizer. Frame-based threading of the Vapoursynth internal resizers scaled very close to linearly up to 24 cores in Stephen's tests (24 cores, 23.8x speedup compared to one core). He had some argument that there is no cache advantage to the slice-based threading because there's no shared data between lines, or something? I don't remember. But anyway internally multithreading like this is likely pointless, at least for resizers. Then again I'm pretty sure avs-mt's frame-based multithreading design is bad but I don't really have the evidence to back that up.

You may not have this point of view, but for those who share it, you can use my multi-threaded version.

I realize that "optimizing" things based on guesswork, hearsay and fundamental misunderstandings of the underlying technology is a very doom9 thing to do (remember that guy who wrote 3000 lines of asm to try to optimize memcpy even though optimizing memcpy does absolutely nothing in the real world?), but holy shit, seriously. Dude. If you optimize something, you'd better benchmark it to prove that is faster than the thing you wanted to improve on. One algorithm being faster than another isn't an opinion or a point of view. Don't try to rice shit without benchmarks.

Chikuzen
13th August 2016, 23:25
benchmark?
I did. http://pastebin.com/ZCNnN5RW.

Groucho2004
13th August 2016, 23:55
Another one (i5 2500K @ 4GHz, XP32, AVS+ r2085):

Internal resizers:
[Runtime info]
Frames processed: 1000 (0 - 999)
FPS (min | max | average): 1.743 | 255682 | 17.60
Memory usage (phys | virt): 293 | 295 MiB
Thread count: 13
CPU usage (average): 99%

Time (elapsed): 00:00:56.812


[Script]
colorbars(width = 1920 * 2, height = 1080 * 2, pixel_type = "yv12").killaudio().assumefps(25, 1).trim(0, 999)
BilinearResize(width() - 64, height() - 64)
BicubicResize(width() - 64, height() - 64)
LanczosResize(width() - 64, height() - 64)
Lanczos4Resize(width() - 64, height() - 64)
BlackmanResize(width() - 64, height() - 64)
Spline16Resize(width() - 64, height() - 64)
Spline36Resize(width() - 64, height() - 64)
Spline64Resize(width() - 64, height() - 64)
GaussResize(width() - 64, height() - 64)
SincResize(width() - 64, height() - 64)
Prefetch(4)


Plugin resizers:
[Runtime info]
Frames processed: 1000 (0 - 999)
FPS (min | max | average): 6.480 | 16.84 | 16.66
Memory usage (phys | virt): 76 | 79 MiB
Thread count: 89
CPU usage (average): 99%

Time (elapsed): 00:01:00.031


[Script]
colorbars(width = 1920 * 2, height = 1080 * 2, pixel_type = "yv12").killaudio().assumefps(25, 1).trim(0, 999)
BilinearResizeMT(width() - 64, height() - 64, threads = 4)
BicubicResizeMT(width() - 64, height() - 64, threads = 4)
LanczosResizeMT(width() - 64, height() - 64, threads = 4)
Lanczos4ResizeMT(width() - 64, height() - 64, threads = 4)
BlackmanResizeMT(width() - 64, height() - 64, threads = 4)
Spline16ResizeMT(width() - 64, height() - 64, threads = 4)
Spline36ResizeMT(width() - 64, height() - 64, threads = 4)
Spline64ResizeMT(width() - 64, height() - 64, threads = 4)
GaussResizeMT(width() - 64, height() - 64, threads = 4)
SincResizeMT(width() - 64, height() - 64, threads = 4)

TheFluff
14th August 2016, 01:13
benchmark?
I did. http://pastebin.com/ZCNnN5RW.

38.607 sec [77.706fps] #threads=1, prefetch=1
36.943 sec [81.206fps] #threads=2, prefetch=1

Is this an error in the benchmark or does it basically not scale at all with two threads?

jpsdr
14th August 2016, 10:01
As i'm often doing this at work during lunch break, and i have only at it a 2 cores CPU without HT, when i've checked on it between 1 or 2 threads, there was a significant difference, and yes, looking also at the result, it scales with 2 threads.

I'm very busy today, but tomorrow i'll try on my PC some benchmark also...

jpsdr
15th August 2016, 10:21
Some tests on my PC :


[OS/Hardware info]
OS version: Windows 7 (x64) Service Pack 1 (Build 7601)
CPU (brand string): Intel(R) Core(TM) i7-6950X CPU @ 3.00GHz
CPU (code name): Unknown Core 2
CPU clock (measured): 3624 MHz
CPU cores / Logical cores: 10 / 20


[Avisynth info]
Avisynth VersionString: AviSynth+ 0.1 (r2151, MT, x86_64)
Avisynth VersionNumber: 2.60
File version: 0.1.0.0
Avisynth Interface Version: 6
Multi-threading support: Yes
Linker/compiler version: 14.0

[Clip info]
Number of frames: 10000
Length (hh:mm:ss.ms): 00:06:40.000
Frame width: 3776
Frame height: 2096
Framerate: 25.000 (25/1)
Colorspace: YV12

[Runtime info]
Frames processed: 10000 (0 - 9999)
FPS (min | max | average): 118.3 | 149685 | 492.7
Memory usage (phys | virt): 1196 | 1191 MiB
Thread count: 41
CPU usage (average): 99%

Time (elapsed): 00:00:20.295


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,9999)
Spline36Resize(width()-64,height()-64)
Prefetch(20)



[OS/Hardware info]
OS version: Windows 7 (x64) Service Pack 1 (Build 7601)
CPU (brand string): Intel(R) Core(TM) i7-6950X CPU @ 3.00GHz
CPU (code name): Unknown Core 2
CPU clock (measured): 3624 MHz
CPU cores / Logical cores: 10 / 20


[Avisynth info]
Avisynth VersionString: AviSynth+ 0.1 (r2151, MT, x86_64)
Avisynth VersionNumber: 2.60
File version: 0.1.0.0
Avisynth Interface Version: 6
Multi-threading support: Yes
Linker/compiler version: 14.0

[Runtime info]
Frames processed: 10000 (0 - 9999)
FPS (min | max | average): 459.2 | 505.2 | 502.5
Memory usage (phys | virt): 63 | 58 MiB
Thread count: 61
CPU usage (average): 92%

Time (elapsed): 00:00:19.900


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,9999)
Spline36ResizeMT(width()-64,height()-64)
#Prefetch(20)



[OS/Hardware info]
OS version: Windows 7 (x86) Service Pack 1 (Build 7601)
CPU (brand string): Intel(R) Core(TM) i7-6950X CPU @ 3.00GHz
CPU (code name): Unknown Core 2
CPU clock (measured): 3623 MHz
CPU cores / Logical cores: 10 / 20


[Avisynth info]
Avisynth VersionString: AviSynth 2.60, build:Mar 31 2015 [16:38:54]
Avisynth VersionNumber: 2.60
File version: 2.6.0.6
Avisynth Interface Version: 6
Multi-threading support: No
Linker/compiler version: 6.0


[Runtime info]
Frames processed: 10000 (0 - 9999)
FPS (min | max | average): 21.46 | 43.44 | 43.26
Memory usage (phys | virt): 46 | 44 MiB
Thread count: 1
CPU usage (average): 5%

Time (elapsed): 00:03:51.170


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,9999)
Spline36Resize(width()-64,height()-64)



[OS/Hardware info]
OS version: Windows 7 (x86) Service Pack 1 (Build 7601)
CPU (brand string): Intel(R) Core(TM) i7-6950X CPU @ 3.00GHz
CPU (code name): Unknown Core 2
CPU clock (measured): 3623 MHz
CPU cores / Logical cores: 10 / 20


[Avisynth info]
Avisynth VersionString: AviSynth 2.60, build:Mar 31 2015 [16:38:54]
Avisynth VersionNumber: 2.60
File version: 2.6.0.6
Avisynth Interface Version: 6
Multi-threading support: No
Linker/compiler version: 6.0

[Runtime info]
Frames processed: 10000 (0 - 9999)
FPS (min | max | average): 404.0 | 484.2 | 481.5
Memory usage (phys | virt): 47 | 45 MiB
Thread count: 41
CPU usage (average): 90%

Time (elapsed): 00:00:20.769


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,9999)
Spline36ResizeMT(width()-64,height()-64)

Groucho2004
15th August 2016, 10:59
Intel(R) Core(TM) i7-6950X
Nice CPU, bloody expensive.

jpsdr
15th August 2016, 11:04
Nice CPU, bloody expensive.
It helps when brother works on Intel...:D

real.finder
18th August 2016, 02:38
intel SSE4.2 Release gave me 0x7e error in load plugin for both x64 and x86

the cpu is core i7 X 980 in os windows server 2008 R2, same intel SSE4.2 Release for nnedi3 always work

jpsdr
18th August 2016, 08:45
I'll check when back at home if i see anything strange in the build profile. My standard PC is no more than SSE4.2 (i7@850), and didn't have issue with it. Do you have the last Intel Redistribuable version ? (Don't know if it can be related...).

EDIT : Can you check if you have the same issue with either the AutoYUY2 filter and/or my VDub filters ?

real.finder
18th August 2016, 15:29
I'll check when back at home if i see anything strange in the build profile. My standard PC is no more than SSE4.2 (i7@850), and didn't have issue with it. Do you have the last Intel Redistribuable version ? (Don't know if it can be related...).

EDIT : Can you check if you have the same issue with either the AutoYUY2 filter and/or my VDub filters ?

AutoYUY2 SSE4.2 gave same error

Intel Redistribuable

I don't see it before, don't you build it as static? maybe you build nnedi3 as static but the others not?

jpsdr
18th August 2016, 16:13
I think all are build as static (i'll chek later). Get and install the Intel Redistribuable (https://software.intel.com/sites/default/files/managed/46/54/ww_icl_redist_msi_2016.3.207.zip), and check if it's this.

real.finder
18th August 2016, 16:33
I think all are build as static (i'll chek later). Get and install the Intel Redistribuable (https://software.intel.com/sites/default/files/managed/46/54/ww_icl_redist_msi_2016.3.207.zip), and check if it's this.

same thing :(

Groucho2004
18th August 2016, 17:00
same thing :(
You could try troubleshooting with Dependency Walker and AVSMeter (with the "-avsinfo" switch).

jpsdr
18th August 2016, 18:25
I've checked the build profile, and found for now nothing unusual, and i must confess that i have no idea what error 0x7e is... :(
After, you still have the standard no Intel releases, they are here as safeguard for such kind of cases. And in the best case, speed difference would probably be only a few percent.
Do you have the same issue with my VDub filters ?

burfadel
19th August 2016, 07:28
benchmark?
I did. http://pastebin.com/ZCNnN5RW.

What if you did thread 4, prefetch 4 (for example) instead of threads/prefetch as 8/1 or 1/8?

MysteryX
19th August 2016, 08:14
Why are you guys spending so much time on this if it gives lower performance than the regular filters with Prefetch?

jpsdr
19th August 2016, 09:12
Why are you guys spending so much time on this if it gives lower performance than the regular filters with Prefetch?
Mine #24 (http://forum.doom9.org/showpost.php?p=1777109&postcount=24) is a little higher on avs+, and a looot on standard avisynth. So basicaly, it depends on people. I never said this was for avs+ only, and that was also the purpose of it. After, everyone is free to use what they want. Personnaly, i rather keep the memory usage low, even at the cost of more threads created, but others are totaly free to have a different point of view, of course.

I've take a look at fk3db to see if i can do the same thing, but it's a lot more complex to follow, and the C++ is a little to much ++ for me... :(

Groucho2004
19th August 2016, 10:00
Mine #24 (http://forum.doom9.org/showpost.php?p=1777109&postcount=24) is a little higher on avs+, and a looot on standard avisynth. So basicaly, it depends on people. I never said this was for avs+ only, and that was also the purpose of it. After, everyone is free to use what they want. Personnaly, i rather keep the memory usage low, even at the cost of more threads created, but others are totaly free to have a different point of view, of course.
I too think it's a very good alternative for "classic" Avisynth users. It scales well, uses very little memory and it's easy to substitute the standard resizers. Nicely done. ;)

FranceBB
19th August 2016, 11:54
Tested using an i7 4 core, 8 threads, 3.60 GHz, 8 MB cache l3, AVX 2, using avisynth trying to upscale a progressive material via Spline64Resize and Spline64ResizeMT to 4K and encode it with x265.
It indeed increases the speed as the "pitch" reached by the standard Spline64 is 3.05, and is stable at 2.88 fps, while Spline64MT reaches a "pitch" of 3.84 and is stable at 3.24 fps, which is a very good improvement for me!
I tested it using an old processor as well, which is a monocore dual thread, which supports up to SSE3 trying to downscale from 1080p to 720p via Spline64 and I can tell ya that the Mt Version takes longer to start and it doesn't have any noticeable benefits. So... it really depends on your CPU. I'm gonna try it on an AMD 6 core as soon as I can, as AMD handles multithreading differently compared to Intel (in a worse way, most of the time) and maybe AMD CPUs will be the ones who will benefit most from it.

Oh, by the way, you said that you tried to do it with f3kdb, right? If you have time, how about doing it with the old good LSFmod as well? *_*

Groucho2004
19th August 2016, 13:09
Tested using an i7 4 core, 8 threads, 3.60 GHz, 8 MB cache l3, AVX 2, using avisynth trying to upscale a progressive material via Spline64Resize and Spline64ResizeMT to 4K and encode it with x265.
It seems to me that you mainly measured the encoding speed. :rolleyes:

jpsdr
19th August 2016, 20:29
I've made a new version with optimized threads repartition according physical cores.

Some tests with it :

[OS/Hardware info]
OS version: Windows 7 (x64) Service Pack 1 (Build 7601)
CPU (brand string): Intel(R) Core(TM) i7-6950X CPU @ 3.00GHz
CPU (code name): Unknown Core 2
CPU clock (measured): 3624 MHz
CPU cores / Logical cores: 10 / 20


[Avisynth info]
Avisynth VersionString: AviSynth+ 0.1 (r2172, MT, x86_64)
Avisynth VersionNumber: 2.60
File version: 0.1.0.0
Avisynth Interface Version: 6
Multi-threading support: Yes
Linker/compiler version: 14.0

[Clip info]
Number of frames: 10000
Length (hh:mm:ss.ms): 00:06:40.000
Frame width: 3776
Frame height: 2096
Framerate: 25.000 (25/1)
Colorspace: YV12

[Runtime info]
Frames processed: 10000 (0 - 9999)
FPS (min | max | average): 471.4 | 509.3 | 506.4
Memory usage (phys | virt): 63 | 58 MiB
Thread count: 41
CPU usage (average): 60%

Time (elapsed): 00:00:19.749


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,9999)
Spline36ResizeMT(width()-64,height()-64,threads=10)
#Spline36Resize(width()-64,height()-64)
#Prefetch(20)



[Clip info]
Number of frames: 10000
Length (hh:mm:ss.ms): 00:06:40.000
Frame width: 3776
Frame height: 2096
Framerate: 25.000 (25/1)
Colorspace: YV12

[Runtime info]
Frames processed: 10000 (0 - 9999)
FPS (min | max | average): 460.0 | 502.9 | 501.0
Memory usage (phys | virt): 64 | 59 MiB
Thread count: 61
CPU usage (average): 90%

Time (elapsed): 00:00:19.962


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,9999)
Spline36ResizeMT(width()-64,height()-64,threads=0)
#Spline36Resize(width()-64,height()-64)
#Prefetch(20)



[Clip info]
Number of frames: 10000
Length (hh:mm:ss.ms): 00:06:40.000
Frame width: 3776
Frame height: 2096
Framerate: 25.000 (25/1)
Colorspace: YV12

[Runtime info]
Frames processed: 10000 (0 - 9999)
FPS (min | max | average): 118.2 | 217181 | 450.0
Memory usage (phys | virt): 624 | 619 MiB
Thread count: 31
CPU usage (average): 63%

Time (elapsed): 00:00:22.222


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,9999)
#Spline36ResizeMT(width()-64,height()-64,threads=0)
Spline36Resize(width()-64,height()-64)
Prefetch(10)



[Clip info]
Number of frames: 10000
Length (hh:mm:ss.ms): 00:06:40.000
Frame width: 3776
Frame height: 2096
Framerate: 25.000 (25/1)
Colorspace: YV12

[Runtime info]
Frames processed: 10000 (0 - 9999)
FPS (min | max | average): 125.1 | 191873 | 493.3
Memory usage (phys | virt): 1196 | 1191 MiB
Thread count: 41
CPU usage (average): 99%

Time (elapsed): 00:00:20.273


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,9999)
#Spline36ResizeMT(width()-64,height()-64,threads=0)
Spline36Resize(width()-64,height()-64)
Prefetch(20)


And winners awards are :
The fastest : MT version with 10 threads (not what i hoped...:sly: )
The more memory used : Core version with 20 threads.
The more threads created : MT version with 20 threads.

Well, it depends of CPU and maybe a little tunning also.
Well, finaly, it's up to you to choose whatever version you want to use... :D

jpsdr
20th August 2016, 15:19
Pleeeaseee !!!! Help wanted.... :(

I've tried to create an external ThreadPool in a DLL for plugin to use.
I've searched and found how to create a simple DLL.
I've been ... almost... successfull.

I am for now doing tests on my "standard" PC, so it's Windows 7 x86 with Avisynth 2.6.0.

You can get the source of the ThreadPool (https://github.com/jpsdr/ThreadPoolDLL) DLL and the filter (https://github.com/jpsdr/ResampleMT).

I have one minor and one critical issue.

The minor : Even if i put the DLL in the same directory of the plugin, it's not working, i have to put it in the system32 directory. Strange, because i hadn't this issue when i've first made some quick very small little test, of an exe using 2 dll, both using a third dll... When everyone was in the same directory, everyone was happy... If anyone can tell me if there is something to do during the build process, on compiler option to add for this to be solved.

The critical : Well... Indeed, everything works fine, i can open the avs script in VDub, etc... Until.... I want to close it :eek:
It seems that in the FreeData called by the destructor, the program is stuck on the line

WaitForSingleObject(thds[i],INFINITE);

I've made a lot of trick, tests, it seems that whatever i do, the StaticThreadpool function don't want to end/exit.
The strange things is that i'm doing exactly the same working thing i'm doing everywhere else.
But, as it's the first time i'm trying to do a DLL, maybe the way i'm doing it is totaly wrong, it works by chance, and the fact that it doesn't end properly is caused by that.
Maybe it's something else, compiler option, just a little trick, no idea.

So, if there is someone with enough courage and powerwill to take a look at the sources code i've provided...

In any case :thanks:

jpsdr
20th August 2016, 18:48
I've used a workaround for the major issue (but still not sure if my way of doing things is good).
But with avs+, strange result.

jpsdr
20th August 2016, 19:17
After some test, finaly, speed is slower. Another bad idea and almost 2 days wasted... :(
Well, it's when trying that you see. But... Instead of an external DLL, the same thing internaly... May keep up with speed, and reduce the number of threads... Another thing to try.

jackoneill
20th August 2016, 20:02
Is avstp.dll not suitable for your needs?

Groucho2004
20th August 2016, 21:33
Is avstp.dll not suitable for your needs?I did some tests with avstp and plugins that use it. Unfortunately, it's not very efficient and does not scale well.

Groucho2004
20th August 2016, 21:36
After some test, finaly, speed is slower. Another bad idea and almost 2 days wasted... :(
Not really wasted, I'm sure you learned something. At least that's how I like to look at such experiences.

jpsdr
21st August 2016, 09:13
I did not tested it with MT disabled.

My internaly MT plugins are compatible with MT enabled, but they are only MT_MULTI_INSTANCE, and not MT_FRIENDLY.
I personnaly don't use MT mode, so...

jpsdr
21st August 2016, 09:16
Try to use avstp.dll
My experience (what i've just tried to do) with a thread pool in an external DLL is that's it's slower than the internal thread pool, so, i'll stay with an internal thread pool.

Groucho2004
21st August 2016, 09:51
@jpsdr
In comparisons like this one (http://forum.doom9.org/showthread.php?p=1777634#post1777634), you can make use of this AVSMeter ini setting:

"DisplayEfficiencyIndex" (0 or 1):
If set to "1", the result of (FPS / CPU usage) is printed to the console. This ratio indicates the efficiency of a script (higher = better) and is useful for comparing different versions of a script or scripts that are supposed to do the same thing.

jpsdr
21st August 2016, 11:07
Ok, new version.
- Update to new avisynth header (don't know if it changes anything, but don't hurt).
- Use an external thread pool class, but internaly within the DLL, not on an external DLL.

Previous 1.0.1 version :

[OS/Hardware info]
OS version: Windows 7 (x64) Service Pack 1 (Build 7601)
CPU (brand string): Intel(R) Core(TM) i7-6950X CPU @ 3.00GHz
CPU (code name): Unknown Core 2
CPU clock (measured): 3624 MHz
CPU cores / Logical cores: 10 / 20

[Avisynth info]
Avisynth VersionString: AviSynth+ 0.1 (r2172, MT, x86_64)
Avisynth VersionNumber: 2.60
File version: 0.1.0.0
Avisynth Interface Version: 6
Multi-threading support: Yes
Linker/compiler version: 14.0

[Clip info]
Number of frames: 1000
Length (hh:mm:ss.ms): 00:00:40.000
Frame width: 3200
Frame height: 1520
Framerate: 25.000 (25/1)
Colorspace: YV12

[Runtime info]
Frames processed: 1000 (0 - 999)
FPS (min | max | average): 39.57 | 47.14 | 46.84
Memory usage (phys | virt): 91 | 87 MiB
Thread count: 221
CPU usage (average): 47%

Time (elapsed): 00:00:21.350


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,999)
BilinearResizeMT(width()-64,height()-64,threads=10)
BicubicResizeMT(width()-64,height()-64,threads=10)
LanczosResizeMT(width()-64,height()-64,threads=10)
Lanczos4ResizeMT(width()-64,height()-64,threads=10)
BlackmanResizeMT(width()-64,height()-64,threads=10)
Spline16ResizeMT(width()-64,height()-64,threads=10)
Spline36ResizeMT(width()-64,height()-64,threads=10)
Spline64ResizeMT(width()-64,height()-64,threads=10)
GaussResizeMT(width()-64,height()-64,threads=10)
SincResizeMT(width()-64,height()-64,threads=10)


Actual 1.1.0 version :

[Clip info]
Number of frames: 1000
Length (hh:mm:ss.ms): 00:00:40.000
Frame width: 3200
Frame height: 1520
Framerate: 25.000 (25/1)
Colorspace: YV12

[Runtime info]
Frames processed: 1000 (0 - 999)
FPS (min | max | average): 27.91 | 47.02 | 46.56
Memory usage (phys | virt): 83 | 78 MiB
Thread count: 31
CPU usage (average): 47%

Time (elapsed): 00:00:21.477


[Script]
Colorbars(width=1920*2,height=1080*2,pixel_type="yv12").killaudio().assumefps(25,1).trim(0,999)
BilinearResizeMT(width()-64,height()-64,threads=10)
BicubicResizeMT(width()-64,height()-64,threads=10)
LanczosResizeMT(width()-64,height()-64,threads=10)
Lanczos4ResizeMT(width()-64,height()-64,threads=10)
BlackmanResizeMT(width()-64,height()-64,threads=10)
Spline16ResizeMT(width()-64,height()-64,threads=10)
Spline36ResizeMT(width()-64,height()-64,threads=10)
Spline64ResizeMT(width()-64,height()-64,threads=10)
GaussResizeMT(width()-64,height()-64,threads=10)
SincResizeMT(width()-64,height()-64,threads=10)


The speed loss is 0.6%... Nothing to cry about compared to the thread explosion prevention. And bonus, even a little less memory used.

My next step : Doing the same thing on other plugins i'm working on (AutoYUY2 and NNEDI3).

My next next step, creating a plugin package with my 3 filters, but the filters in standalone version will continue and will not be dropped.
The point : None if you're using only one of them, reduce the number of threads created if you're using more than one of them, because they'll all share the same thread pool.
If using an external DLL thread pool didn't produce a noticeable speed lost, it would have been the best, but it's, still from my point of view (of course you may not share it) the best compromise.

For those who are still wondering the point of the whole subjet ? I personnaly don't use the MT mode because i don't want the memory explosion usage when you have a lot of cores.