Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit feae09e

Browse files
committed
make arrayjoin much faster with large arrays
arrayjoin was making a region on every input image during startup, and repeating for each thread (!!) so large arrays could be very expensive to join. Instead, make input regions on demand, and computre set of required input images rather than searching for them. See libvips#3247
1 parent a03e1ef commit feae09e

File tree

3 files changed

+55
-26
lines changed

3 files changed

+55
-26
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
- deprecate gifsave `reoptimise`, add `reuse`
2929
- add `encoder` to heifsave [dloebl]
3030
- add `cplusplus` meson build option [jcupitt]
31+
- make arrayjoin much faster with large arrays
3132

3233
9/11/22 started 8.13.4
3334
- missing include in mosaic_fuzzer [ServOKio]

libvips/conversion/arrayjoin.c

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
* - from join.c
55
* 6/9/21
66
* - minmise inputs once we've used them
7+
* 29/12/22
8+
* - much faster with large arrays
79
*/
810

911
/*
@@ -80,43 +82,67 @@ static int
8082
vips_arrayjoin_gen( VipsRegion *or, void *seq,
8183
void *a, void *b, gboolean *stop )
8284
{
83-
VipsRegion **ir = (VipsRegion **) seq;
85+
VipsImage **in = (VipsImage **) a;
8486
VipsArrayjoin *join = (VipsArrayjoin *) b;
8587
VipsConversion *conversion = VIPS_CONVERSION( join );
8688
VipsRect *r = &or->valid;
87-
8889
int n;
89-
VipsImage **in;
90+
91+
/* Find the left/top/width/height of the cells this region touches.
92+
*/
93+
int cell_width = join->hspacing + join->shim;
94+
int cell_height = join->vspacing + join->shim;
95+
int left = r->left / cell_width;
96+
int top = r->top / cell_height;
97+
int width = (VIPS_ROUND_UP( VIPS_RECT_RIGHT( r ), cell_width ) -
98+
VIPS_ROUND_DOWN( r->left, cell_width )) / cell_width;
99+
int height = (VIPS_ROUND_UP( VIPS_RECT_BOTTOM( r ), cell_height ) -
100+
VIPS_ROUND_DOWN( r->top, cell_height )) / cell_height;
101+
90102
int i;
91-
gboolean just_one;
103+
VipsRegion *reg;
92104

93-
in = vips_array_image_get( join->in, &n );
105+
/* Size of image array.
106+
*/
107+
vips_array_image_get( join->in, &n );
94108

95-
/* Does this rect fit completely within one of our inputs?
109+
/* Does this rect fit completely within one of our inputs? We can just
110+
* forward the request.
96111
*/
97-
just_one = FALSE;
98-
for( i = 0; i < n; i++ )
99-
if( vips_rect_includesrect( &join->rects[i], r ) ) {
100-
just_one = TRUE;
101-
break;
112+
if( width == 1 && height == 1 ) {
113+
i = VIPS_MIN( n - 1, left + top * join->across );
114+
115+
reg = vips_region_new( in[i] );
116+
117+
if( vips__insert_just_one( or, reg,
118+
join->rects[i].left, join->rects[i].top ) ) {
119+
g_object_unref( reg );
120+
return( -1 );
102121
}
103122

104-
if( just_one ) {
105-
/* Just needs one input, we can forward the request to that
106-
* region.
107-
*/
108-
if( vips__insert_just_one( or, ir[i],
109-
join->rects[i].left, join->rects[i].top ) )
110-
return( -1 );
123+
g_object_unref( reg );
111124
}
112125
else {
113126
/* Output requires more than one input. Paste all touching
114127
* inputs into the output.
115128
*/
116-
for( i = 0; i < n; i++ )
117-
if( vips__insert_paste_region( or, ir[i],
118-
&join->rects[i] ) )
119-
return( -1 );
129+
int x, y;
130+
131+
for( y = 0; y < height; y++ )
132+
for( x = 0; x < width; x++ ) {
133+
i = VIPS_MIN( n - 1,
134+
x + left + (y + top) * join->across );
135+
136+
reg = vips_region_new( in[i] );
137+
138+
if( vips__insert_paste_region( or, reg,
139+
&join->rects[i] ) ) {
140+
g_object_unref( reg );
141+
return( -1 );
142+
}
143+
144+
g_object_unref( reg );
145+
}
120146
}
121147

122148
if( vips_image_is_sequential( conversion->out ) )
@@ -320,9 +346,12 @@ vips_arrayjoin_build( VipsObject *object )
320346
conversion->out->Xsize = output_width;
321347
conversion->out->Ysize = output_height;
322348

349+
/* DOn't use start_many -- the set of input images can be huge (many
350+
* 10s of 1000s) and we don't want to have 20,000 regions active. It's
351+
* much quicker to make them on demand.
352+
*/
323353
if( vips_image_generate( conversion->out,
324-
vips_start_many, vips_arrayjoin_gen, vips_stop_many,
325-
size, join ) )
354+
NULL, vips_arrayjoin_gen, NULL, size, join ) )
326355
return( -1 );
327356

328357
return( 0 );

libvips/iofuncs/region.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,8 +1621,7 @@ vips_region_generate( VipsRegion *reg, void *a )
16211621
* Use vips_sink_screen() to calculate an area of pixels in the
16221622
* background.
16231623
*
1624-
* See also: vips_sink_screen(),
1625-
* vips_region_prepare_to().
1624+
* See also: vips_sink_screen(), vips_region_prepare_to().
16261625
*
16271626
* Returns: 0 on success, or -1 on error.
16281627
*/

0 commit comments

Comments
 (0)