You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It'd be great to get this merged to master for 8.5, but it needs some testing.
How seq used to work:
The vips sink functions create a set of N threads and scan images top-to-bottom in tiles, allocating tiles to workers as they finish.
They have extra logic to keep workers together. They track the position of the most-delayed worker and if the lead thread gets more than M scanlines ahead, it stalls until the stragglers catch up.
There is more logic in the loaders: they keep track of the current Y position, and if the lead request thread gets ahead of the current read point, it stalls with a 60s timeout until the intermediate tiles are requested. This logic is implemented in the vips_sequential() operation.
The point of trying to keep thread locality and ordering is that we want to limit the number of scanlines that loaders have to keep behind the read point. We want to stream images through memory, not be forced into a load / process / save model.
This works reasonably well for simple cases, like thumbnailing single images, but can fail in more complex cases, such as repeated vips_insert(). Consider this Python program:
This makes a 100,000 x 100,000 pixel black image, then inserts a lot of other files into it and writes the result.
With vips8.4, this could very easily fail. Imagine this situation:
image1 is very tall and thin
image2 is short and fat, and by chance covers the centre of image1
we'll write the top part of image1, then write the body of image2
after image2 has been written, we need to write the bottom of image1, so a thread will ask for a set of pixels near the end of image1
image1 knows that the previous request was for some scanlines near the top, so it thinks this request must be from a thread that has run way ahead of the pack and stalls it
And we have a deadlock. In fact, vips wouldn't deadlock, it would just pause on a 60s timeout on each thread. Sad!
Here's how the new seq works:
Sinks work as before.
Loaders use a revised vips_sequential() with the stalling logic removed. All it does now is track the read position, cache a few 100 lines behind the read point, and makes sure that lines are evaluated in order with no missing areas.
Operations like vips_shrinkv() which can cause large non-local references have an extra bit of code which, if the input comes from a sequential source, adds a an extra vips_sequential() operator on the output. This forces vips_shrinkv() input to be sequential.
The old one constrained thread location on output, and on input as well. The new idea is to get rid of input constraints, and instead add extra code to the operations which could trigger large non-local references. Rather than tying threads down to stop them drifting apart, it makes sure they can never get too far apart in the first place.
Running the test program with git master gives this result:
real 1m2.317s
user 2m58.472s
sys 0m7.568s
peak mem: 10gb
Not bad!
The text was updated successfully, but these errors were encountered:
This branch has a new implementation of sequential mode:
https://github.com/jcupitt/libvips/tree/remove-seq-stalling
It'd be great to get this merged to master for 8.5, but it needs some testing.
How seq used to work:
vips_sequential()
operation.The point of trying to keep thread locality and ordering is that we want to limit the number of scanlines that loaders have to keep behind the read point. We want to stream images through memory, not be forced into a load / process / save model.
This works reasonably well for simple cases, like thumbnailing single images, but can fail in more complex cases, such as repeated
vips_insert()
. Consider this Python program:This makes a 100,000 x 100,000 pixel black image, then inserts a lot of other files into it and writes the result.
With vips8.4, this could very easily fail. Imagine this situation:
And we have a deadlock. In fact, vips wouldn't deadlock, it would just pause on a 60s timeout on each thread. Sad!
Here's how the new seq works:
vips_sequential()
with the stalling logic removed. All it does now is track the read position, cache a few 100 lines behind the read point, and makes sure that lines are evaluated in order with no missing areas.vips_shrinkv()
which can cause large non-local references have an extra bit of code which, if the input comes from a sequential source, adds a an extravips_sequential()
operator on the output. This forcesvips_shrinkv()
input to be sequential.The old one constrained thread location on output, and on input as well. The new idea is to get rid of input constraints, and instead add extra code to the operations which could trigger large non-local references. Rather than tying threads down to stop them drifting apart, it makes sure they can never get too far apart in the first place.
Running the test program with git master gives this result:
Not bad!
The text was updated successfully, but these errors were encountered: