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
|
- remove im_rightshift_size(), just a convenience function now
|
||||||
- vipsthumbnail no longer removes profiles by default
|
- vipsthumbnail no longer removes profiles by default
|
||||||
- much more gentle sharpening in thumbnails
|
- much more gentle sharpening in thumbnails
|
||||||
|
- added "minimise" signal, used by tilecache to drop
|
||||||
|
|
||||||
18/6/12 started 7.28.9
|
18/6/12 started 7.28.9
|
||||||
- slightly more memory debugging output
|
- 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
|
blocking bugs
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
@ -116,16 +116,21 @@ tile_destroy( Tile *tile )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_tile_cache_dispose( GObject *gobject )
|
vips_tile_cache_drop_all( VipsTileCache *cache )
|
||||||
{
|
{
|
||||||
VipsTileCache *cache = (VipsTileCache *) gobject;
|
|
||||||
|
|
||||||
while( cache->tiles ) {
|
while( cache->tiles ) {
|
||||||
Tile *tile = (Tile *) cache->tiles->data;
|
Tile *tile = (Tile *) cache->tiles->data;
|
||||||
|
|
||||||
tile_destroy( tile );
|
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 );
|
VIPS_FREEF( g_mutex_free, cache->lock );
|
||||||
|
|
||||||
G_OBJECT_CLASS( vips_tile_cache_parent_class )->dispose( gobject );
|
G_OBJECT_CLASS( vips_tile_cache_parent_class )->dispose( gobject );
|
||||||
@ -375,6 +380,14 @@ vips_tile_cache_gen( VipsRegion *or,
|
|||||||
return( 0 );
|
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
|
static int
|
||||||
vips_tile_cache_build( VipsObject *object )
|
vips_tile_cache_build( VipsObject *object )
|
||||||
{
|
{
|
||||||
@ -394,6 +407,9 @@ vips_tile_cache_build( VipsObject *object )
|
|||||||
vips_demand_hint( conversion->out,
|
vips_demand_hint( conversion->out,
|
||||||
VIPS_DEMAND_STYLE_SMALLTILE, cache->in, NULL );
|
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,
|
if( vips_image_generate( conversion->out,
|
||||||
vips_start_one, vips_tile_cache_gen, vips_stop_one,
|
vips_start_one, vips_tile_cache_gen, vips_stop_one,
|
||||||
cache->in, cache ) )
|
cache->in, cache ) )
|
||||||
|
@ -419,6 +419,16 @@ typedef struct _VipsImageClass {
|
|||||||
*/
|
*/
|
||||||
void (*invalidate)( VipsImage *image );
|
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;
|
} VipsImageClass;
|
||||||
|
|
||||||
GType vips_image_get_type( void );
|
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_invalidate_all( VipsImage *image );
|
||||||
|
|
||||||
|
void vips_image_minimise_all( VipsImage *image );
|
||||||
|
|
||||||
void vips_image_preeval( VipsImage *image );
|
void vips_image_preeval( VipsImage *image );
|
||||||
void vips_image_eval( VipsImage *image, guint64 processed );
|
void vips_image_eval( VipsImage *image, guint64 processed );
|
||||||
void vips_image_posteval( VipsImage *image );
|
void vips_image_posteval( VipsImage *image );
|
||||||
|
@ -93,7 +93,8 @@ int vips_image_open_input( VipsImage *image );
|
|||||||
int vips_image_open_output( VipsImage *image );
|
int vips_image_open_output( VipsImage *image );
|
||||||
|
|
||||||
void vips__link_break_all( VipsImage *im );
|
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 );
|
char *vips__b64_encode( const unsigned char *data, size_t data_length );
|
||||||
unsigned char *vips__b64_decode( const char *buffer, 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 );
|
g_assert( !image->downstream );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _LinkMap {
|
||||||
|
gboolean upstream;
|
||||||
|
int *serial;
|
||||||
|
VipsSListMap2Fn fn;
|
||||||
|
void *a;
|
||||||
|
void *b;
|
||||||
|
} LinkMap;
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
vips__link_mapp( VipsImage *image,
|
vips__link_mapp( VipsImage *image, LinkMap *map )
|
||||||
VipsSListMap2Fn fn, int *serial, void *a, void *b )
|
|
||||||
{
|
{
|
||||||
void *res;
|
void *res;
|
||||||
|
|
||||||
/* Loop?
|
/* Loop?
|
||||||
*/
|
*/
|
||||||
if( image->serial == *serial )
|
if( image->serial == *map->serial )
|
||||||
return( NULL );
|
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( res );
|
||||||
|
|
||||||
return( vips_slist_map4( image->downstream,
|
return( vips_slist_map2( map->upstream ?
|
||||||
(VipsSListMap4Fn) vips__link_mapp, fn, serial, a, b ) );
|
image->upstream : image->downstream,
|
||||||
|
(VipsSListMap2Fn) vips__link_mapp, map, NULL ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
@ -208,27 +216,37 @@ vips__link_map_cb( VipsImage *image, GSList **images )
|
|||||||
return( NULL );
|
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 *
|
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;
|
static int serial = 0;
|
||||||
|
|
||||||
|
LinkMap map;
|
||||||
GSList *images;
|
GSList *images;
|
||||||
GSList *p;
|
GSList *p;
|
||||||
void *result;
|
void *result;
|
||||||
|
|
||||||
|
serial += 1;
|
||||||
|
|
||||||
|
images = NULL;
|
||||||
|
|
||||||
/* The function might do anything, including removing images
|
/* The function might do anything, including removing images
|
||||||
* or invalidating other images, so we can't trigger them from within
|
* or invalidating other images, so we can't trigger them from within
|
||||||
* the image loop. Instead we collect a list of images, ref them,
|
* the image loop. Instead we collect a list of images, ref them,
|
||||||
* run the functions, and unref.
|
* run the functions, and unref.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
serial += 1;
|
map.upstream = upstream;
|
||||||
images = NULL;
|
map.serial = &serial;
|
||||||
vips__link_mapp( image,
|
map.fn = (VipsSListMap2Fn) vips__link_map_cb;
|
||||||
(VipsSListMap2Fn) vips__link_map_cb, &serial, &images, NULL );
|
map.a = (void *) &images;
|
||||||
|
map.b = NULL;
|
||||||
|
|
||||||
|
vips__link_mapp( image, &map );
|
||||||
|
|
||||||
for( p = images; p; p = p->next )
|
for( p = images; p; p = p->next )
|
||||||
g_object_ref( p->data );
|
g_object_ref( p->data );
|
||||||
|
@ -158,6 +158,7 @@ enum {
|
|||||||
SIG_POSTEVAL,
|
SIG_POSTEVAL,
|
||||||
SIG_WRITTEN,
|
SIG_WRITTEN,
|
||||||
SIG_INVALIDATE,
|
SIG_INVALIDATE,
|
||||||
|
SIG_MINIMISE,
|
||||||
SIG_LAST
|
SIG_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -793,6 +794,12 @@ vips_image_real_invalidate( VipsImage *image )
|
|||||||
g_mutex_unlock( image->sslock );
|
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
|
static void
|
||||||
vips_image_class_init( VipsImageClass *class )
|
vips_image_class_init( VipsImageClass *class )
|
||||||
{
|
{
|
||||||
@ -829,6 +836,8 @@ vips_image_class_init( VipsImageClass *class )
|
|||||||
|
|
||||||
class->invalidate = vips_image_real_invalidate;
|
class->invalidate = vips_image_real_invalidate;
|
||||||
|
|
||||||
|
class->minimise = vips_image_real_minimise;
|
||||||
|
|
||||||
/* Create properties.
|
/* Create properties.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -998,6 +1007,15 @@ vips_image_class_init( VipsImageClass *class )
|
|||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
g_cclosure_marshal_VOID__VOID,
|
g_cclosure_marshal_VOID__VOID,
|
||||||
G_TYPE_NONE, 0 );
|
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
|
static void
|
||||||
@ -1053,16 +1071,52 @@ vips_image_invalidate_all_cb( VipsImage *image )
|
|||||||
* vips_image_invalidate_all:
|
* vips_image_invalidate_all:
|
||||||
* @image: #VipsImage to invalidate
|
* @image: #VipsImage to invalidate
|
||||||
*
|
*
|
||||||
* Invalidate all pixel caches on an @image and any derived images. The
|
* Invalidate all pixel caches on an @image and any downstream images, that
|
||||||
* "invalidate" callback is triggered for all invalidated images.
|
* is, images which depend on this image.
|
||||||
|
*
|
||||||
|
* The "invalidate" callback is triggered for all invalidated images.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
vips_image_invalidate_all( VipsImage *image )
|
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 );
|
(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.
|
/* Attach a new time struct, if necessary, and reset it.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
@ -913,6 +913,10 @@ vips_threadpool_run( VipsImage *im,
|
|||||||
|
|
||||||
vips_threadpool_free( pool );
|
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 );
|
return( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user