add "minimise" signal
on end of an image loop, send a "minimise" signal down the pipeline tilecache listens for this signal on its output and drops the cache helps reduce ruby memuse
This commit is contained in:
parent
49fbfdd454
commit
daac11b01c
@ -7,6 +7,7 @@
|
||||
- remove im_rightshift_size(), just a convenience function now
|
||||
- vipsthumbnail no longer removes profiles by default
|
||||
- much more gentle sharpening in thumbnails
|
||||
- added "minimise" signal, used by tilecache to drop
|
||||
|
||||
18/6/12 started 7.28.9
|
||||
- slightly more memory debugging output
|
||||
|
8
TODO
8
TODO
@ -1,3 +1,11 @@
|
||||
- tile cache doesn't need to copy if request fits within a tile
|
||||
|
||||
though doing a copy means that we can safely drop the cache without leaving
|
||||
dangling pointers
|
||||
|
||||
- could jpeg load via memory buffer support minimise too?
|
||||
|
||||
|
||||
blocking bugs
|
||||
=============
|
||||
|
||||
|
@ -116,16 +116,21 @@ tile_destroy( Tile *tile )
|
||||
}
|
||||
|
||||
static void
|
||||
vips_tile_cache_dispose( GObject *gobject )
|
||||
vips_tile_cache_drop_all( VipsTileCache *cache )
|
||||
{
|
||||
VipsTileCache *cache = (VipsTileCache *) gobject;
|
||||
|
||||
while( cache->tiles ) {
|
||||
Tile *tile = (Tile *) cache->tiles->data;
|
||||
|
||||
tile_destroy( tile );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vips_tile_cache_dispose( GObject *gobject )
|
||||
{
|
||||
VipsTileCache *cache = (VipsTileCache *) gobject;
|
||||
|
||||
vips_tile_cache_drop_all( cache );
|
||||
VIPS_FREEF( g_mutex_free, cache->lock );
|
||||
|
||||
G_OBJECT_CLASS( vips_tile_cache_parent_class )->dispose( gobject );
|
||||
@ -375,6 +380,14 @@ vips_tile_cache_gen( VipsRegion *or,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_tile_cache_minimise( VipsImage *image, VipsTileCache *cache )
|
||||
{
|
||||
printf( "vips_tile_cache_minimise:\n" );
|
||||
|
||||
vips_tile_cache_drop_all( cache );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_tile_cache_build( VipsObject *object )
|
||||
{
|
||||
@ -394,6 +407,9 @@ vips_tile_cache_build( VipsObject *object )
|
||||
vips_demand_hint( conversion->out,
|
||||
VIPS_DEMAND_STYLE_SMALLTILE, cache->in, NULL );
|
||||
|
||||
g_signal_connect( conversion->out, "minimise",
|
||||
G_CALLBACK( vips_tile_cache_minimise ), cache );
|
||||
|
||||
if( vips_image_generate( conversion->out,
|
||||
vips_start_one, vips_tile_cache_gen, vips_stop_one,
|
||||
cache->in, cache ) )
|
||||
|
@ -419,6 +419,16 @@ typedef struct _VipsImageClass {
|
||||
*/
|
||||
void (*invalidate)( VipsImage *image );
|
||||
|
||||
/* Minimise this pipeline.
|
||||
*
|
||||
* This is triggered (sometimes) at the end of eval to signal that
|
||||
* we're probably done and that operations involved should try to
|
||||
* minimise memory use by, for example, dropping caches.
|
||||
*
|
||||
* See vips_tilecache().
|
||||
*/
|
||||
void (*minimise)( VipsImage *image );
|
||||
|
||||
} VipsImageClass;
|
||||
|
||||
GType vips_image_get_type( void );
|
||||
@ -475,6 +485,8 @@ int vips_image_written( VipsImage *image );
|
||||
|
||||
void vips_image_invalidate_all( VipsImage *image );
|
||||
|
||||
void vips_image_minimise_all( VipsImage *image );
|
||||
|
||||
void vips_image_preeval( VipsImage *image );
|
||||
void vips_image_eval( VipsImage *image, guint64 processed );
|
||||
void vips_image_posteval( VipsImage *image );
|
||||
|
@ -93,7 +93,8 @@ int vips_image_open_input( VipsImage *image );
|
||||
int vips_image_open_output( VipsImage *image );
|
||||
|
||||
void vips__link_break_all( VipsImage *im );
|
||||
void *vips__link_map( VipsImage *im, VipsSListMap2Fn fn, void *a, void *b );
|
||||
void *vips__link_map( VipsImage *image, gboolean upstream,
|
||||
VipsSListMap2Fn fn, void *a, void *b );
|
||||
|
||||
char *vips__b64_encode( const unsigned char *data, size_t data_length );
|
||||
unsigned char *vips__b64_decode( const char *buffer, size_t *data_length );
|
||||
|
@ -181,23 +181,31 @@ vips__link_break_all( VipsImage *image )
|
||||
g_assert( !image->downstream );
|
||||
}
|
||||
|
||||
typedef struct _LinkMap {
|
||||
gboolean upstream;
|
||||
int *serial;
|
||||
VipsSListMap2Fn fn;
|
||||
void *a;
|
||||
void *b;
|
||||
} LinkMap;
|
||||
|
||||
static void *
|
||||
vips__link_mapp( VipsImage *image,
|
||||
VipsSListMap2Fn fn, int *serial, void *a, void *b )
|
||||
vips__link_mapp( VipsImage *image, LinkMap *map )
|
||||
{
|
||||
void *res;
|
||||
|
||||
/* Loop?
|
||||
*/
|
||||
if( image->serial == *serial )
|
||||
if( image->serial == *map->serial )
|
||||
return( NULL );
|
||||
image->serial = *serial;
|
||||
image->serial = *map->serial;
|
||||
|
||||
if( (res = fn( image, a, b )) )
|
||||
if( (res = map->fn( image, map->a, map->b )) )
|
||||
return( res );
|
||||
|
||||
return( vips_slist_map4( image->downstream,
|
||||
(VipsSListMap4Fn) vips__link_mapp, fn, serial, a, b ) );
|
||||
return( vips_slist_map2( map->upstream ?
|
||||
image->upstream : image->downstream,
|
||||
(VipsSListMap2Fn) vips__link_mapp, map, NULL ) );
|
||||
}
|
||||
|
||||
static void *
|
||||
@ -208,27 +216,37 @@ vips__link_map_cb( VipsImage *image, GSList **images )
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/* Apply a function to an image and all downstream images, direct and indirect.
|
||||
/* Apply a function to an image and all upstream or downstream images,
|
||||
* direct and indirect.
|
||||
*/
|
||||
void *
|
||||
vips__link_map( VipsImage *image, VipsSListMap2Fn fn, void *a, void *b )
|
||||
vips__link_map( VipsImage *image, gboolean upstream,
|
||||
VipsSListMap2Fn fn, void *a, void *b )
|
||||
{
|
||||
static int serial = 0;
|
||||
|
||||
LinkMap map;
|
||||
GSList *images;
|
||||
GSList *p;
|
||||
void *result;
|
||||
|
||||
serial += 1;
|
||||
|
||||
images = NULL;
|
||||
|
||||
/* The function might do anything, including removing images
|
||||
* or invalidating other images, so we can't trigger them from within
|
||||
* the image loop. Instead we collect a list of images, ref them,
|
||||
* run the functions, and unref.
|
||||
*/
|
||||
|
||||
serial += 1;
|
||||
images = NULL;
|
||||
vips__link_mapp( image,
|
||||
(VipsSListMap2Fn) vips__link_map_cb, &serial, &images, NULL );
|
||||
map.upstream = upstream;
|
||||
map.serial = &serial;
|
||||
map.fn = (VipsSListMap2Fn) vips__link_map_cb;
|
||||
map.a = (void *) &images;
|
||||
map.b = NULL;
|
||||
|
||||
vips__link_mapp( image, &map );
|
||||
|
||||
for( p = images; p; p = p->next )
|
||||
g_object_ref( p->data );
|
||||
|
@ -158,6 +158,7 @@ enum {
|
||||
SIG_POSTEVAL,
|
||||
SIG_WRITTEN,
|
||||
SIG_INVALIDATE,
|
||||
SIG_MINIMISE,
|
||||
SIG_LAST
|
||||
};
|
||||
|
||||
@ -793,6 +794,12 @@ vips_image_real_invalidate( VipsImage *image )
|
||||
g_mutex_unlock( image->sslock );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_real_minimise( VipsImage *image )
|
||||
{
|
||||
VIPS_DEBUG_MSG( "vips_image_real_minimise: %p\n", image );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_class_init( VipsImageClass *class )
|
||||
{
|
||||
@ -829,6 +836,8 @@ vips_image_class_init( VipsImageClass *class )
|
||||
|
||||
class->invalidate = vips_image_real_invalidate;
|
||||
|
||||
class->minimise = vips_image_real_minimise;
|
||||
|
||||
/* Create properties.
|
||||
*/
|
||||
|
||||
@ -998,6 +1007,15 @@ vips_image_class_init( VipsImageClass *class )
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
|
||||
vips_image_signals[SIG_MINIMISE] = g_signal_new( "minimise",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET( VipsImageClass, minimise ),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1053,16 +1071,52 @@ vips_image_invalidate_all_cb( VipsImage *image )
|
||||
* vips_image_invalidate_all:
|
||||
* @image: #VipsImage to invalidate
|
||||
*
|
||||
* Invalidate all pixel caches on an @image and any derived images. The
|
||||
* "invalidate" callback is triggered for all invalidated images.
|
||||
* Invalidate all pixel caches on an @image and any downstream images, that
|
||||
* is, images which depend on this image.
|
||||
*
|
||||
* The "invalidate" callback is triggered for all invalidated images.
|
||||
*/
|
||||
void
|
||||
vips_image_invalidate_all( VipsImage *image )
|
||||
{
|
||||
(void) vips__link_map( image,
|
||||
(void) vips__link_map( image, FALSE,
|
||||
(VipsSListMap2Fn) vips_image_invalidate_all_cb, NULL, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
vips_image_minimise( VipsImage *image )
|
||||
{
|
||||
VIPS_DEBUG_MSG( "vips_image_minimise: %p\n", image );
|
||||
|
||||
g_signal_emit( image, vips_image_signals[SIG_MINIMISE], 0 );
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_image_minimise_all_cb( VipsImage *image )
|
||||
{
|
||||
vips_image_minimise( image );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_minimise_all:
|
||||
* @image: #VipsImage to minimise
|
||||
*
|
||||
* Minimise memory use on this image and any upstream images, that is, images
|
||||
* which this image depends upon.
|
||||
*
|
||||
* The "minimise" callback is triggered for all minimised images.
|
||||
*/
|
||||
void
|
||||
vips_image_minimise_all( VipsImage *image )
|
||||
{
|
||||
printf( "vips_image_minimise_all:\n" );
|
||||
|
||||
(void) vips__link_map( image, TRUE,
|
||||
(VipsSListMap2Fn) vips_image_minimise_all_cb, NULL, NULL );
|
||||
}
|
||||
|
||||
/* Attach a new time struct, if necessary, and reset it.
|
||||
*/
|
||||
static int
|
||||
|
@ -913,6 +913,10 @@ vips_threadpool_run( VipsImage *im,
|
||||
|
||||
vips_threadpool_free( pool );
|
||||
|
||||
/* Ask the pipeline to drop into low-mem-use mode now we're done.
|
||||
*/
|
||||
vips_image_minimise_all( im );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user