Giter Club home page Giter Club logo

Comments (60)

antonfirsov avatar antonfirsov commented on May 22, 2024 1

Hi, I "ported" your projects to .NET 4.6 & managed to play with DotPeek.
I think the main issue is having classes where using structs would be a much better choice. The code needs a LOT of systematic refactor. I would be happy to contribute, but I also want to avoid duplicate work. Any advices? (What to touch/not touch?)

from imagesharp.

antonfirsov avatar antonfirsov commented on May 22, 2024 1

Yes, its the jpeg :)
I will start with a few small changes this week to proof my ideas first.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024 1

Excellent stuff! I got memory usage down on the encoder but the decoder is a mess!

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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?

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@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.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@voidstar69 Just added it to the repo now 😄

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

Hi @voidstar69 Thanks for having a look at this. Have you go the latest version of the codebase?

I have a test against Crop here which resulted in Crop taking half the time of System.Drawing on my machine. Admittedly results will vary depending on how many cores you have (Also make sure you are running in release mode?)

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.

I'll need to add a unit test to double check against the target. The current code was submitted as a bug fix.

ImageBase pins the memory of pixelArray, but never calls GCHandle.Free to unpin this memory.

I do call GCHandle.Free() I think you must have just missed it. Image now implements IDisposable and the method is called when disposing of the instance.

What I do need to know is whether I should be checking and calling Free() when using SetPixels() or whether simply updating the handle is sufficient.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @mattwarren on May 20, 2016 8:53

Hi, I'm one of the developers for BenchmarkDotNet and it's cool to see you using it, I added you to our list.

BTW there's a Diagnostics Nuget package that might be help you out. It gives you information about memory allocations and method inlining that might be useful to have in your benchmarks

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

Hi @mattwarren thanks for dropping by.

That package sounds like it would definitely be very useful thank you! Happy to have made your list. 😄

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @voidstar69 on May 21, 2016 18:17

Hi @JimBobSquarePants, I got the latest code from the Core branch before I tried my changes, and I did test them in Release mode.

That is the same test that I ran on my machine, but the performance profile is different for me (i5 CPU, 4 logical processors). What were your timings in us (microseconds)? If you try out my Array.Copy code, does it make Crop faster or slower on your machine?

You are right about GCHandle.Free - I was searching the file for this exact text, rather than pixelHandles.Free.

As for SetPixels() I suspect that if Free() is not called before calling GCHandle.Alloc() again, the previous memory block will remain pinned in memory. So Free() should be called if pixelsHandle is not null.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@voidstar69 I've taken your advise on board re SetPixels() as that seems like a logical interpretation of expected behaviour. The code will be in the next push.

As for timings. Here's the timing on my main laptop. It's got waaay less cores than my work machine which has twelve. On that machine ImageProcessorCore is 0.46 when scaled which is good and quick.

BenchmarkDotNet=v0.9.6.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Processor 5Y70 CPU @ 1.10GHz, ProcessorCount=4
Frequency=1266597 ticks, Resolution=789.5171 ns, Timer=TSC
HostCLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
JitModules=clrjit-v4.6.1080.0

Type=Crop  Mode=Throughput

                  Method |    Median |    StdDev | Scaled |
------------------------ |---------- |---------- |------- |
     System.Drawing Crop | 1.0361 ms | 0.1025 ms |   1.00 |
 ImageProcessorCore Crop | 1.7126 ms | 0.0806 ms |   1.65 |

Using your code addition

BenchmarkDotNet=v0.9.6.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Processor 5Y70 CPU @ 1.10GHz, ProcessorCount=4
Frequency=1266597 ticks, Resolution=789.5171 ns, Timer=TSC
HostCLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
JitModules=clrjit-v4.6.1080.0

Type=Crop  Mode=Throughput

                  Method |        Median |     StdDev | Scaled |
------------------------ |-------------- |----------- |------- |
     System.Drawing Crop |   847.2536 us | 26.1538 us |   1.00 |
 ImageProcessorCore Crop | 1,397.4700 us | 59.5903 us |   1.65 |

I ran the tests a few times and the difference was negligible so I don't want to change the code yet (big emphasis on the yet)

You have got me thinking though which is awesome. IImageBase should have a method to set a row in one move. There must be a way we can copy an entire row in one in an unsafe context to maximize performance. So if you, I or anyone reading wants to set aside the time to tests and benchmark an approach that would be excellent.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

One thing that we should definitely have a look at which affects all processes is how I manage threading.

in ParallelImageProcessor.cs I split up jobs into tasks

https://github.com/JimBobSquarePants/ImageProcessor/blob/0300f596b0c59a7187ba7ce0efcf0d9e98932a4f/src/ImageProcessorCore/ParallelImageProcessor.cs#L45

I determine the number of tasks based on multiplying the processor count by 2 which I will freely admit was a number plucked out from the air.

I would love to have someone review this process to see if I am falling short somewhere and taking the wrong approach.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

Well ain't this nice... 😄

// * Summary *

BenchmarkDotNet=v0.9.7.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Xeon(R) CPU E5-1650 0 3.20GHz, ProcessorCount=12
Frequency=3117489 ticks, Resolution=320.7710 ns, Timer=TSC
HostCLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
JitModules=clrjit-v4.6.1063.1

Type=Resize  Mode=Throughput

                    Method |    Median |    StdDev | Scaled |
-------------------------- |---------- |---------- |------- |
     System.Drawing Resize | 2.6414 ms | 0.0395 ms |   1.00 |
 ImageProcessorCore Resize | 1.7930 ms | 0.0773 ms |   0.68 |

// ***** BenchmarkRunner: End *****

Global total time: 00:00:30 (30.42 sec)

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @alexmbaker on June 7, 2016 9:10

You may find something useful in https://github.com/Microsoft/Microsoft.IO.RecyclableMemoryStream

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@mattwarren Just to follow up on your package recommendation. My project threw a wobbler citing a missing .dll when I tried to use the diagnostic package. Are there known issues on .NET Core or am I doing something daft?

https://github.com/JimBobSquarePants/ImageProcessor/blob/0c0c868ae14312f4ab5d7bc78a0c8e118d10f404/tests/ImageProcessorCore.Benchmarks/Program.cs#L31

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @mattwarren on June 29, 2016 8:40

Have you added the BenchmarkDotNet.Diagnostics.Windows package to your project as well?

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@mattwarren Yeah I do. Here's the message. I'll open an issue if you like?

Error loading BenchmarkDotNet.Diagnostics.Windows.dll: FileNotFoundException - Could not load file or assembly 'file:///C:\github\ImageProcessor\tests\ImageProcessorCore.Benchmarks\BenchmarkDotNet.Diagnostics.Windows.dll' or one of its dependencies. The system cannot find the file specified.

Unhandled Exception: System.InvalidOperationException: memorydiagnoser is an unrecognised Diagnoser
   at BenchmarkDotNet.Configs.ConfigParser.ParseDiagnosers(String value)
   at BenchmarkDotNet.Configs.ConfigParser.<>c.<.cctor>b__18_9(ManualConfig config, String value)
   at BenchmarkDotNet.Configs.ConfigParser.Parse(String[] args)
   at BenchmarkDotNet.Running.BenchmarkSwitcher.RunBenchmarks(String[] args)
   at ImageProcessorCore.Benchmarks.Program.Main(String[] args) in C:\github\ImageProcessor\tests\ImageProcessorCore.Benchmarks\Program.cs:line 35
Press any key to continue . . .

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @danijel-peric on July 1, 2016 22:9

my test for resize, used jpeg image 960x540 and resized it to 320x240, code

using (MemoryStream inStream = new MemoryStream(Image))
using (MemoryStream outStream = new MemoryStream())
using (ImageFactory imageFactory = new ImageFactory())
    imageFactory.Load(inStream)
                .Resize(new Size(320, 240))
                .Format(new JpegFormat { Quality = 50 })
                .Save(outStream);

if you want code used for Windows.Media.Imaging or System.Drawing.Graphics let me know

note i tested your library because i was trying to find fast resize library which doesn't use much cpu, from this test Windows.Media.Imaging was using 15% cpu on my machine, your resize used 40-50%
Parallel is the problem, but very nice library, thanks


BenchmarkDotNet=v0.9.7.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i7-4790 CPU 3.60GHz, ProcessorCount=8
Frequency=3515620 ticks, Resolution=284.4448 ns, Timer=ACPI
HostCLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
JitModules=clrjit-v4.6.1055.0
Type=ImageResizeBenchmark  Mode=Throughput  
MethodMedianStdDev
WindowsMediaImaging2.1111 ms0.1916 ms
SystemDrawingGraphics5.3590 ms0.5527 ms
ImageProcessor23.0896 ms0.4548 ms

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

Hi @danijel-peric

Thanks for your info but you're actually benchmarking the wrong codebase. This issue has been raised specifically for ImageProcessor.Core.

There's going to be some overhead using the legacy ImageFactory code as I copy the image over to a new pixel format when loading. If you were going to benchmark you should be benchmarking the Resize method only. There is absolutely no parallel code used in the example workflow you have provided.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @rold2007 on July 3, 2016 1:0

@danijel-peric : Also, make sure you compare apples with apples. Resize methods like nearest neighbor and bicubic have a very different speed, and quality. But I'm not even sure what ImageProcessor is using.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @danijel-peric on July 3, 2016 7:25

:), it looks i have tested with old ImageFactory which was on https://www.nuget.org/packages/ImageProcessor

sorry, will do another test with ImageProcessor.Core, so in order to get it i need to download source? and build it, do you have binary files somewhere for download?

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

Yeah, they're on MyGet, you can see it in the readme. There's benchmark tests in the source though.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @mattwarren on July 7, 2016 16:59

@JimBobSquarePants I'm sorry I never replied to your previous comment.

Yes if you could open an issue that would be great, otherwise I'll forget about this problem!!

Also if you can point me so a (simple) test project that repos the issue that would also be helpful.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @Grebe-M on July 7, 2016 20:42

I did some tests regarding the crop function and it really shows that the benchmarks should test for different image sizes:

I ran three crop variations:
1 - The current implementation
2 - The slightly modified version with Array.Copy

Parallel.For(
    startY,
    endY,
    y =>
{
     Array.Copy(
        source.Pixels,
        (((y + sourceY)*source.Width) + (startX + sourceX))*4,
        target.Pixels, ((y*target.Width) + startX)*4,
        (endX - startX)*4);

    this.OnRowProcessed();
});

3 - The slightly modified version with Array.Copy but single threaded

for (int y = startY; y < endY; y++)
{
     Array.Copy(
        source.Pixels,
        (((y + sourceY)*source.Width) + (startX + sourceX))*4,
        target.Pixels, ((y*target.Width) + startX)*4,
        (endX - startX)*4);

    this.OnRowProcessed();
}

The results were as follows:

BenchmarkDotNet=v0.9.7.0
OS=Microsoft Windows NT 6.1.7601 Service Pack 1
Processor=Intel(R) Xeon(R) CPU E3-1231 v3 3.40GHz, ProcessorCount=8
Frequency=3320332 ticks, Resolution=301.1747 ns, Timer=TSC
HostCLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
JitModules=clrjit-v4.6.1076.0

Type=Crop Mode=Throughput

Image size: 400x400, Crop size: 100x100

Method Median StdDev Scaled
System.Drawing Crop 381.9870 us 1.3519 us 1.00
ImageProcessorCore Crop 672.7337 us 23.0420 us 1.76
Method Median StdDev Scaled
System.Drawing Crop 383.0861 us 1.7525 us 1.00
ImageProcessorCore Crop 626.6772 us 12.6071 us 1.64
Method Median StdDev Scaled
System.Drawing Crop 384.2923 us 2.4667 us 1.00
ImageProcessorCore Crop 580.5539 us 18.4702 us 1.51

And with larger images:
Image size: 4000x4000, Crop size: 1000x1000

Method Median StdDev Scaled
System.Drawing Crop 36.4692 ms 0.1921 ms 1.00
ImageProcessorCore Crop 12.4009 ms 0.1998 ms 0.34
Method Median StdDev Scaled
System.Drawing Crop 36.4490 ms 0.1024 ms 1.00
ImageProcessorCore Crop 12.1453 ms 0.1576 ms 0.33
Method Median StdDev Scaled
System.Drawing Crop 37.0588 ms 0.3184 ms 1.00
ImageProcessorCore Crop 15.0092 ms 0.1711 ms 0.41

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@Grebe-M That's some really interesting stats! Thanks for taking the time to produce them. Very cool to see the advantage we have on larger images.

The benchmarking needs a lot of work but I'm going to need help putting it all together. If you or anyone else can devote the time to help me do so that would be very much appreciated. It would give me the confidence to push the project further out of alpha status.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@mattwarren Thanks, I'll see if I can rustle something simple up over the next few days to repeat my issue.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @mattwarren on July 8, 2016 8:55

@Grebe-M I don't if you are aware of not, but BenchmarkDotNet supports parameterised benchmarks that might help you here. It works on fields and properties e.g.

public class IntroParams
{
    [Params(100, 200)]
    public int A { get; set; }

    [Params(10, 20)]
    public int B { get; set; }

    [Benchmark]
    public void Benchmark()
    {
        Thread.Sleep(A + B + 5);
    }
}

Produces the following results:

Method Median StdDev A B
Benchmark 115.3325 ms 0.0242 ms 100 10
Benchmark 125.3282 ms 0.0245 ms 100 20
Benchmark 215.3024 ms 0.0375 ms 200 10
Benchmark 225.2710 ms 0.0434 ms 200 20

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @Grebe-M on July 8, 2016 10:8

@mattwarren I was not aware, but because every possible combination gets tested seperately it's not the best solution in this particular case. I'd like to have parameter pairs that get used. For example I'd like to define something like this:

public class Crop
{
    private class CropBenchParameters
    {
        public int Width { get; set; }
        public int Height { get; set; }
        public int CropWidth { get; set; }
        public int CropHeigth { get; set; }
    }

    private List<CropBenchParameters> parameters = new List<CropBenchParameters>
    {
        new CropBenchParameters
        {
            Width = 96,
            Height = 96,
            CropWidth = 32,
            CropHeigth = 32
        },
        new CropBenchParameters
        {
            Width = 1920,
            Height = 1080,
            CropWidth = 1280,
            CropHeigth = 1024
        },
        new CropBenchParameters
        {
            Width = 4096,
            Height = 4096,
            CropWidth = 4077,
            CropHeigth = 4029
        }
    };
}

And then loop through the list and every loop is a seperate benchmark. Is something like this possible with BenchmarkDotNet?

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @Romanx on July 11, 2016 10:10

@Grebe-M It's not possible as I tried it however making a parameter of an Index in an array and passing that into your test method and looking up your params works.

There is obviously the overhead of lookup on the array during your benchmarks so if you're doing sensitive perf testing it may not be useful though.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @mattwarren on July 11, 2016 12:32

Another trick you can use is to setup "modes" of you benchmark as Enum values and then in a [Setup] method create the relevant Width, Height, etc for that mode. This way you don't pay any extra code in the [Benchmark] method itself.

See the modes in https://gist.github.com/mattwarren/8190ab7e4b139764d686d9bb279711b2 as an example.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @Romanx 12th July 2016

@mattwarren That's really useful. Thanks!

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

I was asked about this issue so I thought I'd comment here with some updates on progress made and where I'd like to focus on.

Since I opened the thread we've:

Reduced the amount of memory used per image by 75% by adopting a generic API and using bytes per color component by default.
Reduced operational memory by half for filters by operating on the input image without copying.
Sped up pixel access by almost 50% by using Unsafe
Reduced the number of allocations in Resize by removing private variables
There's probably more but I can't think what they are off the top of my head.

Areas I'd really like to focus on.

Encoders/Decoders. I've done barely any optimisation work there at all. I'm fairly sure a lot of the code could be rewritten to use pointers. I'd also like to utilize the Big/Little Endian writers more and optimise within there. I've a feeling that there is now classes for writing pointers to streams which we could use within them.

I'm utterly convinced I could use SIMD a lot more also. Within the encoders and within my individual algorithms. I'm not that sharp with them though and docs are sparse so don't really know where to start.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @NeelBhatt 14th July 2016

I like this package and have wrote basic blog for decoding of JPEG using this. which is here:

https://neelbhatt40.wordpress.com/2016/09/14/jpeg-decoder-for-net-core/

Thanks for the Nuget package.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

Hi @NeelBhatt Thanks for the publicity! 😄

I'd just like to suggest some updates to your blog if that's ok to correct a few details.

Just to clarify. The ImageProcessor version (2.4.4) published in Nuget is the legacy version that runs on the full .NET Framework. That version is in a separate branch in this repo called Framework.

What you are looking for to work on .NET Standard 1.1 + is the ImageProcessorCore package which is only on MyGet for the time being. That is hosted here. https://www.myget.org/gallery/imageprocessor

I hope that clears things up a little.

Cheers

James

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

From @NeelBhatt 14th July 2016

Oh okay so you mean for .Net core, we need to download it from the link you mentioned in your comment correct? Also can it be downloaded from your Github repository?

I will surely change that. Thanks :)

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

Just to note. Focus is now on Encoders/Decoders. Bmp is great! The rest....

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

Hey @antonfirsov That's great! Which classes in particular were you looking at? Please say the Jpeg decoder/encoder...

I would ❤️ if you could have a look at that if you could? I'm focusing on png just now.

from imagesharp.

antonfirsov avatar antonfirsov commented on May 22, 2024

Lost some of my initial optimism. Only managed to gain ~10% speed growth by reducing allocations + array flattening in the jpeg decoder. Even with ArrayPool-s!

The main bottlenecks are the IDCT.Transform() and JpegDecoderCore.DecodeHuffman() functions.

After analyzing the libjpeg code, I have the following conclusions:

  1. Transform could be replaced by a faster floating point implementation:
    https://dev.w3.org/Amaya/libjpeg/jidctflt.c
  2. It might be not enough, libjpeg DCT logic is much more complex

I can play a bit more this weekend, but if you want to go 100% managed, someone has to become a jpeg expert sooner or later.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@antonfirsov That's still progress so don't lose heart yet. I have a big book on the jpeg spec at home and am investigating the different implementations. Already forked libjpeg-turbo 😄

Translating to the floating point version shouldn't be beyond us. There's a faster, slightly less accurate version here also https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/jidctflt.c

FluxJpeg has implementations we can adapt that i'd like to investigate also.
https://github.com/briandonahue/FluxJpeg.Core/blob/master/FJCore/FDCT.cs
https://github.com/briandonahue/FluxJpeg.Core/blob/master/FJCore/DCT.cs

Intrigued by their inverse... It seems very simplistic.

from imagesharp.

antonfirsov avatar antonfirsov commented on May 22, 2024

I tried the FluxJpeg implementation ... actually it's slower. Maybe we need a floating point IDCT with System.Numerics.

from imagesharp.

antonfirsov avatar antonfirsov commented on May 22, 2024

This library contains a libjpeg port in C#:
https://imagetools.codeplex.com/

Shouldn't we adapt this instead of the golang port?

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

It's libjpeg.net. You don't wanna see the source, its brutal and super slow.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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

from imagesharp.

boguscoder avatar boguscoder commented on May 22, 2024

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

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

@boguscoder Thanks!

from imagesharp.

antonfirsov avatar antonfirsov commented on May 22, 2024

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

from imagesharp.

antonfirsov avatar antonfirsov commented on May 22, 2024

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.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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)

from imagesharp.

olivif avatar olivif commented on May 22, 2024

@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.

from imagesharp.

antonfirsov avatar antonfirsov commented on May 22, 2024

@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! :)

from imagesharp.

olivif avatar olivif commented on May 22, 2024

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.

from imagesharp.

JimBobSquarePants avatar JimBobSquarePants commented on May 22, 2024

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

from imagesharp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.