Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebP - Improve performance #1786

Closed
JimBobSquarePants opened this issue Oct 23, 2021 · 20 comments · Fixed by #1793, #1800 or #1804
Closed

WebP - Improve performance #1786

JimBobSquarePants opened this issue Oct 23, 2021 · 20 comments · Fixed by #1793, #1800 or #1804

Comments

@JimBobSquarePants
Copy link
Member

TomCruiseNeedForSpeedGIF

Now that WebP has been merged #1552 into master we need to polish the performance to bring it up to speed for the release of V2.

We're looking for community contribution here while we focus on bring the Drawing/Fonts libraries up to RC status and also work on the new Unamanaged Memory allocator #1730 so anyone who like to make things go fast please have a crack.

Benchmarks

The last benchmarks (June 2021) indicate that we're a good bit slower than the Magick.NET implementation. (There's a positive here, potentially lots of low hanging fruit)

Decode

Big improvements in .NET Core with some SIMD which is positive. Definitely some allocations to deal with but will require profiling to determine if something else is in play.

Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.202
    [Host]     : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT
    Job-AQFZAV : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
    Job-YCDAPQ : .NET Core 2.1.18 (CoreCLR 4.6.28801.04, CoreFX 4.6.28802.05), X64 RyuJIT
    Job-WMTYOZ : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT

IterationCount=3  LaunchCount=1  WarmupCount=3
|                     Method |        Job |       Runtime |        TestImageLossy |        TestImageLossless |       Mean |     Error |   StdDev |     Gen 0 |     Gen 1 | Gen 2 |   Allocated |
|--------------------------- |----------- |-------------- |---------------------- |------------------------- |-----------:|----------:|---------:|----------:|----------:|------:|------------:|
|        'Magick Lossy Webp' | Job-IERNAB |    .NET 4.7.2 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   105.8 ms |   6.28 ms |  0.34 ms |         - |         - |     - |    17.65 KB |
|    'ImageSharp Lossy Webp' | Job-IERNAB |    .NET 4.7.2 | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 1,145.0 ms | 110.82 ms |  6.07 ms |         - |         - |     - |  2779.53 KB |
|     'Magick Lossless Webp' | Job-IERNAB |    .NET 4.7.2 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   145.9 ms |   8.55 ms |  0.47 ms |         - |         - |     - |    18.05 KB |
| 'ImageSharp Lossless Webp' | Job-IERNAB |    .NET 4.7.2 | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 1,694.1 ms |  55.09 ms |  3.02 ms | 4000.0000 | 1000.0000 |     - | 30556.87 KB |
|        'Magick Lossy Webp' | Job-IMRAGJ | .NET Core 2.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   105.7 ms |   1.89 ms |  0.10 ms |         - |         - |     - |    15.75 KB |
|    'ImageSharp Lossy Webp' | Job-IMRAGJ | .NET Core 2.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   741.6 ms |  21.45 ms |  1.18 ms |         - |         - |     - |  2767.85 KB |
|     'Magick Lossless Webp' | Job-IMRAGJ | .NET Core 2.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   146.1 ms |   9.52 ms |  0.52 ms |         - |         - |     - |    16.54 KB |
| 'ImageSharp Lossless Webp' | Job-IMRAGJ | .NET Core 2.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   522.5 ms |  21.15 ms |  1.16 ms | 4000.0000 | 1000.0000 |     - | 22860.02 KB |
|        'Magick Lossy Webp' | Job-NAASQX | .NET Core 3.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   105.9 ms |   5.34 ms |  0.29 ms |         - |         - |     - |    15.45 KB |
|    'ImageSharp Lossy Webp' | Job-NAASQX | .NET Core 3.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   748.8 ms | 290.47 ms | 15.92 ms |         - |         - |     - |  2767.84 KB |
|     'Magick Lossless Webp' | Job-NAASQX | .NET Core 3.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   146.1 ms |   1.14 ms |  0.06 ms |         - |         - |     - |     15.9 KB |
| 'ImageSharp Lossless Webp' | Job-NAASQX | .NET Core 3.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   480.7 ms |  25.25 ms |  1.38 ms | 4000.0000 | 1000.0000 |     - |  22859.7 KB |
|        'Magick Lossy Webp' | Job-GLNACU | .NET Core 5.0 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   105.7 ms |   4.71 ms |  0.26 ms |         - |         - |     - |    15.48 KB |
|    'ImageSharp Lossy Webp' | Job-GLNACU | .NET Core 5.0 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   645.7 ms |  61.00 ms |  3.34 ms |         - |         - |     - |  2768.13 KB |
|     'Magick Lossless Webp' | Job-GLNACU | .NET Core 5.0 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   146.5 ms |  18.63 ms |  1.02 ms |         - |         - |     - |     15.8 KB |
| 'ImageSharp Lossless Webp' | Job-GLNACU | .NET Core 5.0 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   306.7 ms |  32.31 ms |  1.77 ms | 4000.0000 | 1000.0000 |     - | 22860.02 KB |

Encode

The current implementation suffers from heavy allocations but I suspect a lot of that is low hanging fruit which we can refactor to use our MemoryAllocator types. The lack of difference between NET 472 and NET 5 suggests we have some SIMD opportunities also.

BenchmarkDotNet = v0.12.1, OS = Windows 10.0.19041.630 (2004/?/20H1)
Intel Core i7-6700K CPU 4.00GHz(Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK = 5.0.100

    [Host]     : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
    Job-OUUGWL : .NET Framework 4.8 (4.8.4250.0), X64 RyuJIT
    Job-GAIITM : .NET Core 2.1.23 (CoreCLR 4.6.29321.03, CoreFX 4.6.29321.01), X64 RyuJIT
    Job-HWOBSO : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT

|                     Method |        Job |       Runtime |    TestImage |      Mean |      Error |    StdDev | Ratio | RatioSD |      Gen 0 |     Gen 1 |     Gen 2 |    Allocated |
|--------------------------- |----------- |-------------- |------------- |----------:|-----------:|----------:|------:|--------:|-----------:|----------:|----------:|-------------:|
|        'Magick Webp Lossy' | Job-RYVNHD |    .NET 4.7.2 | Png/Bike.png |  23.30 ms |   0.869 ms |  0.048 ms |  0.14 |    0.00 |          - |         - |         - |     68.19 KB |
|    'ImageSharp Webp Lossy' | Job-RYVNHD |    .NET 4.7.2 | Png/Bike.png |  68.22 ms |  16.454 ms |  0.902 ms |  0.42 |    0.01 |  6125.0000 |  125.0000 |         - |  26359.49 KB |
|     'Magick Webp Lossless' | Job-RYVNHD |    .NET 4.7.2 | Png/Bike.png | 161.96 ms |   9.879 ms |  0.541 ms |  1.00 |    0.00 |          - |         - |         - |    520.28 KB |
| 'ImageSharp Webp Lossless' | Job-RYVNHD |    .NET 4.7.2 | Png/Bike.png | 370.88 ms |  58.875 ms |  3.227 ms |  2.29 |    0.02 | 34000.0000 | 5000.0000 | 2000.0000 | 163177.15 KB |
|                            |            |               |              |           |            |           |       |         |            |           |           |              |
|        'Magick Webp Lossy' | Job-GOZXWU | .NET Core 2.1 | Png/Bike.png |  23.35 ms |   0.428 ms |  0.023 ms |  0.14 |    0.00 |          - |         - |         - |     67.76 KB |
|    'ImageSharp Webp Lossy' | Job-GOZXWU | .NET Core 2.1 | Png/Bike.png |  43.95 ms |   2.850 ms |  0.156 ms |  0.27 |    0.00 |  6250.0000 |  250.0000 |   83.3333 |  26284.72 KB |
|     'Magick Webp Lossless' | Job-GOZXWU | .NET Core 2.1 | Png/Bike.png | 161.44 ms |   3.749 ms |  0.206 ms |  1.00 |    0.00 |          - |         - |         - |    519.26 KB |
| 'ImageSharp Webp Lossless' | Job-GOZXWU | .NET Core 2.1 | Png/Bike.png | 335.78 ms |  78.666 ms |  4.312 ms |  2.08 |    0.03 | 34000.0000 | 5000.0000 | 2000.0000 | 162727.56 KB |
|                            |            |               |              |           |            |           |       |         |            |           |           |              |
|        'Magick Webp Lossy' | Job-VRDVKW | .NET Core 3.1 | Png/Bike.png |  23.48 ms |   4.325 ms |  0.237 ms |  0.15 |    0.00 |          - |         - |         - |     67.66 KB |
|    'ImageSharp Webp Lossy' | Job-VRDVKW | .NET Core 3.1 | Png/Bike.png |  43.29 ms |  16.503 ms |  0.905 ms |  0.27 |    0.01 |  6272.7273 |  272.7273 |   90.9091 |  26284.86 KB |
|     'Magick Webp Lossless' | Job-VRDVKW | .NET Core 3.1 | Png/Bike.png | 161.81 ms |  10.693 ms |  0.586 ms |  1.00 |    0.00 |          - |         - |         - |    523.25 KB |
| 'ImageSharp Webp Lossless' | Job-VRDVKW | .NET Core 3.1 | Png/Bike.png | 323.97 ms | 235.468 ms | 12.907 ms |  2.00 |    0.08 | 34000.0000 | 5000.0000 | 2000.0000 | 162724.84 KB |
|                            |            |               |              |           |            |           |       |         |            |           |           |              |
|        'Magick Webp Lossy' | Job-ZJRLRB | .NET Core 5.0 | Png/Bike.png |  23.36 ms |   0.448 ms |  0.025 ms |  0.14 |    0.00 |          - |         - |         - |     67.66 KB |
|    'ImageSharp Webp Lossy' | Job-ZJRLRB | .NET Core 5.0 | Png/Bike.png |  40.11 ms |   2.465 ms |  0.135 ms |  0.25 |    0.00 |  6307.6923 |  230.7692 |   76.9231 |  26284.71 KB |
|     'Magick Webp Lossless' | Job-ZJRLRB | .NET Core 5.0 | Png/Bike.png | 161.55 ms |   6.662 ms |  0.365 ms |  1.00 |    0.00 |          - |         - |         - |    518.84 KB |
| 'ImageSharp Webp Lossless' | Job-ZJRLRB | .NET Core 5.0 | Png/Bike.png | 298.73 ms |  17.953 ms |  0.984 ms |  1.85 |    0.01 | 34000.0000 | 5000.0000 | 2000.0000 | 162725.13 KB |
@SebastianStehle
Copy link

Would some sponsoring help for this task? I would really like to see webp support.

@JimBobSquarePants
Copy link
Member Author

Sponsorship is always welcome but it’s really a matter of resources which can be provided by the community if willing. In the interim you can download preview builds from our MyGet feed.

@SebastianStehle
Copy link

I am using imagesharp in a server environment. I am afraid to use it in production currently as it has the potential to bring the CPU down.

I will see if I find the time (and knowledge) to help, but I guess you are much more familiar with this low level code than must other developers. I don't know whether you work as a freelancer or employee but I guess if you would have the chance to work on this for 1-2 weeks the results would be amazing.

@JimBobSquarePants
Copy link
Member Author

I am using imagesharp in a server environment. I am afraid to use it in production currently as it has the potential to bring the CPU down.

Our MyGet build is exactly the same as our NuGet ones we just don't tag them. Things are subject to change but do go through 30,000+ unit tests. We've still got #1730 to complete before we can consider shipping V2 I'm afraid so we cannot ship a stable build until then.

I don't know whether you work as a freelancer or employee but I guess if you would have the chance to work on this for 1-2 weeks the results would be amazing.

Everyone contributing to Six Labors is doing so in their spare time - There's not been enough financial support from the software industry for me to be able to work full time on the projects (hopefully one day). I personally attempt to get some work done most nights between 11pm and 2am.

@SebastianStehle
Copy link

Everyone contributing to Six Labors is doing so in their spare time - There's not been enough financial support from the software industry for me to be able to work full time on the projects (hopefully one day). I personally attempt to get some work done most nights between 11pm and 2am.

Yes, I assumed that it works like this, therefore I asked if I can support the team financially by sponsoring this task, at least partially.

@JimBobSquarePants JimBobSquarePants linked a pull request Oct 27, 2021 that will close this issue
4 tasks
@brianpopow
Copy link
Collaborator

brianpopow commented Oct 30, 2021

@SebastianStehle:

Would some sponsoring help for this task? I would really like to see webp support.

Getting some donation for doing the work here would be very welcome. I think most people really underestimate how much work it really is.
It took me almost 2 years to get webp done. Of course this was most of the time in the same mode as James mentioned: nights and weekends.

I guess if you would have the chance to work on this for 1-2 weeks the results would be amazing.

I am not sure that we can achieve that much in that short time period to be honest.
Also keep in mind that encoding webp is a CPU intense task, no matter how much optimization we do (i assume that's your usecase).

I am currently working on reducing the allocations. I have an experimental branch,
which uses 1/20 of the allocations for lossy encoding and 1/2 for lossless.

I think the first step for improving the performance should be, that someone does
extensive profiling and spots places which would benefit the most from optimization.
That would already be pretty helpful.

As James mentioned, hardware intrinsics are the way to go for performance gains.
The original libwebp source contains a lot of hardware intrinsics usages.
They can be easily spotted, because the files have the suffix sse2 or sse41.
I tried to keep the original function names as they are in the libwebp source.
I have ported already some of them, but there are plenty left.

@brianpopow
Copy link
Collaborator

brianpopow commented Nov 1, 2021

wait why is this closed? This was a mistake, I just wanted to link #1800. Same with #1799, how can this be linked without closing this issue?

@brianpopow brianpopow reopened this Nov 1, 2021
@vpetrusevici
Copy link

Hi. Nice work! Do you have plans to support webp animations?

@brianpopow
Copy link
Collaborator

Hi. Nice work! Do you have plans to support webp animations?

The goal is to support all features of webp, so yes, but animations is not high on my priority list at the moment. Performance improvements are more important now.
I would appreciate it, if someone from the community steps up and implements it.

I will create a tracking issue with the missing features.

@brianpopow brianpopow linked a pull request Nov 1, 2021 that will close this issue
5 tasks
@brianpopow
Copy link
Collaborator

Sorry for that closing and reopening again, same issue as before: just wanted to link an PR to this issue.

@brianpopow brianpopow reopened this Nov 2, 2021
@JimBobSquarePants
Copy link
Member Author

@brianpopow Rather than manually linking (which always closes when PRs are merged into the default branch) you can just use the hash syntax without closing keywords.

@brianpopow
Copy link
Collaborator

I have re-run the benchmarks again for the commit: 853c40c from 23. October, which was the commit merging webp into master.
I assume we stay with the same settings proposed in #1808.

Encode:

BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19043.1320 (21H1/May2021Update)
Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET SDK=6.0.100-rc.2.21505.57
  [Host]     : .NET 5.0.11 (5.0.1121.47308), X64 RyuJIT
  Job-MCQRNW : .NET 5.0.11 (5.0.1121.47308), X64 RyuJIT
  Job-MKUBKO : .NET Core 3.1.20 (CoreCLR 4.700.21.47003, CoreFX 4.700.21.47101), X64 RyuJIT
  Job-DQBIQV : .NET Framework 4.8 (4.8.4420.0), X64 RyuJIT

IterationCount=3  LaunchCount=1  WarmupCount=3

|                     Method |        Job |              Runtime |    TestImage |      Mean |      Error |    StdDev | Ratio | RatioSD |       Gen 0 |     Gen 1 |     Gen 2 |  Allocated |
|--------------------------- |----------- |--------------------- |------------- |----------:|-----------:|----------:|------:|--------:|------------:|----------:|----------:|-----------:|
|        'Magick Webp Lossy' | Job-BGVUUM |             .NET 5.0 | Png/Bike.png |  24.94 ms |  14.459 ms |  0.793 ms |  0.15 |    0.00 |           - |         - |         - |      67 KB |
|    'ImageSharp Webp Lossy' | Job-BGVUUM |             .NET 5.0 | Png/Bike.png | 258.31 ms | 115.015 ms |  6.304 ms |  1.56 |    0.04 | 135000.0000 |         - |         - | 552,714 KB |
|     'Magick Webp Lossless' | Job-BGVUUM |             .NET 5.0 | Png/Bike.png | 165.43 ms |   6.883 ms |  0.377 ms |  1.00 |    0.00 |           - |         - |         - |     518 KB |
| 'ImageSharp Webp Lossless' | Job-BGVUUM |             .NET 5.0 | Png/Bike.png | 342.17 ms | 304.705 ms | 16.702 ms |  2.07 |    0.11 |  34000.0000 | 5000.0000 | 2000.0000 | 161,672 KB |
|                            |            |                      |              |           |            |           |       |         |             |           |           |            |
|        'Magick Webp Lossy' | Job-HPMKSN |        .NET Core 3.1 | Png/Bike.png |  23.80 ms |   0.471 ms |  0.026 ms |  0.14 |    0.00 |           - |         - |         - |      67 KB |
|    'ImageSharp Webp Lossy' | Job-HPMKSN |        .NET Core 3.1 | Png/Bike.png | 264.16 ms |  46.068 ms |  2.525 ms |  1.60 |    0.05 | 135000.0000 |         - |         - | 552,713 KB |
|     'Magick Webp Lossless' | Job-HPMKSN |        .NET Core 3.1 | Png/Bike.png | 165.15 ms |  64.844 ms |  3.554 ms |  1.00 |    0.00 |           - |         - |         - |     520 KB |
| 'ImageSharp Webp Lossless' | Job-HPMKSN |        .NET Core 3.1 | Png/Bike.png | 321.60 ms |  26.428 ms |  1.449 ms |  1.95 |    0.04 |  34000.0000 | 5000.0000 | 2000.0000 | 161,668 KB |
|                            |            |                      |              |           |            |           |       |         |             |           |           |            |
|        'Magick Webp Lossy' | Job-BOAJTS | .NET Framework 4.7.2 | Png/Bike.png |  23.68 ms |   3.686 ms |  0.202 ms |  0.14 |    0.00 |           - |         - |         - |      68 KB |
|    'ImageSharp Webp Lossy' | Job-BOAJTS | .NET Framework 4.7.2 | Png/Bike.png | 385.60 ms |  48.371 ms |  2.651 ms |  2.35 |    0.02 | 135000.0000 |         - |         - | 554,351 KB |
|     'Magick Webp Lossless' | Job-BOAJTS | .NET Framework 4.7.2 | Png/Bike.png | 164.32 ms |   8.850 ms |  0.485 ms |  1.00 |    0.00 |           - |         - |         - |     518 KB |
| 'ImageSharp Webp Lossless' | Job-BOAJTS | .NET Framework 4.7.2 | Png/Bike.png | 390.85 ms |  30.365 ms |  1.664 ms |  2.38 |    0.00 |  34000.0000 | 5000.0000 | 2000.0000 | 162,117 KB |

Decode:

|                     Method |        Job |              Runtime |        TestImageLossy |        TestImageLossless |       Mean |     Error |   StdDev |     Gen 0 |     Gen 1 |    Gen 2 | Allocated |
|--------------------------- |----------- |--------------------- |---------------------- |------------------------- |-----------:|----------:|---------:|----------:|----------:|---------:|----------:|
|        'Magick Lossy Webp' | Job-EJYKMG |             .NET 5.0 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   105.6 ms |   0.98 ms |  0.05 ms |         - |         - |        - |     25 KB |
|    'ImageSharp Lossy Webp' | Job-EJYKMG |             .NET 5.0 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   669.9 ms | 280.92 ms | 15.40 ms |         - |         - |        - |  2,770 KB |
|     'Magick Lossless Webp' | Job-EJYKMG |             .NET 5.0 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   107.8 ms |  33.00 ms |  1.81 ms |         - |         - |        - |     18 KB |
| 'ImageSharp Lossless Webp' | Job-EJYKMG |             .NET 5.0 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   313.9 ms |  69.97 ms |  3.84 ms | 5000.0000 | 1500.0000 | 500.0000 | 22,862 KB |
|        'Magick Lossy Webp' | Job-BMMSCS |        .NET Core 3.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   106.0 ms |   6.18 ms |  0.34 ms |         - |         - |        - |     25 KB |
|    'ImageSharp Lossy Webp' | Job-BMMSCS |        .NET Core 3.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   759.4 ms |  91.77 ms |  5.03 ms |         - |         - |        - |  2,769 KB |
|     'Magick Lossless Webp' | Job-BMMSCS |        .NET Core 3.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   107.9 ms |  16.58 ms |  0.91 ms |         - |         - |        - |     15 KB |
| 'ImageSharp Lossless Webp' | Job-BMMSCS |        .NET Core 3.1 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   491.0 ms |  47.61 ms |  2.61 ms | 4000.0000 | 1000.0000 |        - | 22,860 KB |
|        'Magick Lossy Webp' | Job-HVJOCM | .NET Framework 4.7.2 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   107.2 ms |  14.95 ms |  0.82 ms |         - |         - |        - |     32 KB |
|    'ImageSharp Lossy Webp' | Job-HVJOCM | .NET Framework 4.7.2 | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 1,135.7 ms | 117.43 ms |  6.44 ms |         - |         - |        - |  2,780 KB |
|     'Magick Lossless Webp' | Job-HVJOCM | .NET Framework 4.7.2 | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   107.2 ms |  17.90 ms |  0.98 ms |         - |         - |        - |     18 KB |
| 'ImageSharp Lossless Webp' | Job-HVJOCM | .NET Framework 4.7.2 | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 1,773.9 ms | 169.72 ms |  9.30 ms | 4000.0000 | 1000.0000 |        - | 30,557 KB |

The biggest deviation to the original benchmarks from this thread is lossy encoding. The good news is though, I made good progress in improving that (see the open PR and there is more potential there).

@brianpopow
Copy link
Collaborator

brianpopow commented Nov 10, 2021

I wanted to share some updates on the improvements for webp.
Benchmarks from the current master branch:

Encode:

BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19043.1320 (21H1/May2021Update)
Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET SDK=6.0.100
  [Host]     : .NET 5.0.12 (5.0.1221.52207), X64 RyuJIT
  Job-EIDTBY : .NET 5.0.12 (5.0.1221.52207), X64 RyuJIT
  Job-CPHHDA : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-UGXIBH : .NET Framework 4.8 (4.8.4420.0), X64 RyuJIT

IterationCount=3  LaunchCount=1  WarmupCount=3

|                     Method |        Job |              Runtime |             Arguments |    TestImage |      Mean |     Error |   StdDev | Ratio |     Gen 0 |     Gen 1 |     Gen 2 | Allocated |
|--------------------------- |----------- |--------------------- |---------------------- |------------- |----------:|----------:|---------:|------:|----------:|----------:|----------:|----------:|
|        'Magick Webp Lossy' | Job-EIDTBY |             .NET 5.0 | /p:DebugType=portable | Png/Bike.png |  23.25 ms |  0.356 ms | 0.020 ms |  0.14 |         - |         - |         - |     67 KB |
|    'ImageSharp Webp Lossy' | Job-EIDTBY |             .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 133.63 ms |  7.292 ms | 0.400 ms |  0.83 | 4000.0000 |  250.0000 |         - | 16,648 KB |
|     'Magick Webp Lossless' | Job-EIDTBY |             .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 160.69 ms | 14.893 ms | 0.816 ms |  1.00 |         - |         - |         - |    518 KB |
| 'ImageSharp Webp Lossless' | Job-EIDTBY |             .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 288.44 ms |  6.384 ms | 0.350 ms |  1.80 | 8000.0000 | 3000.0000 |  500.0000 | 61,553 KB |
|                            |            |                      |                       |              |           |           |          |       |           |           |           |           |
|        'Magick Webp Lossy' | Job-CPHHDA |        .NET Core 3.1 |               Default | Png/Bike.png |  23.24 ms |  2.965 ms | 0.163 ms |  0.15 |         - |         - |         - |     67 KB |
|    'ImageSharp Webp Lossy' | Job-CPHHDA |        .NET Core 3.1 |               Default | Png/Bike.png | 147.15 ms |  5.399 ms | 0.296 ms |  0.92 | 4000.0000 |         - |         - | 16,648 KB |
|     'Magick Webp Lossless' | Job-CPHHDA |        .NET Core 3.1 |               Default | Png/Bike.png | 159.59 ms |  4.746 ms | 0.260 ms |  1.00 |         - |         - |         - |    517 KB |
| 'ImageSharp Webp Lossless' | Job-CPHHDA |        .NET Core 3.1 |               Default | Png/Bike.png | 310.73 ms | 20.905 ms | 1.146 ms |  1.95 | 8000.0000 | 3000.0000 | 1000.0000 | 61,555 KB |
|                            |            |                      |                       |              |           |           |          |       |           |           |           |           |
|        'Magick Webp Lossy' | Job-UGXIBH | .NET Framework 4.7.2 |               Default | Png/Bike.png |  23.40 ms |  0.566 ms | 0.031 ms |  0.15 |         - |         - |         - |     68 KB |
|    'ImageSharp Webp Lossy' | Job-UGXIBH | .NET Framework 4.7.2 |               Default | Png/Bike.png | 439.02 ms | 35.185 ms | 1.929 ms |  2.74 | 4000.0000 |         - |         - | 16,752 KB |
|     'Magick Webp Lossless' | Job-UGXIBH | .NET Framework 4.7.2 |               Default | Png/Bike.png | 159.98 ms |  9.306 ms | 0.510 ms |  1.00 |         - |         - |         - |    518 KB |
| 'ImageSharp Webp Lossless' | Job-UGXIBH | .NET Framework 4.7.2 |               Default | Png/Bike.png | 430.20 ms | 35.086 ms | 1.923 ms |  2.69 | 8000.0000 | 3000.0000 | 1000.0000 | 61,698 KB |

Decode:

IterationCount=3  LaunchCount=1  WarmupCount=3

|                     Method |        Job |              Runtime |             Arguments |        TestImageLossy |        TestImageLossless |       Mean |    Error |  StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------------- |----------- |--------------------- |---------------------- |---------------------- |------------------------- |-----------:|---------:|--------:|------:|------:|------:|----------:|
|        'Magick Lossy Webp' | Job-JFZHJM |             .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   107.2 ms | 22.09 ms | 1.21 ms |     - |     - |     - |     25 KB |
|    'ImageSharp Lossy Webp' | Job-JFZHJM |             .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   275.7 ms |  9.75 ms | 0.53 ms |     - |     - |     - |  1,703 KB |
|     'Magick Lossless Webp' | Job-JFZHJM |             .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   106.8 ms |  8.18 ms | 0.45 ms |     - |     - |     - |     16 KB |
| 'ImageSharp Lossless Webp' | Job-JFZHJM |             .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   261.8 ms | 56.62 ms | 3.10 ms |     - |     - |     - |  2,051 KB |
|        'Magick Lossy Webp' | Job-LPYOLC |        .NET Core 3.1 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   107.6 ms |  6.76 ms | 0.37 ms |     - |     - |     - |     25 KB |
|    'ImageSharp Lossy Webp' | Job-LPYOLC |        .NET Core 3.1 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   293.4 ms | 10.52 ms | 0.58 ms |     - |     - |     - |  1,702 KB |
|     'Magick Lossless Webp' | Job-LPYOLC |        .NET Core 3.1 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   106.6 ms | 13.72 ms | 0.75 ms |     - |     - |     - |     15 KB |
| 'ImageSharp Lossless Webp' | Job-LPYOLC |        .NET Core 3.1 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   437.4 ms | 58.98 ms | 3.23 ms |     - |     - |     - |  2,049 KB |
|        'Magick Lossy Webp' | Job-GQRTJY | .NET Framework 4.7.2 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   106.8 ms |  8.77 ms | 0.48 ms |     - |     - |     - |     32 KB |
|    'ImageSharp Lossy Webp' | Job-GQRTJY | .NET Framework 4.7.2 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   565.5 ms | 23.85 ms | 1.31 ms |     - |     - |     - |  1,708 KB |
|     'Magick Lossless Webp' | Job-GQRTJY | .NET Framework 4.7.2 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp |   106.7 ms |  5.65 ms | 0.31 ms |     - |     - |     - |     18 KB |
| 'ImageSharp Lossless Webp' | Job-GQRTJY | .NET Framework 4.7.2 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 1,768.8 ms | 94.91 ms | 5.20 ms |     - |     - |     - |  9,689 KB |

Notable mentions:

  • Lossy encoding is down from 258 ms to 134 ms
  • Lossy decoding is down from 669 ms to 276 ms
  • Memory allocations is much better for encoding.

Notes:

  • Lossy encoding can be further improved with hardware intrinsics (ITransform, FTransform are main candidates).
  • Lossy decoding takes alot of time converting data from YUV (30% time). This can also profit alot from hardware intrinsics.
    Its pretty complicated though. I am not sure if i can port that over from libwebp. Maybe someone with more experience SSE2/SSE4 is needed here.
  • While the lower memory allocations is nice, it was mainly achieved by reusing objects instead of creating them. This comes at the cost of having them
    cleared before using them. From profiling i would roughly guess this costs 5% performance. I still think its worth it.

@CarlosTorrecillas
Copy link

Is that already available in the latest package? If so, I somehow get the UnknownImageFormatException and WEBP is still not listed there. Perhaps I'm doing something wrong but I'm not able to load a WEBP image just yet.

@JimBobSquarePants
Copy link
Member Author

You need to use the MyGet feed. We’ll be shipping it to NuGet with 2.0

@brianpopow
Copy link
Collaborator

Some update in the current status.
Here are the benchmark results from the current master branch:

Encode:

|                     Method |        Job |              Runtime |             Arguments |    TestImage |      Mean |     Error |   StdDev | Ratio | RatioSD |     Gen 0 |     Gen 1 |     Gen 2 | Allocated |
|--------------------------- |----------- |--------------------- |---------------------- |------------- |----------:|----------:|---------:|------:|--------:|----------:|----------:|----------:|----------:|
|        'Magick Webp Lossy' | Job-OLZPMB |             .NET 5.0 | /p:DebugType=portable | Png/Bike.png |  23.25 ms |  0.128 ms | 0.076 ms |  0.15 |    0.00 |         - |         - |         - |     67 KB |
|    'ImageSharp Webp Lossy' | Job-OLZPMB |             .NET 5.0 | /p:DebugType=portable | Png/Bike.png |  94.60 ms |  0.788 ms | 0.469 ms |  0.59 |    0.00 | 4166.6667 |  166.6667 |         - | 17,588 KB |
|     'Magick Webp Lossless' | Job-OLZPMB |             .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 160.34 ms |  0.974 ms | 0.579 ms |  1.00 |    0.00 |         - |         - |         - |    518 KB |
| 'ImageSharp Webp Lossless' | Job-OLZPMB |             .NET 5.0 | /p:DebugType=portable | Png/Bike.png | 272.89 ms | 15.251 ms | 9.076 ms |  1.70 |    0.06 | 7500.0000 | 3500.0000 | 1500.0000 | 46,979 KB |
|                            |            |                      |                       |              |           |           |          |       |         |           |           |           |           |
|        'Magick Webp Lossy' | Job-MHFYZF |        .NET Core 3.1 |               Default | Png/Bike.png |  23.34 ms |  0.303 ms | 0.180 ms |  0.15 |    0.00 |         - |         - |         - |     67 KB |
|    'ImageSharp Webp Lossy' | Job-MHFYZF |        .NET Core 3.1 |               Default | Png/Bike.png | 110.29 ms |  2.185 ms | 1.300 ms |  0.69 |    0.01 | 4000.0000 |         - |         - | 17,588 KB |
|     'Magick Webp Lossless' | Job-MHFYZF |        .NET Core 3.1 |               Default | Png/Bike.png | 159.52 ms |  0.650 ms | 0.387 ms |  1.00 |    0.00 |         - |         - |         - |    517 KB |
| 'ImageSharp Webp Lossless' | Job-MHFYZF |        .NET Core 3.1 |               Default | Png/Bike.png | 277.31 ms |  7.406 ms | 4.407 ms |  1.74 |    0.03 | 8000.0000 | 4000.0000 | 2000.0000 | 46,981 KB |
|                            |            |                      |                       |              |           |           |          |       |         |           |           |           |           |
|        'Magick Webp Lossy' | Job-PATHPQ | .NET Framework 4.7.2 |               Default | Png/Bike.png |  23.31 ms |  0.237 ms | 0.141 ms |  0.15 |    0.00 |         - |         - |         - |     68 KB |
|    'ImageSharp Webp Lossy' | Job-PATHPQ | .NET Framework 4.7.2 |               Default | Png/Bike.png | 431.98 ms |  2.513 ms | 1.496 ms |  2.71 |    0.01 | 4000.0000 |         - |         - | 17,642 KB |
|     'Magick Webp Lossless' | Job-PATHPQ | .NET Framework 4.7.2 |               Default | Png/Bike.png | 159.66 ms |  0.931 ms | 0.554 ms |  1.00 |    0.00 |         - |         - |         - |    518 KB |
| 'ImageSharp Webp Lossless' | Job-PATHPQ | .NET Framework 4.7.2 |               Default | Png/Bike.png | 451.57 ms |  1.993 ms | 1.186 ms |  2.83 |    0.01 | 8000.0000 | 4000.0000 | 2000.0000 | 47,107 KB |

Decode:

|                     Method |        Job |              Runtime |             Arguments |        TestImageLossy |        TestImageLossless |     Mean |   Error |  StdDev |     Gen 0 |     Gen 1 |     Gen 2 | Allocated |
|--------------------------- |----------- |--------------------- |---------------------- |---------------------- |------------------------- |---------:|--------:|--------:|----------:|----------:|----------:|----------:|
|        'Magick Lossy Webp' | Job-EBSHHU |             .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 105.6 ms | 2.48 ms | 1.48 ms |         - |         - |         - |     16 KB |
|    'ImageSharp Lossy Webp' | Job-EBSHHU |             .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 194.0 ms | 2.80 ms | 1.67 ms | 2000.0000 | 2000.0000 | 2000.0000 |  1,765 KB |
|     'Magick Lossless Webp' | Job-EBSHHU |             .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 105.4 ms | 1.67 ms | 0.99 ms |         - |         - |         - |     16 KB |
| 'ImageSharp Lossless Webp' | Job-EBSHHU |             .NET 5.0 | /p:DebugType=portable | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 238.9 ms | 1.35 ms | 0.80 ms | 2000.0000 | 2000.0000 | 2000.0000 |  1,754 KB |
|        'Magick Lossy Webp' | Job-ACMKPP |        .NET Core 3.1 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 106.1 ms | 2.55 ms | 1.51 ms |         - |         - |         - |     15 KB |
|    'ImageSharp Lossy Webp' | Job-ACMKPP |        .NET Core 3.1 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 204.5 ms | 2.10 ms | 1.25 ms | 1000.0000 |         - |         - |  1,755 KB |
|     'Magick Lossless Webp' | Job-ACMKPP |        .NET Core 3.1 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 105.8 ms | 0.65 ms | 0.39 ms |         - |         - |         - |     15 KB |
| 'ImageSharp Lossless Webp' | Job-ACMKPP |        .NET Core 3.1 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 241.2 ms | 4.31 ms | 2.57 ms | 1000.0000 |         - |         - |  1,736 KB |
|        'Magick Lossy Webp' | Job-POKFWI | .NET Framework 4.7.2 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 105.9 ms | 2.03 ms | 1.21 ms |         - |         - |         - |     18 KB |
|    'ImageSharp Lossy Webp' | Job-POKFWI | .NET Framework 4.7.2 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 555.2 ms | 5.17 ms | 3.08 ms | 1000.0000 |         - |         - |  1,772 KB |
|     'Magick Lossless Webp' | Job-POKFWI | .NET Framework 4.7.2 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 105.8 ms | 1.30 ms | 0.78 ms |         - |         - |         - |     18 KB |
| 'ImageSharp Lossless Webp' | Job-POKFWI | .NET Framework 4.7.2 |               Default | Webp/earth_lossy.webp | Webp/earth_lossless.webp | 548.0 ms | 5.33 ms | 3.17 ms | 1000.0000 |         - |         - |  9,377 KB |

Notable mentions:

  • Lossy encoding is down from 133.63 ms to 94.60 ms
  • Lossy decoding is down from 276 ms to 194.0 ms
  • Lossless decoding is down from 262 ms to 238.9 ms

@antonfirsov
Copy link
Member

antonfirsov commented Feb 6, 2022

Is this general issue still valuable? = meaning shall we roll it to "Future", or close it?

@brianpopow
Copy link
Collaborator

Since I do not see any big opportunities anymore to improve the performance further, I would vote for closing the issue.

@JimBobSquarePants
Copy link
Member Author

Yeah let's close it for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment