libvips/lua-vips

lua entry thread aborted: runtime error: /usr/local/share/lua/5.1/vips/voperation.lua:126: too many callbacks

wuyachao opened this issue · 13 comments

I use ab -n 1000 -c 100 "xxx.com/asdsad".
I get the original picture

Requests per second:    1457.55 [#/sec] (mean)
Time per request:       68.608 [ms] (mean)
Time per request:       0.686 [ms] (mean, across all concurrent requests)
Transfer rate:          101334.15 [Kbytes/sec] received

but,I use thumbnail_buffer, the rps decrease a lot.

Requests per second:    85.25 [#/sec] (mean)
Time per request:       1328.824 [ms] (mean)
Time per request:       13.288 [ms] (mean, across all concurrent requests)
Transfer rate:          1845.87 [Kbytes/sec] received
local image = vips.Image.new_from_buffer(img)

local args = ngx_req_get_uri_args()

local img2

if tonumber(args.p) == 0 or tonumber(args.w) > image:width() or tonumber(args.h) > image:height() then
  ngx.header.content_type = "image/jpeg"
  ngx.say(img)
  ngx.exit(200)
end

if tonumber(args.p) == 2 then
  img2 = image:smartcrop(tonumber(args.w), tonumber(args.h), { interesting = "centre" })
else
  img2 = vips.Image.thumbnail_buffer(img, tonumber(args.w), { height = tonumber(args.h), size = "down"})
end

local a = img2:jpegsave_buffer()
ngx.header.content_type = "image/jpeg"
ngx.say(a)

vips.Image.thumbnail_buffer may cause qps decrease.
I can get some error form nginx_error_log:

115567 lua entry thread aborted: runtime error: /usr/local/share/lua/5.1/vips/voperation.lua:126: too many callbacks
or 

sometimes,there is no error.but the qps is also 80~110. I'm sorry for my poor English.

Hello, I tried to make a test program:

#!/usr/bin/env luajit

vips = require 'vips'

-- benchmark thumbnail via a memory buffer
function via_memory(filename, thumbnail_width)
    print("memory processing ", filename)

    local fp = assert(io.open(filename, "rb"))
    local data = fp:read("*all")

    local thumb = vips.Image.thumbnail_buffer(data, thumbnail_width,
        {crop = "centre"})

    return thumb:write_to_buffer(".jpg")
end

-- benchmark thumbnail via files
function via_files(filename, thumbnail_width)
    print("file processing ", filename)

    local thumb = vips.Image.thumbnail(filename, thumbnail_width,
        {crop = "centre"})

    return thumb:write_to_buffer(".jpg")
end

for i = 1, #arg do
    -- thumb = via_memory(arg[i], 500)
    thumb = via_files(arg[i], 500)
end

I made some sample data like this:

  677  mkdir samples
  678  cd samples/
  679  for i in {1..10}; do cp ~/pics/k2.jpg $i.jpg; done

Wher k2.jpg is 1500 x 2000 pixel JPG.

When I run the program I see:

john@kiwi:~/try$ time ./soak.lua samples/*
file processing 	samples/10.jpg
file processing 	samples/1.jpg
file processing 	samples/2.jpg
file processing 	samples/3.jpg
file processing 	samples/4.jpg
file processing 	samples/5.jpg
file processing 	samples/6.jpg
file processing 	samples/7.jpg
file processing 	samples/8.jpg
file processing 	samples/9.jpg

real	0m0.538s
user	0m0.880s
sys	0m0.028s

And:

john@kiwi:~/try$ time ./soak.lua samples/*
memory processing 	samples/10.jpg
memory processing 	samples/1.jpg
memory processing 	samples/2.jpg
memory processing 	samples/3.jpg
memory processing 	samples/4.jpg
memory processing 	samples/5.jpg
memory processing 	samples/6.jpg
memory processing 	samples/7.jpg
memory processing 	samples/8.jpg
memory processing 	samples/9.jpg

real	0m0.521s
user	0m0.832s
sys	0m0.060s

So very similar speed, about 50ms per image on my slow laptop.

I tried with 1,000 images, and I see your "too many callbacks" error:

...
memory processing 	samples/934.jpg
memory processing 	samples/935.jpg
luajit: /home/john/.luarocks/share/lua/5.1/vips/voperation.lua:126: too many callbacks
stack traceback:
	[C]: in function 'cast'
	/home/john/.luarocks/share/lua/5.1/vips/voperation.lua:126: in function 'getargs'
	/home/john/.luarocks/share/lua/5.1/vips/voperation.lua:158: in function 'via_memory'
	./soak.lua:30: in main chunk
	[C]: at 0x004044a0

real	0m44.504s
user	1m16.292s
sys	0m2.236s

I tried adding collectgarbage() before each loop, but it made no difference.

I agree, it seems a callback is being leaked on each iteration. I'll investigate.

Thank you for reporting this.

The file processing version works, so it seems to be the GC callback on the buffer that leaks.

I've pushed a fix, it seems to work for me now. Would you be able to test?

If it fixes the problem for you too, I'll update the rock.

@jcupitt yes, it can fix this. It can work well when I request with `ab -n 2000 -c 200 'xxx.com/asda'

OK, I'll update the rock. Thanks again!

I meant to ask, did you find out why you were sometimes seeing low speed?

For JPEG, I would expect roughly 10 - 50ms per image, whether from file or memory. If you are seeing over 1000ms, something is probably broken.

@jcupitt lua-vips is always work fastly. It will 30-80ms for a request. I write the lua-vips to nginx_lua(OpenResty).
But the qps is very low. GraphicsMagick and ImageMagick is also like this.
I think the libvips,GraphicsMagick or ImageMagick dependent CPU very much. I can see the CPU is used up(over 90%) when I test it.
image
It's very fast per request. GraphicsMagick or ImageMagick will need 110-190ms. but libvips need 40~80ms.

real	0m0.045s
user	0m0.004s
sys	0m0.005s

QPS is queries per second, I guess?

On my desktop, I see:

john@mm-jcupitt5 /data/john/pics $ mkdir sample
john@mm-jcupitt5 /data/john/pics $ cd sample/
john@mm-jcupitt5 /data/john/pics/sample $ for i in {1..1000}; do cp ../k2.jpg $i.jpg; done
john@mm-jcupitt5 /data/john/pics/sample $ time parallel vipsthumbnail {} ::: *.jpg
real	0m5.372s
user	0m37.072s
sys	0m9.628s

So about ~150 thumbnails per second on this machine.

You could try benchmarking PNG, libvips should be much faster than graphicsmagick there. I see:

john@mm-jcupitt5 /data/john/pics $ time convert k2.png -resize 128x128 tn_k2.jpg

real	0m0.436s
user	0m0.380s
sys	0m0.020s
john@mm-jcupitt5 /data/john/pics $ time vipsthumbnail k2.png -s 128x128 -o tn_k2.jpg

real	0m0.182s
user	0m0.176s
sys	0m0.004s

With lower memory use. You'll find you can thumbnail very, very large images.

@jcupitt Thank you for your reply.
The qps is 43 when I use pngsave_buffer benchmarking. But jpegsave_buffer have 78 qps. the jpegsave_buffer is faster than pngsave_buffer.

Yes, libpng is slower than libjpg, but when you use PNG, libvips should be faster than graphicsmagick.