Skip to content

Speed. Hot nasty bad-ass speed! #8

Closed

Description

@JimBobSquarePants

From @JimBobSquarePants on March 16, 2016 9:44

We've got a pretty good feature set for a V1 release.

Now we need to make it fast.

Things to look at:

  • Reducing array allocation ArrayPool, Slice<T>
  • Unsafe code where applicable
  • Moar SIMD
  • Algorithmic tightening
  • Reduce pixel looping
  • Other things

For benchmarking we can use BenchMarkDotNet now that the prerelease supports CoreFX

i-wanna-go-fast-ricky-bobby

Add your thoughts below.

Copied from original issue: JimBobSquarePants/ImageProcessor#347

Activity

  1. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    From @mavenius on March 16, 2016 10:11

    Might want to check out Scientist.Net for comparing performance and
    consistency between old and optimized branches. It's fairly new, but I've
    read good things.

    Thank you,

    Mark Avenius
    On Mar 16, 2016 5:44 AM, "James Jackson-South" [email protected]
    wrote:

    We've got a pretty good feature set
    https://github.com/JimBobSquarePants/ImageProcessor#what-works-so-far-what-is-planned
    for a V1 release.

    Now we need to make it fast.

    Things to look at:

    For benchmarking we can use BenchMarkDotNet
    https://github.com/PerfDotNet/BenchmarkDotNet now that the prerelease
    supports CoreFX

    [image: i-wanna-go-fast-ricky-bobby]
    https://cloud.githubusercontent.com/assets/385879/13807908/b9e66592-ebb7-11e5-8c21-c7596ff3264e.gif

    Add your thoughts below.

    —
    You are receiving this because you are subscribed to this thread.
    Reply to this email directly or view it on GitHub
    https://github.com/JimBobSquarePants/ImageProcessor/issues/347

  2. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    From @rold2007 on March 17, 2016 8:35

    The first task is obviously to identify the slow parts. I have never used BenchMarkDotNet but I heard about it recently, I guess this is a good opportunity to try it!
    Maybe a new set of tests (performance) should be created for this? I think the benchmark should be done on small, medium, large and huge images (32x32, 512x512, 1024x1024, 10Kx10K ?).

    I never heard of Scientist.Net before but maybe it could be used to compare even with other similar libraries (AForge.Net, etc.) ?

    I'll do some tests with BenchMarkDotNet to see if it does the job, and report back here.

  3. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    That would be great if you could. I had a read through the instructions but I am terrible when it comes to following them.

  4. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    From @rold2007 on March 23, 2016 8:9

    I haven't been able to use BenchmarkDotNet with DNX so far, even on the most basic code. I'll report my issues to the BenchmarkDotNet team and see what can be done. Sorry about the delay.

  5. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    @rold2007 No worries, thanks for trying. I'm sure someone there will be happy to give us pointers.

  6. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    From @rold2007 on March 23, 2016 8:50

    @JimBobSquarePants It is now resolved. I'll be quite busy until next week but I'll continue with this asap.

  7. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    @rold2007 Awesome! Here's hoping we can get some great info to find bottlenecks.

  8. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    From @voidstar69 on May 1, 2016 9:4

    I have tried installing BenchmarkDotNet into ImageProcessorCore.Tests via Nuget, both the official release and the prerelease. I cannot use either - the prerelease appears to need the NETStandard libraries, and the official release appears to not support DNXCore 5.0.

    @JimBobSquarePants @rold2007 Have you managed to get BenchmarkDotNet working to benchmark an existing unit test in ImageProcessorCore?

  9. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    @voidstar69 Truth be told I've not tried, I've only used it outside for testing. I'll have a look as soon as I can.

    It's probably best, however, to put the benchmark tests into a separate NET 4.6 console project so that I can do direct comparisons against System.Drawing.

  10. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    @voidstar69 Just added it to the repo now 😄

  11. JimBobSquarePants commented on Oct 30, 2016

    @JimBobSquarePants
    MemberAuthor

    From @voidstar69 on May 19, 2016 21:12

    @JimBobSquarePants Thanks for adding BenchmarkDotNet to the repo, looks like it will be very useful to compare against System.Drawing.

    I have started off by looking at the performance of Crop. On my laptop the System.Drawing version take about 800us, while the Core version takes about 1380us.
    I tried a minor optimisation in Crop.cs, changing this:

    for (int x = startX; x < endX; x++)
    {
        target[x, y] = source[x + sourceX, y + sourceY];
    }
    

    to this:

    Array.Copy(source.Pixels, (((y + sourceY) * source.Width) + (startX + sourceX)) * 4,
        target.Pixels, ((y * target.Width) + startX) * 4,
        (endX - startX) * 4);
    

    This appears to speed up the crop from 1380us to about 1330us. A small but significant improvement. You should test for a similar performance improvement on your PC, in case this is specific to my PC.

    One downside is that the array index calculation is now exposed in Crop.cs, whereas before it was hidden away in ImageBase.this[].
    Some other things I noticed:

    • If the target rectangle (top-left) x and y are non-zero, I believe the crop will be incorrect because the source coordinates are offset by this target x and y.
    • ImageBase pins the memory of pixelArray, but never calls GCHandle.Free to unpin this memory. Additionally keeping lots of memory blocks pinned for long periods will degrade the garbage collector. As long as ImageBase objects are constructed and then disposed not long later, this probably is not a problem. The alternative would be to pin this memory on-demand, and unpin it at a convenient time, i.e. at the end of each image operation.
  12. 40 remaining items

  13. JimBobSquarePants commented on Nov 10, 2016

    @JimBobSquarePants
    MemberAuthor

    Could you PR with what you have please and I'll have a tinker from there.

  14. boguscoder commented on Nov 10, 2016

    @boguscoder

    As an initial exercise I'll try to PR scanline buffer reuse in PNG decoder filters, its seems there are redundant allocations hapenning there

  15. JimBobSquarePants commented on Nov 11, 2016

    @JimBobSquarePants
    MemberAuthor

    @boguscoder Thanks!

  16. antonfirsov commented on Nov 11, 2016

    @antonfirsov
    Member

    Just sent a PR, but conflicted :( I'm not sure if it's worth to merge in it's current form.

    Currently I'm experimenting with SIMD IDCT implementations. Trying to port this:
    https://github.com/norishigefukushima/dct_simd

  17. antonfirsov commented on Nov 14, 2016

    @antonfirsov
    Member

    I have good news with JpegDecoder!
    DecodeJpeg.JpegCore() (with Calliphora.jpg) on my machine:

    Host Process Environment Information:
    BenchmarkDotNet-Dev.Core=v0.9.9.0
    OS=Microsoft Windows NT 6.1.7601 Service Pack 1
    Processor=Intel(R) Core(TM) i7-4810MQ CPU 2.80GHz, ProcessorCount=8
    Frequency=2728115 ticks, Resolution=366.5535 ns, Timer=TSC
    CLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
    GC=Concurrent Workstation
    JitModules=clrjit-v4.6.1076.0
    
    Type=DecodeJpeg  Mode=Throughput  
    

    Current master branch:

    Method Median StdDev Gen 0 Gen 1 Gen 2 Bytes Allocated/Op
    ImageSharp Jpeg 48.7835 ms 0.4524 ms 724.00 - 144.00 6,063,638.46

    My (experimental) master with SIMD optimizations:

    Method Median StdDev Gen 0 Gen 1 Gen 2 Bytes Allocated/Op
    ImageSharp Jpeg 31.8167 ms 0.5176 ms - - 130.00 1,979,222.11

    Are you interested to pull this in? :) There are lots of additional classes & test cases this time.

  18. JimBobSquarePants commented on Nov 14, 2016

    @JimBobSquarePants
    MemberAuthor

    Awwwwwww yeaaaaaaaaah!

    That's a brilliant improvement!

    Definitely looking to pull the changes in though I'll need you to strip your PR down to the minimum changes please first. You've got 28 files changed so far, some of which are completely unrelated (png filters)

  19. olivif commented on Dec 17, 2016

    @olivif
    Contributor

    @JimBobSquarePants I'd like to help out on perf investigations, any pointers on where I can start/what to focus on? Should we start with some documentation on bechmarking in ImageSharp and an overview of the areas and if anyone is actively looking into them? 😄

    Btw, I ran benchmark.cmd on a few of the profiles, but it's a bit difficult to go from there.

    Also, I searched a bit on benchmarking with xUnit, found NBench and xUnit Perf, not sure if anyone has already looked into these.

  20. antonfirsov commented on Dec 18, 2016

    @antonfirsov
    Member

    @olivif benchmarks are very good starters, but you don't get too far in performance analysis & optimization without a profiler. There is a built-in profiler in VS, but it's quite slow, it's better to grab JetBrains dotTrace if possible.

    And here is the tricky part:
    None of these tools worked for me with a .NET core project. My workaround was to define a temporal 4.6 project, and reference ImageSharp as a dll (bin\Release\net45\ImageSharp.dll).

    If the infrastructure is ready, it's really easy to profile .NET 4.6 code with dotTrace or with VS profiler. Finding and eliminating bottlenecks is an exciting game, think of a detective movie! :)

  21. olivif commented on Dec 18, 2016

    @olivif
    Contributor

    Ahh I think I see now. Benchmarking will give you the overall numbers and help you compare against a baseline (be it a different lib or an earlier version of your lib), whereas the profiler will actually tell you what is slow (or provide enough info on all the parts so you can hunt yourself).

    Hmm I'm surprised the VS profiler didn't work with a core project, maybe the tooling for core is not all fully out there.

  22. JimBobSquarePants commented on Nov 24, 2018

    @JimBobSquarePants
    MemberAuthor

    Closing this as we have come a long way performance wise and it does no good to keep this issue open.

  23. added a commit that references this issue on Nov 27, 2019
  24. added a commit that references this issue on Jan 18, 2020
  25. added 2 commits that reference this issue on Feb 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions