cache drops operations on invalidate
we can now enable the vips8 operation cache in nip2, woo!
This commit is contained in:
parent
66425bec8e
commit
d7bad8fd5b
@ -38,6 +38,7 @@
|
|||||||
- better filename tracking for globalbalance
|
- better filename tracking for globalbalance
|
||||||
- revised vips8 image load/save API, now simpler and more logical
|
- revised vips8 image load/save API, now simpler and more logical
|
||||||
- operations emit "invalidate" if any of their input images invalidate
|
- operations emit "invalidate" if any of their input images invalidate
|
||||||
|
- operation cache drops ops on invalidate
|
||||||
|
|
||||||
6/3/14 started 7.38.6
|
6/3/14 started 7.38.6
|
||||||
- grey ramp minimum was wrong
|
- grey ramp minimum was wrong
|
||||||
|
8
TODO
8
TODO
@ -1,11 +1,3 @@
|
|||||||
- test operation invalidate
|
|
||||||
|
|
||||||
enable cache in nip2, find max using vips_call, try painting on the input
|
|
||||||
|
|
||||||
- cache needs to listen for invalidate
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- can we use postbuild elsewhere? look at use of "preclose" / "written", etc.
|
- can we use postbuild elsewhere? look at use of "preclose" / "written", etc.
|
||||||
|
|
||||||
|
@ -65,11 +65,6 @@ typedef gboolean (*VipsOperationBuildFn)( VipsObject * );
|
|||||||
typedef struct _VipsOperation {
|
typedef struct _VipsOperation {
|
||||||
VipsObject parent_instance;
|
VipsObject parent_instance;
|
||||||
|
|
||||||
/* When we added this operation to cache .. used to find LRU for
|
|
||||||
* flush.
|
|
||||||
*/
|
|
||||||
int time;
|
|
||||||
|
|
||||||
/* Keep the hash here.
|
/* Keep the hash here.
|
||||||
*/
|
*/
|
||||||
guint hash;
|
guint hash;
|
||||||
|
@ -37,8 +37,6 @@
|
|||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
listen for invalidate
|
|
||||||
|
|
||||||
will we need to drop all on exit? unclear
|
will we need to drop all on exit? unclear
|
||||||
|
|
||||||
what about delayed writes ... do we ever write in close? we shouldn't,
|
what about delayed writes ... do we ever write in close? we shouldn't,
|
||||||
@ -123,6 +121,22 @@ static GMutex *vips_cache_lock = NULL;
|
|||||||
#define VIPS_VALUE_GET_CHAR g_value_get_char
|
#define VIPS_VALUE_GET_CHAR g_value_get_char
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* A cache entry.
|
||||||
|
*/
|
||||||
|
typedef struct _VipsOperationCacheEntry {
|
||||||
|
VipsOperation *operation;
|
||||||
|
|
||||||
|
/* When we added this operation to cache .. used to find LRU for
|
||||||
|
* flush.
|
||||||
|
*/
|
||||||
|
int time;
|
||||||
|
|
||||||
|
/* We listen for "invalidate" from the operation. Track the id here so
|
||||||
|
* we can disconnect when we drop an operation.
|
||||||
|
*/
|
||||||
|
gulong invalidate_id;
|
||||||
|
} VipsOperationCacheEntry;
|
||||||
|
|
||||||
/* Pass in the pspec so we can get the generic type. For example, a
|
/* Pass in the pspec so we can get the generic type. For example, a
|
||||||
* held in a GParamSpec allowing OBJECT, but the value could be of type
|
* held in a GParamSpec allowing OBJECT, but the value could be of type
|
||||||
* VipsImage. generics are much faster to compare.
|
* VipsImage. generics are much faster to compare.
|
||||||
@ -515,17 +529,90 @@ vips_cache_unref( VipsOperation *operation )
|
|||||||
g_object_unref( operation );
|
g_object_unref( operation );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop an operation from the cache.
|
/* Remove an operation from the cache.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
vips_cache_drop( VipsOperation *operation )
|
vips_cache_remove( VipsOperation *operation )
|
||||||
{
|
{
|
||||||
/* It must be in cache.
|
VipsOperationCacheEntry *entry = (VipsOperationCacheEntry *)
|
||||||
*/
|
g_hash_table_lookup( vips_cache_table, operation );
|
||||||
g_assert( g_hash_table_lookup( vips_cache_table, operation ) );
|
|
||||||
|
g_assert( entry );
|
||||||
|
|
||||||
g_hash_table_remove( vips_cache_table, operation );
|
g_hash_table_remove( vips_cache_table, operation );
|
||||||
vips_cache_unref( operation );
|
vips_cache_unref( operation );
|
||||||
|
|
||||||
|
if( entry->invalidate_id ) {
|
||||||
|
g_signal_handler_disconnect( operation, entry->invalidate_id );
|
||||||
|
entry->invalidate_id = 0;
|
||||||
|
}
|
||||||
|
g_free( entry );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
vips_object_ref_arg( VipsObject *object,
|
||||||
|
GParamSpec *pspec,
|
||||||
|
VipsArgumentClass *argument_class,
|
||||||
|
VipsArgumentInstance *argument_instance,
|
||||||
|
void *a, void *b )
|
||||||
|
{
|
||||||
|
if( (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
|
||||||
|
(argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
|
||||||
|
argument_instance->assigned &&
|
||||||
|
G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
|
||||||
|
GObject *value;
|
||||||
|
|
||||||
|
/* This will up the ref count for us.
|
||||||
|
*/
|
||||||
|
g_object_get( G_OBJECT( object ),
|
||||||
|
g_param_spec_get_name( pspec ), &value, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_operation_touch( VipsOperation *operation )
|
||||||
|
{
|
||||||
|
VipsOperationCacheEntry *entry = (VipsOperationCacheEntry *)
|
||||||
|
g_hash_table_lookup( vips_cache_table, operation );
|
||||||
|
|
||||||
|
vips_cache_time += 1;
|
||||||
|
entry->time = vips_cache_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ref an operation for the cache. The operation itself, plus all the output
|
||||||
|
* objects it makes.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
vips_cache_ref( VipsOperation *operation )
|
||||||
|
{
|
||||||
|
g_object_ref( operation );
|
||||||
|
(void) vips_argument_map( VIPS_OBJECT( operation ),
|
||||||
|
vips_object_ref_arg, NULL, NULL );
|
||||||
|
vips_operation_touch( operation );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_cache_insert( VipsOperation *operation )
|
||||||
|
{
|
||||||
|
VipsOperationCacheEntry *entry = g_new( VipsOperationCacheEntry, 1 );
|
||||||
|
|
||||||
|
/* It must not be in cache.
|
||||||
|
*/
|
||||||
|
g_assert( !g_hash_table_lookup( vips_cache_table, operation ) );
|
||||||
|
|
||||||
|
entry->operation = operation;
|
||||||
|
entry->time = 0;
|
||||||
|
entry->invalidate_id = 0;
|
||||||
|
|
||||||
|
g_hash_table_insert( vips_cache_table, operation, entry );
|
||||||
|
vips_cache_ref( operation );
|
||||||
|
|
||||||
|
/* If the operation signals "invalidate", we must drop it.
|
||||||
|
*/
|
||||||
|
entry->invalidate_id = g_signal_connect( operation, "invalidate",
|
||||||
|
G_CALLBACK( vips_cache_remove ), NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
@ -567,7 +654,7 @@ vips_cache_drop_all( void )
|
|||||||
* first item instead.
|
* first item instead.
|
||||||
*/
|
*/
|
||||||
while( (operation = vips_cache_get_first()) )
|
while( (operation = vips_cache_get_first()) )
|
||||||
vips_cache_drop( operation );
|
vips_cache_remove( operation );
|
||||||
|
|
||||||
VIPS_FREEF( g_hash_table_unref, vips_cache_table );
|
VIPS_FREEF( g_hash_table_unref, vips_cache_table );
|
||||||
}
|
}
|
||||||
@ -576,8 +663,8 @@ vips_cache_drop_all( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_cache_get_lru_cb( VipsOperation *key, VipsOperation *value,
|
vips_cache_get_lru_cb( VipsOperation *key, VipsOperationCacheEntry *value,
|
||||||
VipsOperation **best )
|
VipsOperationCacheEntry **best )
|
||||||
{
|
{
|
||||||
if( !*best ||
|
if( !*best ||
|
||||||
(*best)->time > value->time )
|
(*best)->time > value->time )
|
||||||
@ -591,13 +678,13 @@ vips_cache_get_lru_cb( VipsOperation *key, VipsOperation *value,
|
|||||||
static VipsOperation *
|
static VipsOperation *
|
||||||
vips_cache_get_lru( void )
|
vips_cache_get_lru( void )
|
||||||
{
|
{
|
||||||
VipsOperation *operation;
|
VipsOperationCacheEntry *entry;
|
||||||
|
|
||||||
operation = NULL;
|
entry = NULL;
|
||||||
g_hash_table_foreach( vips_cache_table,
|
g_hash_table_foreach( vips_cache_table,
|
||||||
(GHFunc) vips_cache_get_lru_cb, &operation );
|
(GHFunc) vips_cache_get_lru_cb, &entry );
|
||||||
|
|
||||||
return( operation );
|
return( entry->operation );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is the cache full? Drop until it's not.
|
/* Is the cache full? Drop until it's not.
|
||||||
@ -618,53 +705,12 @@ vips_cache_trim( void )
|
|||||||
printf( "vips_cache_trim: trimming %p\n", operation );
|
printf( "vips_cache_trim: trimming %p\n", operation );
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
vips_cache_drop( operation );
|
vips_cache_remove( operation );
|
||||||
}
|
}
|
||||||
|
|
||||||
g_mutex_unlock( vips_cache_lock );
|
g_mutex_unlock( vips_cache_lock );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
|
||||||
vips_object_ref_arg( VipsObject *object,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
VipsArgumentClass *argument_class,
|
|
||||||
VipsArgumentInstance *argument_instance,
|
|
||||||
void *a, void *b )
|
|
||||||
{
|
|
||||||
if( (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
|
|
||||||
(argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
|
|
||||||
argument_instance->assigned &&
|
|
||||||
G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
|
|
||||||
GObject *value;
|
|
||||||
|
|
||||||
/* This will up the ref count for us.
|
|
||||||
*/
|
|
||||||
g_object_get( G_OBJECT( object ),
|
|
||||||
g_param_spec_get_name( pspec ), &value, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
vips_operation_touch( VipsOperation *operation )
|
|
||||||
{
|
|
||||||
vips_cache_time += 1;
|
|
||||||
operation->time = vips_cache_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ref an operation for the cache. The operation itself, plus all the output
|
|
||||||
* objects it makes.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
vips_cache_ref( VipsOperation *operation )
|
|
||||||
{
|
|
||||||
g_object_ref( operation );
|
|
||||||
(void) vips_argument_map( VIPS_OBJECT( operation ),
|
|
||||||
vips_object_ref_arg, NULL, NULL );
|
|
||||||
vips_operation_touch( operation );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vips_cache_operation_buildp: (skip)
|
* vips_cache_operation_buildp: (skip)
|
||||||
* @operation: pointer to operation to lookup
|
* @operation: pointer to operation to lookup
|
||||||
@ -679,7 +725,7 @@ vips_cache_ref( VipsOperation *operation )
|
|||||||
int
|
int
|
||||||
vips_cache_operation_buildp( VipsOperation **operation )
|
vips_cache_operation_buildp( VipsOperation **operation )
|
||||||
{
|
{
|
||||||
VipsOperation *hit;
|
VipsOperationCacheEntry *hit;
|
||||||
|
|
||||||
g_assert( VIPS_IS_OPERATION( *operation ) );
|
g_assert( VIPS_IS_OPERATION( *operation ) );
|
||||||
|
|
||||||
@ -693,15 +739,15 @@ vips_cache_operation_buildp( VipsOperation **operation )
|
|||||||
if( (hit = g_hash_table_lookup( vips_cache_table, *operation )) ) {
|
if( (hit = g_hash_table_lookup( vips_cache_table, *operation )) ) {
|
||||||
if( vips__cache_trace ) {
|
if( vips__cache_trace ) {
|
||||||
printf( "vips cache-: " );
|
printf( "vips cache-: " );
|
||||||
vips_object_print_summary( VIPS_OBJECT( hit ) );
|
vips_object_print_summary( VIPS_OBJECT( *operation ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ref before unref in case *operation == hit.
|
/* Ref before unref in case *operation == hit.
|
||||||
*/
|
*/
|
||||||
vips_cache_ref( hit );
|
vips_cache_ref( hit->operation );
|
||||||
g_object_unref( *operation );
|
g_object_unref( *operation );
|
||||||
|
|
||||||
*operation = hit;
|
*operation = hit->operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_mutex_unlock( vips_cache_lock );
|
g_mutex_unlock( vips_cache_lock );
|
||||||
@ -724,11 +770,8 @@ vips_cache_operation_buildp( VipsOperation **operation )
|
|||||||
g_mutex_lock( vips_cache_lock );
|
g_mutex_lock( vips_cache_lock );
|
||||||
|
|
||||||
if( !(vips_operation_get_flags( *operation ) &
|
if( !(vips_operation_get_flags( *operation ) &
|
||||||
VIPS_OPERATION_NOCACHE) ) {
|
VIPS_OPERATION_NOCACHE) )
|
||||||
vips_cache_ref( *operation );
|
vips_cache_insert( *operation );
|
||||||
g_hash_table_insert( vips_cache_table,
|
|
||||||
*operation, *operation );
|
|
||||||
}
|
|
||||||
|
|
||||||
g_mutex_unlock( vips_cache_lock );
|
g_mutex_unlock( vips_cache_lock );
|
||||||
}
|
}
|
||||||
|
@ -439,8 +439,10 @@ vips_operation_class_print_usage( VipsOperationClass *operation_class )
|
|||||||
void
|
void
|
||||||
vips_operation_invalidate( VipsOperation *operation )
|
vips_operation_invalidate( VipsOperation *operation )
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
printf( "vips_operation_invalidate: %p\n", operation );
|
printf( "vips_operation_invalidate: %p\n", operation );
|
||||||
vips_object_print_summary( VIPS_OBJECT( operation ) );
|
vips_object_print_summary( VIPS_OBJECT( operation ) );
|
||||||
|
*/
|
||||||
|
|
||||||
g_signal_emit( operation, vips_operation_signals[SIG_INVALIDATE], 0 );
|
g_signal_emit( operation, vips_operation_signals[SIG_INVALIDATE], 0 );
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user