Log in

View Full Version : AviSynth+ thread Vol.2


Pages : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 [34] 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

StainlessS
8th December 2021, 23:12
Originally Posted by Dogway View Post
Also StainlessS stated that using 'lut' with scaled_inputs (ie. lut over scaled down to 8-bit expression) would be slower than realtime.
That's just a 'gut feeling'.

Dogway
8th December 2021, 23:18
Can CombinePlanes combine directly to YV12 when U and V clips are half resolution of Y?

Yes, you just need to provide the "pixel_type" or "sample_clip".
Actually even Expr() can combine planes if you declare the "format" type, but it might use the slow CombinePlanes() code path, so maybe pinterf can also look into that.

That's just a 'gut feeling'.

Ah well, I have you in very high regard lol

pinterf
9th December 2021, 09:02
Yes, actually I was testing with the following:
Y = ExtractY()
U = ExtractU()
V = ExtractV()
# some per plane filtering
YtoUV(U,V,Y)
# CombinePlanes(Y,U,V,planes="YUV",sample_clip=a)
But probably there are more cases for optimizations.

Thanks for looking into that.
How did you measure? YtoUV is not any quicker with this script. Sometimes CombinePlanes is faster but mostly they are even, any difference is probably a measurement glitch. Both are running at ~48000 fps when processing a Colorbars(pixel_type="YV12"). That 48000 fps also means that this is too quick to be a bottleneck function, making it even 50% quicker has hardly any measurable effect on a real script.

EDIT:
the provided sample was not perfect: you don't need to specify a third Y parameter because it is then copied as well and the whole thing is perfectly identical to present CombinePlanes.
Colorbars(pixel_type="YV12")
Y = ExtractY()
U = ExtractU()
V = ExtractV()
# some per plane filtering
YtoUV(U,V) # instead of YtoUV(U,V,Y)


Now I see the speed difference (which probably does not affect a bigger script's speed). But anyway, let's focus on perfection.

EDIT2:
The speed difference was because I was stupid and omitted the Y parameter from the YtoUV example.

Finally. These are giving identical results. With identical speed. They are working the same way internally. They create a new empty frame then copy source planes bytes one by one.
Colorbars(pixel_type="YV12")
a=last
Y = ExtractY()
U = ExtractU()
V = ExtractV()
# some per plane filtering
#YtoUV(U,V,Y)
CombinePlanes(Y,U,V,planes="YUV", source_planes="YYY",sample_clip=a)

Dogway
9th December 2021, 19:44
Yes sorry for the delay. Indeed with synthetic or even staged tests I get almost same speed (with a slight edge on YtoUV), in any case my tests were with the rework of ex_gaussianblur() which uses by default mergeluma() (UV=2). Here (https://pastebin.com/h8ZLyChG)an almost finished version of the filter.
Testing with 1080
setmemorymax()
DGSource("1080psource.dgi")
ConvertBits(16)
ex_gaussianblur(6) # 400fps (340fps with CombinePlanes)
Prefetch(4) # This seems ideal value for scalers on a 4/8 CPU


I will try to come up with a simplified script.

EDIT: Ok, this is a simpler script but still doesn't show the 15% speed difference
Y = ExtractY().BicubicResize(round(width()/1.5),round(height()/1.5))
Y = Y.BicubicResize(width(),height())
mergeluma(y)

I thought the crop in my filter didn't go well with CombinePlanes, but testing with pad=false (no padding) showed the same if not more speed gap. So I can only think GaussResize() doesn't go well with CombinePlanes.

EDIT2: Ok, here's a stripped down test that starts to show the issue (still not quite 15% diff) probably cropping in-between makes things worse:
a=last
ExtractY().BilinearResize(344,204)
GaussResize(a.width(),a.height(),p=9)
#mergeluma(a,last)
CombinePlanes(last,a,planes="YUV",sample_clip=a)

VoodooFX
9th December 2021, 21:12
Tested and got +11% speed with CombinePlanes, instead of upsizing chroma then downsizing it when using MergeLuma.

Dogway
9th December 2021, 23:13
This shows a +6% speed for mergeluma():
setmemorymax()
DGSource("1080psource.dgi")
ConvertBits(16)
a=last
w0=width() h0=height() p=64

ExtractY().BilinearResize(344,204, src_left=-p, src_top=-p, src_width=w0+p+p, src_height=h0+p+p)
GaussResize(w0+p+p,h0+p+p,p=9)
crop (p, p, -p, -p)
mergeluma(a,last) # 384
#CombinePlanes(last,a,planes="YUV",sample_clip=a) # 363
Prefetch(4)
When used with ex_GaussianBlur() (for unknown reasons) it can reach over 10~15%, my linked script only needs ResizersPack for nmod()

VoodooFX
9th December 2021, 23:40
What if you remove decoding "bottleneck" with BlankClip(last) after DGSource? I didn't used Prefetch.

Dogway
10th December 2021, 00:25
With BlankClip(last) it's same speed using Prefetch(4) but I always test in context with real world material, maybe CombinePlanes() is superfast on its own, but has a harder time when frame is served in a specified manner.
To note I also experienced these slowdowns in TransformsPack which is a different monster, there I don't crop nor resize, simply do per-plane matrix operations with Expr() and then Combine.
YUV444 source # to don't add more YUV -> RGB overhead
m=RGB_to_XYZ("sRGB",true)
MatrixClip2(m)
Prefetch(4)

function MatrixClip2 ( clip clp, float_array mat, string "fmt_o") {

rgb = isRGB(clp)
fmt_o = Default(fmt_o, rgb ? "RGB" : "YUV")

CLPa = ExtractClip(clp)

# clip · 3x3
C = DotClipA(CLPa,[mat[0],mat[3],mat[6]])
L = DotClipA(CLPa,[mat[1],mat[4],mat[7]])
P = DotClipA(CLPa,[mat[2],mat[5],mat[8]])

# YtoUV(L, P, C) } # 141
CombinePlanes(C, L, P, planes=fmt_o) } # 139


With prefetch(6) this doesn't happen, they are same speed, but at the cost of a lower speed. The optimal Prefetch here again is 4, at least for my CPU which sees both methods increase speed albeit one more than the other.


On another note, in AddBorders() I was about to add "color" to the Alpha plane of RGB, there's no such an option right?

pinterf
10th December 2021, 09:33
This shows a +6% speed for mergeluma():
setmemorymax()
DGSource("1080psource.dgi")
ConvertBits(16)
a=last
w0=width() h0=height() p=64

ExtractY().BilinearResize(344,204, src_left=-p, src_top=-p, src_width=w0+p+p, src_height=h0+p+p)
GaussResize(w0+p+p,h0+p+p,p=9)
crop (p, p, -p, -p)
mergeluma(a,last) # 384
#CombinePlanes(last,a,planes="YUV",sample_clip=a) # 363
Prefetch(4)
When used with ex_GaussianBlur() (for unknown reasons) it can reach over 10~15%, my linked script only needs ResizersPack for nmod()
Thanks, I got it, checked how MergeLuma works.
When the input clip is not referenced by other clips in the filter chain (there is exactly one reference on it, technically "IsWritable") MergeLuma can obtain a write-permission directly, sparing the need of copying Y plane. I'm gonna check this on CombinePlane.

EDIT:
MergeLuma is called w/o passing weight, so weight is 1.0.
This means the luma of second clip (last) is kept 100%.
This also means that the smaller U and V planes (4:2:0) are needed to be copied, saving time.
But:
this is not the case here, since 'last' is a luma-only Y and cannot accept U+V copy.
In this MergeLuma example all three planes are copied to a brand new empty frame which is the worst case.

Dogway
11th December 2021, 17:52
Thanks for looking into it. Not sure what that means, that MergeLuma (CombinePlanes regardless) can work even faster? In any case good you could spot it because a 15% speed difference isn't normal with the example of ex_gaussianblur().

I think I found another bug, masktools2 related though while trying to match my ex_lutspa() version:
mt_lutspa(mode="relative", expr="x range_max *",U=128,V=128)

Outputs 65501 as YPlaneMax for 16-bit instead of 65535.

And some issues with internal filters with color arguments like BlankClip, Blackness, Letterbox, AddBorders and FadeXXX. If you specifiy white (color_yuv=$ffffff or $ff8080) output is 65280 for 16-bit, not suitable for masks. I think a solution would be to map automatically 0~15 and 236~255 values to full scale if a fulld argument is not desired.

pinterf
12th December 2021, 20:49
Thanks for looking into it. Not sure what that means, that MergeLuma (CombinePlanes regardless) can work even faster? In any case good you could spot it because a 15% speed difference isn't normal with the example of ex_gaussianblur().

I think I found another bug, masktools2 related though while trying to match my ex_lutspa() version:
mt_lutspa(mode="relative", expr="x range_max *",U=128,V=128)

Outputs 65501 as YPlaneMax for 16-bit instead of 65535.

And some issues with internal filters with color arguments like BlankClip, Blackness, Letterbox, AddBorders and FadeXXX. If you specifiy white (color_yuv=$ffffff or $ff8080) output is 65280 for 16-bit, not suitable for masks. I think a solution would be to map automatically 0~15 and 236~255 values to full scale if a fulld argument is not desired.
Aside from the fact that similar filters sometimes report different speeds I've specialized two cases for CombinePlanes, but I'm gonna test them more.

- when the 1st clip's Y plane can be kept - when selected stars has sysygy and Mars stops its retrograde motion
Condition: 1st clip has the same format as the output

- when the 2nd clip's UV planes can be kept - condition as at the first case :)
Condition: 2nd clip has the same format as the output

Yep, colors are simply treated as rec601 limited range ones.
For this reason BlankClip has an exact color array syntax for passing exact, unscaled color values.
For other filters where color is given by a single integer number my first statement holds.

Masktools: yes, there are things to backport from Expr, just for the sake of make consistency between them. The mt_lutspa you mentioned maybe not a such difference but a simple difference, but hey, the more they resemble each other the happier world.

Dogway
12th December 2021, 21:13
Yes, no problem, I was working from the other side, making Expr wrappers work more like masktools2, felt it was nice to report even if I don't use masktools much.
What array syntax do you mean? I only see int color, and int color_yuv the later has an extra option (http://avisynth.nl/index.php/Colors)for integer color definition instead of hexadecimal, but testing with max value 16777215 still gives me 65280.
Currently the only option is a post processing to scale values from bitshift to fullscale, but this makes things slower.

pinterf
13th December 2021, 09:31
There is a colors array parameter. (signature: [colors]f+)
Now that script arrays are part of Avisynth+, Wiki could be refreshed with it. It was my test parameter but seems it was missed from documentation, it appeared only in an early change log.

pinterf
13th December 2021, 09:34
Integer and hexadecimal covers the very same 32 bit integer in the background, former is in decimal radix, latter is written is hexadecimal notation.

Dogway
13th December 2021, 14:20
ooooooh wonderful! colors=[65535,65535,65535]

By the way I was refactoring ex_bs() to make it behave like avisynth does but found some inconsistencies or maybe I'm mistaken.

Taking as example 10-bit value 514, which is range_half in full scale and converting to narrow range bitshift scale
# HBD Scaling Range compression
# fs bs fs-1 bs bs bs
# ((((514*(65280/1023)) *56064)/65280)+4096) = 32265 (ConvertBits(16,fulls=true,fulld=false)) 32265.009/256 = 126.03519
# fs bs+1 fs bs bs bs
# ((((514*(65281/1024)) *56064)/65280)+4096) = 32237 (Alternative) Satisfies: (32237.93/256 = 125.929418 = ((128*219)/255)+16) = 125,92941176470588235294117647059

Another example. Simply full range scaling the same 10-bit value to 16-bit full scale
# fs fs fs-1
# 514*65536/1023 = 32928 (ConvertBits(16,fulls=true,fulld=true))
# fs fs fs
# 514*65536/1024 = 32896 (Alternative) Satisfies n*256+n = 128*256+128

For an exact roundtrip (saving rounding conventions) you have to repeat process in the opposite direction.
For example I found that doing range conversion first in higher bitdepth is preferable otherwise convert up in bitdepth before range conversion.

Converting 512 from TV levels bitshift scale to 16-bit PC levels full scale

# bs fs bs+1 fs fs fs
# (((512*(65536/1021)) -4112)/56283)*65535 = 33478,684609501831404
# fs bs fs bs bs+1 bs
# (((33478.68461*56283)/65535)+4112)*(1021/65536) = 512

Boulder
13th December 2021, 16:53
@pinterf, do you see anything Avisynth+ core related with this issue? Settings some points values manually works, but inputting a GIMP curve file fails with an access violation. It seems to pass inputting the luma points but crashes with the next set. I also tried installing the Avisynth+ build from AviSynthPlus_3.7.0_20210111.exe but it didn't help.

https://forum.doom9.org/showthread.php?p=1959135#post1959135

DTL
13th December 2021, 17:55
Finally found what was wrong with first attempt to use large pages buffers for MVtools processing - it is cache set overloading because of limited capacity of N-ways set-associative caches for some memory access patterns. It was especially critical to MVtools with lots (>8) equal sized buffers processing of single x,y coordinates data from many frames at once (in MDegrainN operation at least).

This hardware-limit issue also described in Intel Software Optimization manual:
3.6.7 Capacity Limits and Aliasing in Caches
There are cases in which addresses with a given stride will compete for some resource in the memory
hierarchy.
Typically, caches are implemented to have multiple ways of set associativity, with each way consisting of
multiple sets of cache lines (or sectors in some cases). Multiple memory references that compete for the
same set of each way in a cache can cause a capacity issue. There are aliasing conditions that apply to
specific microarchitectures. Note that first-level cache lines are 64 bytes. Thus, the least significant 6 bits
are not considered in alias comparisons.
3.6.7.1 Aliasing Cases in the PentiumŪ M, IntelŪ Core™ Solo, IntelŪ Core™ Duo and IntelŪ Core™
2 Duo Processors
Pentium M, Intel Core Solo, Intel Core Duo and Intel Core 2 Duo processors have the following aliasing
case:
• Store forwarding — If a store to an address is followed by a load from the same address, the load
will not proceed until the store data is available. If a store is followed by a load and their addresses
differ by a multiple of 4 KBytes, the load stalls until the store operation completes.
Assembly/Compiler Coding Rule 49. (H impact, M generality) Avoid having a store followed by a
non-dependent load with addresses that differ by a multiple of 4 KBytes. Also, lay out data or order
computation to avoid having cache lines that have linear addresses that are a multiple of 64 KBytes
apart in the same working set. Avoid having more than 4 cache lines that are some multiple of 2 KBytes
apart in the same first-level cache working set, and avoid having more than 8 cache lines that are some
multiple of 4 KBytes apart in the same first-level cache working set.
When declaring multiple arrays that are referenced with the same index and are each a multiple of 64
KBytes (as can happen with STRUCT_OF_ARRAY data layouts), pad them to avoid declaring them contiguously. Padding can be accomplished by either intervening declarations of other variables or by artificially
increasing the dimension.
User/Source Coding Rule 8. (H impact, ML generality) Consider using a special memory allocation
library with address offset capability to avoid aliasing. One way to implement a memory allocator to
avoid aliasing is to allocate more than enough space and pad. For example, allocate structures that are
68 KB instead of 64 KBytes to avoid the 64-KByte aliasing, or have the allocator pad and return random
offsets that are a multiple of 128 Bytes (the size of a cache line).
User/Source Coding Rule 9. (M impact, M generality) When padding variable declarations to
avoid aliasing, the greatest benefit comes from avoiding aliasing on second-level cache lines,
suggesting an offset of 128 bytes or more.
4-KByte memory aliasing occurs when the code accesses two different memory locations with a 4-KByte
offset between them. The 4-KByte aliasing situation can manifest in a memory copy routine where the
addresses of the source buffer and destination buffer maintain a constant offset and the constant offset
happens to be a multiple of the byte increment from one iteration to the next.

So corrected version of largepage allocation is: (in DeviceManager.cpp)

virtual BYTE* Allocate(size_t size, int margin)
{
#define RAND_OFFSET_MAX 256
/* overhead about 1.6% max over 2 MB largepage, support about 256 different allocations without addresses of same offset inside frame hit same cache set. */

#define L2L3_CACHE_LINE_SIZE 128

size += margin;
// return new BYTE[size + 16];
// large pages
// to prevent cache set overloading when accessing same frame regions - add random 128-bytes sized offset to different allocations
size_t random = rand();
random *= RAND_OFFSET_MAX;
random /= RAND_MAX;
random *= L2L3_CACHE_LINE_SIZE;

SIZE_T stLPGranularity = GetLargePageMinimum();
size_t iNumLPUnits = (size + random) / stLPGranularity;
SIZE_T stSizeToAlloc = (iNumLPUnits + 1) * stLPGranularity;

BYTE* data = (BYTE*)VirtualAlloc(0, stSizeToAlloc, MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
DWORD error = GetLastError();

if (error == ERROR_NO_SYSTEM_RESOURCES)
env->ThrowError("CPUDevice: LargePages alloc error. Insufficient system resources exist to complete the requested service.\n \
While allocating %d pages of %d size.\n", iNumLPUnits+1, stSizeToAlloc);

if (error != ERROR_SUCCESS)
env->ThrowError("CPUDevice: LargePages alloc error. GetLastError returned: %d\n", error);

data += random; // add random L2L3_CACHE_LINE_SIZE-byte granulated offset up to RAND_OFFSET_MAX*L2L3_CACHE_LINE_SIZE size to the pointer, \
need to be cleared at freeing
return data;
#endif
}

virtual void Free(BYTE* ptr)
{
if (ptr != nullptr) {
// large pages here

// clear random offset and feed 2M-granularity address
ptr = (BYTE*)((uint64_t)ptr >> 21);
ptr = (BYTE*)((uint64_t)ptr << 21);

VirtualFree(ptr, 0, MEM_RELEASE);
// delete[] ptr;
}
}


So it is ready for next round of testing. Make testbuild based on 3.7 sources - https://github.com/DTL2020/AviSynthPlus-LP-mod/releases/tag/3.7-01

This issue may also hits 'standard allocations' so it is good to track used allocated addresses and if found dangerous combinations - adjust it somehow to prevent competing for the same cache set at Avisynth filters working (though multi-frames accessing filters may be rare enough - like temporal denoisers ?).

The size of possible performance penalty - about 60% in fps.

The users of other AVS filters may suffer from this issue if using multi-line accessing (with lines > ways of cache) and data buffer pitch (one or multi lines) is close to 4096 (+-32 or +-64 ?). The solution is to pad frame width with some value to move pitch value outside critical values (around 4096 ?).
One example: MVtools frame width size 1920 and MSuper(hpad=64) - creates 1920+64+64=2048 pitch and each 2nd line vertical access hits same L1D cache set. With 8-ways cache after 8 hit (block height > 16) it become overloaded (no more free lines in the 8-lines cache set) and execution got visible performance penalty.

gispos
13th December 2021, 18:57
@Ferenc or he who knows, where can I find your integer properties value conversion to string?
I can't find the latest avisynth source on GitHub, is it available somewhere?

pinterf
13th December 2021, 19:06
@Ferenc or he who knows, where can I find your integer properties value conversion to string?
I can't find the latest avisynth source on GitHub, is it available somewhere?
You can find some (there is no Primaries and Transfer handling in avs+) in conditional_reader.cpp and for constants you can look into convert_helper.cpp. Maybe these constants would be moved into a separate header file which can be used by plugins developers.

pinterf
13th December 2021, 19:15
Taking as example 10-bit value 514, which is range_half in full scale
Why 514?

Dogway
13th December 2021, 20:54
Why 514?
ConvertBits(8)
Expr("range_half")
ConvertBits(10,fulls=true,fulld=true) # outputs 514

More:
128*2^(10-8) = 512
128*2^(10-8)+(2^(10-8))/2 = 514
257*2^(10-8)/2 = 514
128*2^(10-8) *256*2^(10-8)/255*2^(10-8) = 514
(255*2^(10-8))/2+(256*2^(10-8)-255*2^(10-8)) = 514
32896/2^(16-10) = 514

32896 is range_half in full scale (http://forum.doom9.org/showthread.php?p=1957551#post1957551):
"Special even quicker case: 8->16 bit fulls=true, fulld=true (simply *257)"
128*257 = 32896
128*2^(16-8)+(2^(16-8))/2 = 32896

Another issue is that the constants are not being mapped correctly when range property is full
ConvertBits(16,fulls=true)
Expr("range_half") # outputs 32768

pinterf
14th December 2021, 09:05
I see now, but the logic fails because your base value is 128 which is not true.
8 bit Y full scale range_half is not a precise thing since it must be 127.5, and rounded up to 128 so it cannot be the strict base of further calculations.
My note is that range_half in other than chroma planes has not that special meaning as in chroma, and - as beeing just a rounded value somewhere betwen the extremes - is not more special like e.g. 787.
In luma/rgb full range the only thing in you can be sure that the two extremes are 0 and (2^N )-1, all values in between are scaled proportionally.

pinterf
14th December 2021, 10:24
Another issue is that the constants are not being mapped correctly when range property is full
ConvertBits(16,fulls=true)
Expr("range_half") # outputs 32768
Expr does not use range information from frame property.
There are several Expr parameters which directly control that expression is full or limited when autoscaled feature is used. Not to mention the explicite scaleb and scalef usage.

gispos
18th December 2021, 21:19
I just found a problem with the newer avisynth's (don't know from which version) tested with 3.71 test 34

video = LWLibavVideoSource (SourceFile, cache = False)
audio = LWLibavAudioSource (SourceFile, cache = False)
audioDub(video, audio)
Spline36Resize(1920, 1036)
prefetch(2)

does not work with AvsPmod (C Interface ?), but works with e.g. Avisynth Version 3.62 test 6
If I add a 'last' or remove the prefetch it works.

Spline36Resize(1920, 1036)
last
prefetch(2)

Can anybody confirm this?

Edit:
If no external filter is used but only internal ones like resizer, crop, sharpen, Levels etc. avisynth gets stuck if prefetch used.
If I use an external filter or an older Avisynth, there are no problems with prefetch.

Edit2
3.71 test 12 is OK
3.71 test 25 does not work

Edit3
3.71 test 22 is the last version that works

pinterf
21st December 2021, 13:53
I just found a problem with the newer avisynth's (don't know from which version) tested with 3.71 test 34

video = LWLibavVideoSource (SourceFile, cache = False)
audio = LWLibavAudioSource (SourceFile, cache = False)
audioDub(video, audio)
Spline36Resize(1920, 1036)
prefetch(2)

does not work with AvsPmod (C Interface ?), but works with e.g. Avisynth Version 3.62 test 6
If I add a 'last' or remove the prefetch it works.

Spline36Resize(1920, 1036)
last
prefetch(2)

Can anybody confirm this?

Edit:
If no external filter is used but only internal ones like resizer, crop, sharpen, Levels etc. avisynth gets stuck if prefetch used.
If I use an external filter or an older Avisynth, there are no problems with prefetch.

Edit2
3.71 test 12 is OK
3.71 test 25 does not work

Edit3
3.71 test 22 is the last version that works
Works for me. I'd try installing latest vc++ redistributables?

jpsdr
21st December 2021, 18:32
@gispos: Not sure if it's significant, but what Windows version are you using ?

gispos
21st December 2021, 21:02
I think so, my last version is 14.30.30401.0 from 21.07.2021
Win10 x64

I just tried again, same result. There are no problems with 3.71 test 22.
I think the runtimes should be up to date with version 14.30.30401.0 Wouldn't like to install something over it again.
Unusual.

https://i.postimg.cc/4d6MTdSX/visual-c.jpg (https://postimg.cc/MMGt7WwL)

Edit:
It's probably not the latest, just found version 14.31.30818.0.
Will try it.

gispos
21st December 2021, 21:33
The latest runtimes are installed but unfortunately no changes.
3.71 test 22 is the last version that has no problems with prefetch for me.

Edit:
The newer Avisynth's behave very strangely with me.

No matter how many threads, it doesn't work
Spline36Resize(1280, 720)
prefetch(2)

It doesn't work with prefetch 2
NonlinUSM(z=3, pow=1.2, str=0.25, rad=6)
prefetch(2)

With prefetch 4 it works
NonlinUSM(z=3, pow=1.2, str=0.25, rad=6)
prefetch(4)

Edit2:
And it also seems to depend on the filter.
UnsharpMask (strength = 52, radius = 3, threshold = 4)
prefetch(2)

works, but not with prefetch(4)

Some things work with prefetch(8) but not with prefetch(6).

This is not the case with version 3.71 test 22 and older

gispos
21st December 2021, 22:12
I don't want to cause any stress now, maybe it's just my system, but it's strange how it behaves with the newer versions for me.
What kind of runtimes are needed exactly? As written, I installed the latest package.

StainlessS
21st December 2021, 23:03
GP, if you've got "avstp.dll" in plugins, remove it and re-test.

cretindesalpes
21st December 2021, 23:44
avstp.dll is not related to any of these functions.

gispos
21st December 2021, 23:49
I deleted the DLL years ago. And with earlier versions, earlier 3.71 test 23 it works.
No one else with the problem with AvsPmod?

I save the script and open it with AviSource then there are no problems, which is an indiez for a C Interface bug for me. At least it was so in the past.

StainlessS
22nd December 2021, 00:25
Just 'clutching at straws' pussycat :)

gispos
22nd December 2021, 00:31
All back. I'm so sorry
I tested an older AvsPmod version and thus no problems.:o
Now I'm the ass that gets stressed.

Sorry Ferenc :o

gispos
22nd December 2021, 00:52
All back. I'm so sorry
I tested an older AvsPmod version and thus no problems.:o
Now I'm the ass that gets stressed.

Sorry Ferenc :o
I have to revise.
I had only once tested the older AvsPmod version and apparently a suitable combination of filters and prefetch caught that it seemed it to work.

But if I change filter and prefetch it does not work for most combinations.

Dogway
23rd December 2021, 11:50
Pixel addressing seems to fluctuate a lot depending on prefetch value.
Using ex_expand(3) as an example which is a mix of pixel fetching and 'max' operator, but I'm assuming 'max' is not the issue here.

Source is 8-bit 1080p, loading with DGSource()
ex_expand(3) # 430
Prefetch(4)

ex_expand(3) # 190
Prefetch(8)

2 months ago I tested adding Prefetch() inside the functions, but it didn't work out, performance was much worse than a single call at end of the script.

kedautinh12
23rd December 2021, 12:11
I think DGSource() affect to prefetch. You can change to L-SmashSource and speed will increase

Boulder
23rd December 2021, 13:01
Pixel addressing seems to fluctuate a lot depending on prefetch value.
Using ex_expand(3) as an example which is a mix of pixel fetching and 'max' operator, but I'm assuming 'max' is not the issue here.

Source is 8-bit 1080p, loading with DGSource()
ex_expand(3) # 430
Prefetch(4)

ex_expand(3) # 190
Prefetch(8)

2 months ago I tested adding Prefetch() inside the functions, but it didn't work out, performance was much worse than a single call at end of the script.
I think you want to set the number of threads and frames separately in Prefetch. For example, I use threads=24, frames=12 on my 3900X. Too high value for frames will decrease performance (as will too low too, of course).

Dogway
23rd December 2021, 14:30
@kedautinh12: L-SmashSource doesn't work for me in latest AVS+, using latest build (from August)

Setting frames improves it but still far from Prefetch(4)
ex_expand(3) # 340
Prefetch(8,4)

Anyway, I'm trying to describe a bigger issue. For example for big functions like QTGMC best performance is achieved with Prefetch(8), that traces back to any ex_expand() I have in the function and hits performance. Setting Prefetch(4) to just after ex_expand() won't fix things, but actually make them much worse, there's some discussion here (https://github.com/AviSynth/AviSynthPlus/issues/244).

The problem is on what basis do you set threads and frames? Trial and error?
My main concern is that while I'm doing a bunch of code optimizations in QTGMC that doesn't reflect on speed, compared to say using unoptimzed MaskTools2 calls.

That the code below is faster than my Expr optimization (even with Prefetch(4) ) is something to worry about, even if masktools2 is AVX2.
Merge( lossed1.mt_expand( mode="vertical", U=3,V=3 ), lossed1.mt_inpand( mode="vertical", U=3,V=3 ) )
Prefetch(8)

lossed1.Expr("x[0,-1] A@ x[0,0] B@ max x[0,1] C@ max A B min C min + 0.5 *")
Prefetch(8)

I tried with:
Merge( lossed1.mt_expand( mode="vertical", U=3,V=3,avx=true,avx2=false,sse4=false), lossed1.mt_inpand( mode="vertical", U=3,V=3,avx=true,avx2=false,sse4=false ) )
Prefetch(8)
and indeed it's a tad bit slower.
Looks like SSE4 makes the most change.

tormento
23rd December 2021, 15:53
What is the status of VFR (variable framerate) support?

I went thru a VFR anime with 23.976/29.97 sequences and I really don't know if AVS can handle it in the proper way.

Now that we have frame properties, it could become an interest thing.

Boulder
23rd December 2021, 16:46
The problem is on what basis do you set threads and frames? Trial and error?

I have a pretty stable script setup for my encodes, so I just took a long enough sample range and tested various values multiple times. Threads is always set to the maximum, but the amount of frames is something that might need tweaking. Increasing the maximum cache size is also a must with UHD sources and Prefetch with several frames.

Dogway
24th December 2021, 10:55
I don't think that might work, at least for my CPU (4C/8T) maxing threads to 8 performs worse than with 4, with whatever 'frames' I set it to.

For example (always from my CPU POV) internal resizers perform best with Prefetch(6), pixel addressing with Prefetch(4), mathematical expressions with Prefetch(6), and heavy functions like QTGMC with many expression calls Prefetch(8).

Now if you think you can take the best of both worlds and do:
ex_median()
Prefetch(4)
BicubicResize()
Prefetch(6)

It will actually perform much worse than with a single final Prefetch with 4 or 6, 6 being faster but as I said not optimal for the resizer.

I will run some benchmarks later.

kedautinh12
24th December 2021, 11:06
And if you use prefetch with L-SMASH source. I think it's faster than DGSource

Dogway
24th December 2021, 11:43
And if you use prefetch with L-SMASH source. I think it's faster than DGSource

What L-SMASH build are you using that works with test34? As I said the latest(?) build crashes. A few months back I benchmarked it and it wasn't very fast but you can't compare with GPU decoding.

kedautinh12
24th December 2021, 13:02
What L-SMASH build are you using that works with test34? As I said the latest(?) build crashes. A few months back I benchmarked it and it wasn't very fast but you can't compare with GPU decoding.

I did met crashed same you but in some benchmarked with TemporalDegrain2(postFFT=5) #cause if use bm3d. I seen L-SMASH source faster than DGSource when used with prefetch

Boulder
24th December 2021, 14:08
None of the source filters should do any multithreading regarding Prefetch. L-SMASH might do some internal multithreading when decoding.

qyot27
24th December 2021, 17:51
What L-SMASH build are you using that works with test34? As I said the latest(?) build crashes. A few months back I benchmarked it and it wasn't very fast but you can't compare with GPU decoding.
From git:
https://github.com/AkarinVS/L-SMASH-Works/commits/ffmpeg-4.5

Dogway
24th December 2021, 22:27
From git:
https://github.com/AkarinVS/L-SMASH-Works/commits/ffmpeg-4.5

Thanks! I got deceived with the "AviSynth+ users please use ???" message.

qyot27
24th December 2021, 23:21
Noting, of course, that that mainly arose from the part where you can't build HomeOfAviSynthPlusEvolution/L-SMASH-Works against current FFmpeg-git (https://github.com/HomeOfAviSynthPlusEvolution/L-SMASH-Works/issues/11), thus creating problems for those Linux/mac/etc. users that prefer to install the git version of FFmpeg to their system, only to find out that they can't build LSMASHSource, because it was using stuff that FFmpeg made explicitly part of the private API as part of the transition to the next release. So eventually those fixes will either have to be re-upstreamed to HomeOfAviSynthPlusEvolution/L-SMASH-Works or land in the master branch of AkarinVS/L-SMASH-Works. The AviSynth fix occurred as a side-effect of getting it compiled for newer FFmpeg, as now that it could build, it was throwing assertion failures with AviSynth+-git. Again, something that'll have to be merged back upstream.

Dogway
24th December 2021, 23:37
@qyot27, thanks, so notes for developer only. EDIT: Didn't work either "There is no function named 'LSMASHVideoSource'"

I did some benchmarks, over 1080p@16-bit:
ex_median("median5") # 97 P(4) 111 P(6) 115 P(8) 116 P(8,12)
BicubicResize(1280,720)
BicubicResize(1920,1080) # 340 P(4) 300 P(6) 285 P(8) 280 P(8,8) 250 P(8,12) 305 P(8,4)
ex_edge("scharr") # 390 P(4) 380 P(6) 240 P(8) 200 P(8,12) 280 P(8,8) 200 P(8,16)

With this in mind one would want to run ex_median() with P(8,12) and the rest with P(4), well, it doesn't work like that.
ex_median("median5")
Prefetch(8,12)
BicubicResize(1280,720)
BicubicResize(1920,1080)
ex_edge("scharr")
Prefetch(4) # 90

You get better performance with a single last prefetch, which is not optimal for the resizers nor ex_edge():
ex_median("median5")
BicubicResize(1280,720)
BicubicResize(1920,1080)
ex_edge("scharr")
#Prefetch(4) # 74
#Prefetch(6) # 90
#Prefetch(8) # 93
#Prefetch(8,8) # 81
#Prefetch(8,12) # 92