Replies: 3 comments
-
Hello @maximeg, That's very interesting, thank you for testing this. I think what's happening is that your processing is relatively quick, so being able to do it during the download does not save a great deal of time. I tried:
It's only 100ms of CPU that can be overlapped with download. It should save you a useful chunk of memory -- you're no longer buffering the entire source image. I don't know why implementing seek makes a difference, that seems very curious (and inefficient). I'll investigate. |
Beta Was this translation helpful? Give feedback.
-
I had a thought: how about adding upload as well, to simulate writing back to S3? The stream version should be able to overlap download and upload, and that ought to give a nice speedup. |
Beta Was this translation helpful? Give feedback.
-
I spent a little time on this again. Here's a revised version of that nice benchmark: puts "Ruby version: #{RUBY_VERSION}"
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
gem "benchmark-ips"
gem "down"
gem "http"
gem "ruby-vips"
end
require "benchmark/ips"
require "down/http"
IMAGE_URL = "https://images.unsplash.com/photo-1491933382434-500287f9b54b?q=80&w=5000"
SIZE = 512
def vips_ops(image)
image = image.sharpen(sigma: 1, x1: 2, y2: 10, y3: 20, m1: 0, m2: 3)
image
end
def old_way
buffer = HTTP.get(IMAGE_URL).to_s
image = Vips::Image.thumbnail_buffer(buffer, SIZE, crop: "centre")
image = vips_ops(image)
image.write_to_file("old_way.jpg", Q: 95, strip: true)
end
def stream_way
remote = Down::Http.open(IMAGE_URL)
source = Vips::SourceCustom.new
source.on_read { |length| remote.read(length) }
# fails if we don't implement seek() ... why?
source.on_seek { |offset, whence| remote.seek(offset, whence) }
image = Vips::Image.thumbnail_source(source, SIZE, crop: "centre")
image = vips_ops(image)
image.write_to_file("stream_way.jpg", Q: 95, strip: true)
remote.close
end
def download_and_stream_way
tmpfile = Down::Http.download(IMAGE_URL)
source = Vips::Source.new_from_memory tmpfile.read
tmpfile.unlink
image = Vips::Image.thumbnail_source(source, SIZE, crop: "centre")
image = vips_ops(image)
image.write_to_file("download_and_stream_way.jpg", Q: 95, strip: true)
end
Benchmark.ips do |x|
x.config(time: 10, warmup: 2)
# streaming is slower overall, perhaps because of the number of callbacks we
# end up triggering ... try buffering reads?
x.report("old_way") { old_way }
x.report("stream_way") { stream_way }
x.report("download_and_stream_way") { download_and_stream_way }
end Changes:
I see:
Notes:
So I think it's likely that the slowdown is just the Ruby callback overhead. Therefore:
|
Beta Was this translation helpful? Give feedback.
-
Hi @jcupitt,
I saw the promising streaming features from the 8.9 release 🥳.
So I tested to see if I could gain some perf improvement over one of my uses of vips.
The result is not what I hoped for.
Here is a synthetic test I used:
Result:
Do you have any insight? Maybe I missed something.
Note: when I don't implement
on_seek
, I get a bunch ofread: fiber called across threads
andVipsJpeg: Premature end of JPEG file
.Beta Was this translation helpful? Give feedback.
All reactions