make the buffer recycle list per image
so now recycle lists are short, scale with pipeline complexity, and buffers are always appropriately sized for the image instead of being slowly sized up to the max size for the pipeline before: $ vips sharpen k2.jpg x.jpg --radius 20 memory: high-water mark 38.99 MB after: $ vips sharpen k2.jpg x.jpg --radius 20 memory: high-water mark 29.46 MB
This commit is contained in:
parent
3835834177
commit
2c5ee332f0
3
TODO
3
TODO
@ -1,3 +1,6 @@
|
|||||||
|
- vipsthumbnail could have a --zoom option, does a crop to ensure output is
|
||||||
|
always exactly the specified --size
|
||||||
|
|
||||||
- vipsprofile reports a leak, strangely
|
- vipsprofile reports a leak, strangely
|
||||||
|
|
||||||
- vipsprofile performance is very poor for large data sets, eg.
|
- vipsprofile performance is very poor for large data sets, eg.
|
||||||
|
@ -82,28 +82,29 @@ VipsWindow *vips_window_ref( struct _VipsImage *im, int top, int height );
|
|||||||
int vips_window_unref( VipsWindow *window );
|
int vips_window_unref( VipsWindow *window );
|
||||||
void vips_window_print( VipsWindow *window );
|
void vips_window_print( VipsWindow *window );
|
||||||
|
|
||||||
/* Per-thread buffer cache. Held in a GPrivate.
|
/* Per-thread buffer state. Held in a GPrivate.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GHashTable *hash; /* Hash to VipsBufferCacheList* */
|
GHashTable *hash; /* VipsImage -> VipsBufferCache* */
|
||||||
GThread *thread; /* Just for sanity checking */
|
GThread *thread; /* Just for sanity checking */
|
||||||
GSList *reserve; /* VipsBuffer kept in reserve */
|
} VipsBufferThread;
|
||||||
int n_reserve; /* Number in reserve */
|
|
||||||
} VipsBufferCache;
|
|
||||||
|
|
||||||
/* Per-image buffer cache. Hash to this from VipsBufferCache.
|
/* Per-image buffer cache. Hash to this from VipsBufferCache.
|
||||||
* We can't store the GSList directly in the hash table, as GHashTable lacks an
|
* We can't store the GSList directly in the hash table, as GHashTable lacks an
|
||||||
* update operation and we'd need to _remove() and _insert() on every list
|
* update operation and we'd need to _remove() and _insert() on every list
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
typedef struct _VipsBufferCacheList {
|
typedef struct _VipsBufferCache {
|
||||||
GSList *buffers; /* GSList of VipsBuffer* */
|
GSList *buffers; /* GSList of VipsBuffer* */
|
||||||
GThread *thread; /* Just for sanity checking */
|
GThread *thread; /* Just for sanity checking */
|
||||||
struct _VipsImage *im;
|
struct _VipsImage *im;
|
||||||
VipsBufferCache *cache;
|
VipsBufferThread *buffer_thread;
|
||||||
} VipsBufferCacheList;
|
GSList *reserve; /* VipsBuffer kept in reserve */
|
||||||
|
int n_reserve; /* Number in reserve */
|
||||||
|
} VipsBufferCache;
|
||||||
|
|
||||||
/* What we track for each pixel buffer.
|
/* What we track for each pixel buffer. These can move between caches and
|
||||||
|
* between threads, but not between images.
|
||||||
*/
|
*/
|
||||||
typedef struct _VipsBuffer {
|
typedef struct _VipsBuffer {
|
||||||
int ref_count; /* # of regions referencing us */
|
int ref_count; /* # of regions referencing us */
|
||||||
@ -111,7 +112,7 @@ typedef struct _VipsBuffer {
|
|||||||
|
|
||||||
VipsRect area; /* Area this pixel buffer covers */
|
VipsRect area; /* Area this pixel buffer covers */
|
||||||
gboolean done; /* Calculated and in cache */
|
gboolean done; /* Calculated and in cache */
|
||||||
VipsBufferCache *cache;
|
VipsBufferCache *cache; /* The cache this buffer is published on */
|
||||||
VipsPel *buf; /* Private malloc() area */
|
VipsPel *buf; /* Private malloc() area */
|
||||||
size_t bsize; /* Size of private malloc() */
|
size_t bsize; /* Size of private malloc() */
|
||||||
} VipsBuffer;
|
} VipsBuffer;
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
* - move link maintenance to im_demand_hint
|
* - move link maintenance to im_demand_hint
|
||||||
* 21/9/11
|
* 21/9/11
|
||||||
* - switch to vips_tracked_malloc()
|
* - switch to vips_tracked_malloc()
|
||||||
|
* 18/12/13
|
||||||
|
* - keep a few buffers in reserve per image, stops malloc/free
|
||||||
|
* cycling when sharing is repeatedly discovered
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -74,12 +77,11 @@ static GSList *vips__buffers_all = NULL;
|
|||||||
static int buffer_cache_n = 0;
|
static int buffer_cache_n = 0;
|
||||||
#endif /*DEBUG_CREATE*/
|
#endif /*DEBUG_CREATE*/
|
||||||
|
|
||||||
/* The maximum numbers of buffers we hold in reserve per thread. About 5 seems
|
/* The maximum numbers of buffers we hold in reserve per image.
|
||||||
* enough to stop malloc cycling on vips_sharpen().
|
|
||||||
*/
|
*/
|
||||||
static const int buffer_cache_max_reserve = 40;
|
static const int buffer_cache_max_reserve = 2;
|
||||||
|
|
||||||
static GPrivate *thread_buffer_cache_key = NULL;
|
static GPrivate *buffer_thread_key = NULL;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static void *
|
static void *
|
||||||
@ -131,6 +133,13 @@ vips_buffer_free( VipsBuffer *buffer )
|
|||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_thread_free( VipsBufferThread *buffer_thread )
|
||||||
|
{
|
||||||
|
VIPS_FREEF( g_hash_table_destroy, buffer_thread->hash );
|
||||||
|
VIPS_FREE( buffer_thread );
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
buffer_cache_free( VipsBufferCache *cache )
|
buffer_cache_free( VipsBufferCache *cache )
|
||||||
{
|
{
|
||||||
@ -139,69 +148,41 @@ buffer_cache_free( VipsBufferCache *cache )
|
|||||||
#ifdef DEBUG_CREATE
|
#ifdef DEBUG_CREATE
|
||||||
buffer_cache_n -= 1;
|
buffer_cache_n -= 1;
|
||||||
|
|
||||||
printf( "vips__buffer_cache_free: freeing cache %p on thread %p\n",
|
printf( "buffer_cache_free: freeing cache %p on thread %p\n",
|
||||||
cache, g_thread_self() );
|
cache, g_thread_self() );
|
||||||
printf( "\t(%d caches left)\n", buffer_cache_n );
|
printf( "\t(%d caches left)\n", buffer_cache_n );
|
||||||
#endif /*DEBUG_CREATE*/
|
#endif /*DEBUG_CREATE*/
|
||||||
|
|
||||||
|
/* Need to mark undone so we don't try and take them off this hash on
|
||||||
|
* unref.
|
||||||
|
*/
|
||||||
|
for( p = cache->buffers; p; p = p->next ) {
|
||||||
|
VipsBuffer *buffer = (VipsBuffer *) p->data;
|
||||||
|
|
||||||
|
buffer->done = FALSE;
|
||||||
|
}
|
||||||
|
VIPS_FREEF( g_slist_free, cache->buffers );
|
||||||
|
|
||||||
for( p = cache->reserve; p; p = p->next ) {
|
for( p = cache->reserve; p; p = p->next ) {
|
||||||
VipsBuffer *buffer = (VipsBuffer *) p->data;
|
VipsBuffer *buffer = (VipsBuffer *) p->data;
|
||||||
|
|
||||||
vips_buffer_free( buffer );
|
vips_buffer_free( buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
VIPS_FREEF( g_slist_free, cache->reserve );
|
VIPS_FREEF( g_slist_free, cache->reserve );
|
||||||
VIPS_FREEF( g_hash_table_destroy, cache->hash );
|
|
||||||
VIPS_FREE( cache );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
g_free( cache );
|
||||||
buffer_cache_list_free( VipsBufferCacheList *cache_list )
|
|
||||||
{
|
|
||||||
GSList *p;
|
|
||||||
|
|
||||||
/* Need to mark undone so we don't try and take them off this hash on
|
|
||||||
* unref.
|
|
||||||
*/
|
|
||||||
for( p = cache_list->buffers; p; p = p->next ) {
|
|
||||||
VipsBuffer *buffer = (VipsBuffer *) p->data;
|
|
||||||
|
|
||||||
buffer->done = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VIPS_FREEF( g_slist_free, cache_list->buffers );
|
|
||||||
g_free( cache_list );
|
|
||||||
}
|
|
||||||
|
|
||||||
static VipsBufferCacheList *
|
|
||||||
buffer_cache_list_new( VipsBufferCache *cache, VipsImage *im )
|
|
||||||
{
|
|
||||||
VipsBufferCacheList *cache_list;
|
|
||||||
|
|
||||||
cache_list = g_new( VipsBufferCacheList, 1 );
|
|
||||||
cache_list->buffers = NULL;
|
|
||||||
cache_list->thread = g_thread_self();
|
|
||||||
cache_list->cache = cache;
|
|
||||||
cache_list->im = im;
|
|
||||||
|
|
||||||
#ifdef DEBUG_CREATE
|
|
||||||
printf( "buffer_cache_list_new: new cache %p for thread %p\n",
|
|
||||||
cache, g_thread_self() );
|
|
||||||
printf( "\t(%d caches now)\n", buffer_cache_n );
|
|
||||||
#endif /*DEBUG_CREATE*/
|
|
||||||
|
|
||||||
return( cache_list );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VipsBufferCache *
|
static VipsBufferCache *
|
||||||
buffer_cache_new( void )
|
buffer_cache_new( VipsBufferThread *buffer_thread, VipsImage *im )
|
||||||
{
|
{
|
||||||
VipsBufferCache *cache;
|
VipsBufferCache *cache;
|
||||||
|
|
||||||
cache = g_new( VipsBufferCache, 1 );
|
cache = g_new( VipsBufferCache, 1 );
|
||||||
cache->hash = g_hash_table_new_full( g_direct_hash, g_direct_equal,
|
cache->buffers = NULL;
|
||||||
NULL, (GDestroyNotify) buffer_cache_list_free );
|
|
||||||
cache->thread = g_thread_self();
|
cache->thread = g_thread_self();
|
||||||
|
cache->im = im;
|
||||||
|
cache->buffer_thread = buffer_thread;
|
||||||
cache->reserve = NULL;
|
cache->reserve = NULL;
|
||||||
cache->n_reserve = 0;
|
cache->n_reserve = 0;
|
||||||
|
|
||||||
@ -216,19 +197,51 @@ buffer_cache_new( void )
|
|||||||
return( cache );
|
return( cache );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the buffer cache.
|
static VipsBufferThread *
|
||||||
*/
|
buffer_thread_new( void )
|
||||||
static VipsBufferCache *
|
|
||||||
buffer_cache_get( void )
|
|
||||||
{
|
{
|
||||||
VipsBufferCache *cache;
|
VipsBufferThread *buffer_thread;
|
||||||
|
|
||||||
if( !(cache = g_private_get( thread_buffer_cache_key )) ) {
|
buffer_thread = g_new( VipsBufferThread, 1 );
|
||||||
cache = buffer_cache_new();
|
buffer_thread->hash = g_hash_table_new_full(
|
||||||
g_private_set( thread_buffer_cache_key, cache );
|
g_direct_hash, g_direct_equal,
|
||||||
|
NULL, (GDestroyNotify) buffer_cache_free );
|
||||||
|
buffer_thread->thread = g_thread_self();
|
||||||
|
|
||||||
|
return( buffer_thread );
|
||||||
|
}
|
||||||
|
|
||||||
|
static VipsBufferThread *
|
||||||
|
buffer_thread_get( void )
|
||||||
|
{
|
||||||
|
VipsBufferThread *buffer_thread;
|
||||||
|
|
||||||
|
if( !(buffer_thread = g_private_get( buffer_thread_key )) ) {
|
||||||
|
buffer_thread = buffer_thread_new();
|
||||||
|
g_private_set( buffer_thread_key, buffer_thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
return( cache );
|
g_assert( buffer_thread->thread == g_thread_self() );
|
||||||
|
|
||||||
|
return( buffer_thread );
|
||||||
|
}
|
||||||
|
|
||||||
|
static VipsBufferCache *
|
||||||
|
buffer_cache_get( VipsImage *im )
|
||||||
|
{
|
||||||
|
VipsBufferThread *buffer_thread = buffer_thread_get();
|
||||||
|
|
||||||
|
VipsBufferCache *cache;
|
||||||
|
|
||||||
|
if( !(cache = (VipsBufferCache *)
|
||||||
|
g_hash_table_lookup( buffer_thread->hash, im )) ) {
|
||||||
|
cache = buffer_cache_new( buffer_thread, im );
|
||||||
|
g_hash_table_insert( buffer_thread->hash, im, cache );
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert( cache->thread == g_thread_self() );
|
||||||
|
|
||||||
|
return( cache );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pixels have been calculated: publish for other parts of this thread to see.
|
/* Pixels have been calculated: publish for other parts of this thread to see.
|
||||||
@ -238,8 +251,7 @@ vips_buffer_done( VipsBuffer *buffer )
|
|||||||
{
|
{
|
||||||
if( !buffer->done ) {
|
if( !buffer->done ) {
|
||||||
VipsImage *im = buffer->im;
|
VipsImage *im = buffer->im;
|
||||||
VipsBufferCache *cache = buffer_cache_get();
|
VipsBufferCache *cache = buffer_cache_get( im );
|
||||||
VipsBufferCacheList *cache_list;
|
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
printf( "vips_buffer_done: thread %p adding to cache %p\n",
|
printf( "vips_buffer_done: thread %p adding to cache %p\n",
|
||||||
@ -247,18 +259,11 @@ vips_buffer_done( VipsBuffer *buffer )
|
|||||||
vips_buffer_print( buffer );
|
vips_buffer_print( buffer );
|
||||||
#endif /*DEBUG_VERBOSE*/
|
#endif /*DEBUG_VERBOSE*/
|
||||||
|
|
||||||
/* Look up and update the buffer list.
|
g_assert( !g_slist_find( cache->buffers, buffer ) );
|
||||||
*/
|
g_assert( !buffer->cache );
|
||||||
if( !(cache_list = g_hash_table_lookup( cache->hash, im )) ) {
|
|
||||||
cache_list = buffer_cache_list_new( cache, im );
|
|
||||||
g_hash_table_insert( cache->hash, im, cache_list );
|
|
||||||
}
|
|
||||||
|
|
||||||
g_assert( !g_slist_find( cache_list->buffers, buffer ) );
|
cache->buffers = g_slist_prepend( cache->buffers, buffer );
|
||||||
g_assert( cache_list->thread == cache->thread );
|
|
||||||
|
|
||||||
cache_list->buffers =
|
|
||||||
g_slist_prepend( cache_list->buffers, buffer );
|
|
||||||
buffer->done = TRUE;
|
buffer->done = TRUE;
|
||||||
buffer->cache = cache;
|
buffer->cache = cache;
|
||||||
}
|
}
|
||||||
@ -270,9 +275,8 @@ void
|
|||||||
vips_buffer_undone( VipsBuffer *buffer )
|
vips_buffer_undone( VipsBuffer *buffer )
|
||||||
{
|
{
|
||||||
if( buffer->done ) {
|
if( buffer->done ) {
|
||||||
VipsImage *im = buffer->im;
|
|
||||||
VipsBufferCache *cache = buffer->cache;
|
VipsBufferCache *cache = buffer->cache;
|
||||||
VipsBufferCacheList *cache_list;
|
VipsBufferThread *buffer_thread = cache->buffer_thread;
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
printf( "vips_buffer_undone: thread %p removing "
|
printf( "vips_buffer_undone: thread %p removing "
|
||||||
@ -281,19 +285,15 @@ vips_buffer_undone( VipsBuffer *buffer )
|
|||||||
#endif /*DEBUG_VERBOSE*/
|
#endif /*DEBUG_VERBOSE*/
|
||||||
|
|
||||||
g_assert( cache->thread == g_thread_self() );
|
g_assert( cache->thread == g_thread_self() );
|
||||||
|
g_assert( buffer_thread->thread == cache->thread );
|
||||||
|
g_assert( g_slist_find( cache->buffers, buffer ) );
|
||||||
|
g_assert( buffer_thread == buffer_thread_get() );
|
||||||
|
|
||||||
cache_list = g_hash_table_lookup( cache->hash, im );
|
cache->buffers = g_slist_remove( cache->buffers, buffer );
|
||||||
|
|
||||||
g_assert( cache_list );
|
|
||||||
g_assert( cache_list->thread == cache->thread );
|
|
||||||
g_assert( g_slist_find( cache_list->buffers, buffer ) );
|
|
||||||
|
|
||||||
cache_list->buffers =
|
|
||||||
g_slist_remove( cache_list->buffers, buffer );
|
|
||||||
buffer->done = FALSE;
|
buffer->done = FALSE;
|
||||||
buffer->cache = NULL;
|
buffer->cache = NULL;
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
printf( "vips_buffer_undone: %d buffers left\n",
|
printf( "vips_buffer_undone: %d buffers left\n",
|
||||||
g_slist_length( cache_list->buffers ) );
|
g_slist_length( cache_list->buffers ) );
|
||||||
@ -320,7 +320,8 @@ vips_buffer_unref( VipsBuffer *buffer )
|
|||||||
buffer->ref_count -= 1;
|
buffer->ref_count -= 1;
|
||||||
|
|
||||||
if( buffer->ref_count == 0 ) {
|
if( buffer->ref_count == 0 ) {
|
||||||
VipsBufferCache *cache = buffer_cache_get();
|
VipsImage *im = buffer->im;
|
||||||
|
VipsBufferCache *cache = buffer_cache_get( im );
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
if( !buffer->done )
|
if( !buffer->done )
|
||||||
@ -336,9 +337,6 @@ vips_buffer_unref( VipsBuffer *buffer )
|
|||||||
g_slist_prepend( cache->reserve, buffer );
|
g_slist_prepend( cache->reserve, buffer );
|
||||||
cache->n_reserve += 1;
|
cache->n_reserve += 1;
|
||||||
|
|
||||||
buffer->done = FALSE;
|
|
||||||
buffer->cache = NULL;
|
|
||||||
buffer->im = NULL;
|
|
||||||
buffer->area.width = 0;
|
buffer->area.width = 0;
|
||||||
buffer->area.height = 0;
|
buffer->area.height = 0;
|
||||||
}
|
}
|
||||||
@ -378,7 +376,7 @@ buffer_move( VipsBuffer *buffer, VipsRect *area )
|
|||||||
VipsBuffer *
|
VipsBuffer *
|
||||||
vips_buffer_new( VipsImage *im, VipsRect *area )
|
vips_buffer_new( VipsImage *im, VipsRect *area )
|
||||||
{
|
{
|
||||||
VipsBufferCache *cache = buffer_cache_get();
|
VipsBufferCache *cache = buffer_cache_get( im );
|
||||||
|
|
||||||
VipsBuffer *buffer;
|
VipsBuffer *buffer;
|
||||||
|
|
||||||
@ -387,10 +385,11 @@ vips_buffer_new( VipsImage *im, VipsRect *area )
|
|||||||
cache->reserve = g_slist_remove( cache->reserve, buffer );
|
cache->reserve = g_slist_remove( cache->reserve, buffer );
|
||||||
cache->n_reserve -= 1;
|
cache->n_reserve -= 1;
|
||||||
|
|
||||||
|
g_assert( buffer->im == im );
|
||||||
|
g_assert( buffer->done == FALSE );
|
||||||
|
g_assert( !buffer->cache );
|
||||||
|
|
||||||
buffer->ref_count = 1;
|
buffer->ref_count = 1;
|
||||||
buffer->im = im;
|
|
||||||
buffer->done = FALSE;
|
|
||||||
buffer->cache = NULL;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
buffer = g_new0( VipsBuffer, 1 );
|
buffer = g_new0( VipsBuffer, 1 );
|
||||||
@ -422,22 +421,19 @@ vips_buffer_new( VipsImage *im, VipsRect *area )
|
|||||||
static VipsBuffer *
|
static VipsBuffer *
|
||||||
buffer_find( VipsImage *im, VipsRect *r )
|
buffer_find( VipsImage *im, VipsRect *r )
|
||||||
{
|
{
|
||||||
VipsBufferCache *cache = buffer_cache_get();
|
VipsBufferCache *cache = buffer_cache_get( im );
|
||||||
VipsBufferCacheList *cache_list;
|
|
||||||
VipsBuffer *buffer;
|
VipsBuffer *buffer;
|
||||||
GSList *p;
|
GSList *p;
|
||||||
VipsRect *area;
|
VipsRect *area;
|
||||||
|
|
||||||
cache_list = g_hash_table_lookup( cache->hash, im );
|
|
||||||
p = cache_list ? cache_list->buffers : NULL;
|
|
||||||
|
|
||||||
/* This needs to be quick :-( don't use
|
/* This needs to be quick :-( don't use
|
||||||
* vips_slist_map2()/vips_rect_includesrect(), do the search inline.
|
* vips_slist_map2()/vips_rect_includesrect(), do the search inline.
|
||||||
*
|
*
|
||||||
* FIXME we return the first enclosing buffer, perhaps we should
|
* FIXME we return the first enclosing buffer, perhaps we should
|
||||||
* search for the largest?
|
* search for the largest?
|
||||||
*/
|
*/
|
||||||
for( ; p; p = p->next ) {
|
for( p = cache->buffers; p; p = p->next ) {
|
||||||
buffer = (VipsBuffer *) p->data;
|
buffer = (VipsBuffer *) p->data;
|
||||||
area = &buffer->area;
|
area = &buffer->area;
|
||||||
|
|
||||||
@ -456,17 +452,15 @@ buffer_find( VipsImage *im, VipsRect *r )
|
|||||||
buffer );
|
buffer );
|
||||||
#endif /*DEBUG_VERBOSE*/
|
#endif /*DEBUG_VERBOSE*/
|
||||||
|
|
||||||
break;
|
return( buffer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( p )
|
return( NULL );
|
||||||
return( buffer );
|
|
||||||
else
|
|
||||||
return( NULL );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a ref to a buffer that encloses area.
|
/* Return a ref to a buffer that encloses area. The buffer we return might be
|
||||||
|
* done.
|
||||||
*/
|
*/
|
||||||
VipsBuffer *
|
VipsBuffer *
|
||||||
vips_buffer_ref( VipsImage *im, VipsRect *area )
|
vips_buffer_ref( VipsImage *im, VipsRect *area )
|
||||||
@ -548,13 +542,13 @@ vips__buffer_init( void )
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_PRIVATE_INIT
|
#ifdef HAVE_PRIVATE_INIT
|
||||||
static GPrivate private =
|
static GPrivate private =
|
||||||
G_PRIVATE_INIT( (GDestroyNotify) buffer_cache_free );
|
G_PRIVATE_INIT( (GDestroyNotify) buffer_thread_free );
|
||||||
|
|
||||||
thread_buffer_cache_key = &private;
|
buffer_thread_key = &private;
|
||||||
#else
|
#else
|
||||||
if( !thread_buffer_cache_key )
|
if( !buffer_thread_key )
|
||||||
thread_buffer_cache_key = g_private_new(
|
buffer_thread_key = g_private_new(
|
||||||
(GDestroyNotify) buffer_cache_free );
|
(GDestroyNotify) buffer_thread_free );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( buffer_cache_max_reserve < 1 )
|
if( buffer_cache_max_reserve < 1 )
|
||||||
@ -564,10 +558,10 @@ vips__buffer_init( void )
|
|||||||
void
|
void
|
||||||
vips__buffer_shutdown( void )
|
vips__buffer_shutdown( void )
|
||||||
{
|
{
|
||||||
VipsBufferCache *cache;
|
VipsBufferThread *buffer_thread;
|
||||||
|
|
||||||
if( (cache = g_private_get( thread_buffer_cache_key )) ) {
|
if( (buffer_thread = g_private_get( buffer_thread_key )) ) {
|
||||||
buffer_cache_free( cache );
|
buffer_thread_free( buffer_thread );
|
||||||
g_private_set( thread_buffer_cache_key, NULL );
|
g_private_set( buffer_thread_key, NULL );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,6 +223,15 @@ def is_overlap(events, gate_name1, gate_name2):
|
|||||||
if event2.gate_name != gate_name2:
|
if event2.gate_name != gate_name2:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# events are sorted by start time, so if we've gone past event1's
|
||||||
|
# stop time, we can give up
|
||||||
|
if event2.start > event1.stop:
|
||||||
|
break
|
||||||
|
|
||||||
|
# ... or if we're before event1's start
|
||||||
|
if event2.stop < event1.start:
|
||||||
|
continue
|
||||||
|
|
||||||
# if either endpoint of 1 is within 2
|
# if either endpoint of 1 is within 2
|
||||||
if event1.start > event2.start and event1.stop < event2.stop:
|
if event1.start > event2.start and event1.stop < event2.stop:
|
||||||
return True
|
return True
|
||||||
|
Loading…
Reference in New Issue
Block a user