saschanaz / libflif.js

Another trial to get FLIF to the web platform
ISC License
41 stars 2 forks source link

Slow processing vs poly-flif #7

Open FallingSnow opened 7 years ago

FallingSnow commented 7 years ago

libflif is much slower than poly-flif in my test and more unstable. Do you know if there are any specific optimizations that poly-flif does versus libflif?

https://github.com/UprootLabs/poly-flif/issues/27

saschanaz commented 7 years ago

Can you provide an example to reproduce slow performance? Note that chromium-dev itself is unstable, so you have to test on the latest stable build to get more meaningful result.

FallingSnow commented 7 years ago

Got a test case done. If you use chromium, you will need to add --allow-file-access-from-files to your command line arguments.

libflif-performance-test-case.zip

In script.js you will see

decodeWebWorker(buffer);
// decodeSync(buffer);

Just switch between commenting each other and reload the page to see the difference.

FallingSnow commented 7 years ago

I ran some numbers. Both were set to scale to the image's native resolution of 5146x2935.

Web worker decode took 17053.045000000002 milliseconds.
Sync decode took 11826.785 milliseconds.
Web worker decode took 5226.260000000002 milliseconds longer.

When using poly-flif's scaling the results are much more dramatic.

FallingSnow commented 7 years ago

Using google-chrome-stable, same image, native resolution.

Web worker decode took 16493.545 milliseconds.
Sync decode took 12338.705000000002 milliseconds.
Web worker decode took 4154.8399999999965 milliseconds longer.
saschanaz commented 7 years ago

Currently one key part is memory-growth compiler option. poly-flif currently gives -s TOTAL_MEMORY=100000000, which forces 100 MiB memory allocation from the start. On the other hand, libflif.js currently gives -s ALLOW_MEMORY_GROWTH=1, which allows starting with small memory space and growing if needed. However, the memory growth option limits compiler optimization which can cause slower speed.

WebAssembly will allow chasing two rabbits but the current asm.js can only chase one, smaller memory space or faster performance.

saschanaz commented 7 years ago

The scaling decoder option is yet implemented, but you can still use it by manually inserting decoder.setScale(scaleX, scaleY)decoder.setScale(scale) on the worker script if you want. I just opened #8 for this.

FallingSnow commented 7 years ago

Thanks for the responses. I'm not sure yet, but I think the scaling option will add enough of a performance boost for the time being. If you don't mind, I might ask you for advice in the future about memory growth. I was able to deduce that I can use decoder.setResize and decoder.setFit so that's awesome.

Is there a way I can have the web worker just decode once (the highest possible quality) rather than in waves? (In my experience each wave takes just as long as a single max quality decode)

BTW, correct syntax is decoder.setScale(scale) for anyone reading this in the future.

saschanaz commented 7 years ago

You can decoder.setFirstCallbackQuality(10000) to get only single wave.

FallingSnow commented 7 years ago

Thank you.

saschanaz commented 7 years ago

BTW,

(In my experience each wave takes just as long as a single max quality decode)

I can reproduce this and I doubt this is a problem on my code. The callback does not cause much delay so this is possibly a FLIF decoder problem.

FallingSnow commented 7 years ago

Well, I solved this issue by doing a decode where setFit was set to a much smaller size, this gives a quick decode and image to display. Then follow up with the correct setFit.

Basically the same thing you were trying to accomplish without the delay.

saschanaz commented 7 years ago

Then follow up with the correct setFit.

You mean you call decodeWebWorker() multiple time with different setFit values?

FallingSnow commented 7 years ago

Yes.

Right now I'm trying to get the right setFit value for the final decode without knowing the image's dimensions beforehand. I basically want the opposite of --resize=WxH so that its lossy downscaled image to at least WxH instead of lossy downscaled image to fit inside WxH.

Sadly I'm still trying to figure out if this is possible without knowing the image's dimensions beforehand.