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

Libvips is slower and consumes more memory than ImageMagick when resize small image #3654

Open
WeisiminPeng-Simmi opened this issue Sep 7, 2023 · 10 comments

Comments

@WeisiminPeng-Simmi
Copy link

WeisiminPeng-Simmi commented Sep 7, 2023

Hi Libvips team, I plan to move from ImageMagick to Libvips, but I have noticed that Libvips is slower and consumes more memory than ImageMagick when resize small image, I tried 144kb, 500kb, 1mb, 5mb, and 10mb, they all need less time and less memory than ImageMagick except 144kb and 500kb.

The commands I use

//ImageMagick
//takes 0.10 seconds and memory 10mb
convert 500kB.png -resize 64x64! 500kB-out.png
// 0.06 seconds and memory 7.28mb
convert 144kb.png -resize 64x64! 144kb-im.png

//Libvips
//takes 0.41 seconds and memory 10.6mb
vipsthumbnail 500kB.png --size 64x64 -o 500kB-out-1.png
// 0.17 seconds and memory 10.37mb
vipsthumbnail 144kb.png --size 64x64 -o 144kb_libvips.png

Maybe there are some configurations I missed? I wish Libvips consumes the similar time and memory as ImageMagick, is it possible?

500kb:
500kB
144kb:
144kb

@jcupitt
Copy link
Member

jcupitt commented Sep 7, 2023

Hi @WeisiminPeng-Simmi,

vipsthumbnail has a longer startup time, and that hurts for small images. If you process many images at once, you can see the per-image cost:

$ for i in {1..100}; do cp ../500kb.png $i.png; done
$ /usr/bin/time -f %M:%e vipsthumbnail *.png --size 64
40156:1.12

So for 100 images, vipsthumbnail is 0.012s per image.

You can reduce the startup time by configuring libvips without modules, and by linking it statically. You'd need to build your own binary for that though.

@WeisiminPeng-Simmi
Copy link
Author

WeisiminPeng-Simmi commented Sep 7, 2023

@jcupitt I actually use pyvips to run Libvips. Is there a way I can decrease the time using pyvips?

def perform_resize(image, width, height):
    return image.thumbnail_image(width, height=height, size="force")

Also I tried your way to test 100 images, below is the best result I got (run 10 times), is there anything I missed? Your memory is also less than my test.

➜  test /usr/bin/time -l -h -p vipsthumbnail *.png --size 64
real 1.81
user 1.02
sys 0.13
            33341440  maximum resident set size
                   0  average shared memory size
                   0  average unshared data size
                   0  average unshared stack size
                2439  page reclaims
                  22  page faults
                   0  swaps
                   0  block input operations
                   0  block output operations
                   0  messages sent
                   0  messages received
                   0  signals received
                   0  voluntary context switches
                2933  involuntary context switches
          8668050135  instructions retired
          3497429363  cycles elapsed
            15926976  peak memory footprint

@jcupitt
Copy link
Member

jcupitt commented Sep 7, 2023

I actually use pyvips to run Libvips. Is there a way I can decrease the time using pyvips?

You can use multiprocessing to run many resizes at once. It should be 4x faster on a 4 core machine, etc.

Also I tried your way to test 100 images, below is the best result I got (run 10 times), is there anything I missed? Your memory is also less than my test.

Did you build libvips yourself? What commands did you use to build it? What host OS are you using? Is it arch?

@WeisiminPeng-Simmi
Copy link
Author

Want to make sure I understand what you said longer startup time, it means if I run multiple vipsthumbnail one by one, it will has a long startup time each time? And if I run multiple vipsthumbnail at the same time, it will only need one long startup time?

Did you build libvips yourself? What commands did you use to build it? What host OS are you using? Is it arch?
--- No, I didn't build anything, just normal vips (brew install vips), I am using MacOS Ventura with M1 chip.

@jcupitt
Copy link
Member

jcupitt commented Sep 7, 2023

vipsthumbnail calls vips_init() to start libvips up. This does quite a few things to get ready. You can see the cost like this:

$ time vipsthumbnail 

real	0m0.032s
user	0m0.020s
sys	0m0.012s

So that's just startup and shutdown time, no images are processed.

With pyvips, you pay that cost once when you import pyvips, but after that it ought to be quick.

@jcupitt
Copy link
Member

jcupitt commented Sep 7, 2023

You can use multiprocessing like this:

#!/usr/bin/python3

import sys
import pyvips
from multiprocessing import Pool

def thumbnail(params):
    filename, N = params
    try:
        # 58s
        thumb = pyvips.Image.thumbnail(filename, 1600)
        thumb.write_to_file(f"t-{N}-1600.jpg")
        thumb = pyvips.Image.thumbnail(filename, 720)
        thumb.write_to_file(f"t-{N}-720.jpg")
        thumb = pyvips.Image.thumbnail(filename, 120)
        thumb.write_to_file(f"t-{N}-120.jpg")

        return 'OK'
    except Exception as e:
        return e

pool = Pool(8)
results = pool.map(thumbnail, zip(sys.argv[1:] ,range((len(sys.argv[1:])))))

That'll run up to 8 thumbnails at once.

@WeisiminPeng-Simmi
Copy link
Author

I see you talked about 4 core machine, we are using 2 core machine, will you recommend to use 4 core machine?

@jcupitt
Copy link
Member

jcupitt commented Sep 8, 2023

You can use any number of cores you like, it was just an example.

@jcupitt
Copy link
Member

jcupitt commented Nov 23, 2023

I think we're done, I'll close.

@jcupitt jcupitt closed this as completed Nov 23, 2023
@jcupitt
Copy link
Member

jcupitt commented Nov 23, 2023

I just noticed, you pasted this pyvips code:

def perform_resize(image, width, height):
    return image.thumbnail_image(width, height=height, size="force")

Don't use thumbnail_image! It's usually much slower than thumbnail. For example:

$ time vips thumbnail nina.jpg x.jpg 128
memory: high-water mark 2.99 MB

real	0m0.125s
user	0m0.090s
sys	0m0.028s

$ time vips thumbnail_image nina.jpg x.jpg 128
memory: high-water mark 87.46 MB

real	0m0.678s
user	0m0.644s
sys	0m0.084s

Plain thumbnail is around 5x faster, and needs a lot less memory.

It would be best to make a complete, runnable benchmark, and then tune that. If you post the exact code you are testing, I can check it for you.

@jcupitt jcupitt reopened this Nov 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants