operation cache working

but see notes in file
This commit is contained in:
John Cupitt 2011-09-10 14:38:39 +01:00
parent 5d1accfc83
commit f9b8e0d88f
2 changed files with 85 additions and 40 deletions

View File

@ -31,16 +31,19 @@
TODO TODO
vips_object_build() needs a new type ... should return the
VipsObject it makes
should the cache be thread-private? or lock? or say operations can should the cache be thread-private? or lock? or say operations can
only be made from the main thread? only be made from the main thread?
only cache operation_new()? (this is what we do now)
listen for invalidate listen for invalidate
keep operations alive? at the moment
vips_min( im, &d, NULL );
will never get cached since it produces no persistent output ... we'd
need to keep a ref to the operation in the cache and only drop after a
few seconds or if we have more than 10,000 cached operations
*/ */
/* /*
@ -74,10 +77,14 @@
static GHashTable *vips_object_cache = NULL; static GHashTable *vips_object_cache = NULL;
/* generic is the general type of the value. For example, the value could be
* held in a GParamSpec allowing OBJECT, but the value could be of type
* VipsImage. generics are much faster to compare.
*/
static unsigned int static unsigned int
vips_value_hash( GValue *value ) vips_value_hash( GType generic, GValue *value )
{ {
switch( G_VALUE_TYPE( value ) ) { switch( generic ) {
case G_TYPE_BOOLEAN: case G_TYPE_BOOLEAN:
return( (unsigned int) g_value_get_boolean( value ) ); return( (unsigned int) g_value_get_boolean( value ) );
case G_TYPE_CHAR: case G_TYPE_CHAR:
@ -144,25 +151,44 @@ vips_value_hash( GValue *value )
default: default:
{ {
/* Fallback: convert to a string and hash that. This is very /* These GTypes are not compile-time constants and need to be
* slow, print a warning if we use it so we can add another * in ifs.
* case.
*/ */
char *s; if( generic == VIPS_TYPE_IMAGE )
unsigned int hash; return( g_direct_hash( g_value_get_object( value ) ) );
else {
/* Fallback: convert to a string and hash that.
* This is very slow, print a warning if we use it
* so we can add another case.
*/
char *s;
unsigned int hash;
s = g_strdup_value_contents( value ); s = g_strdup_value_contents( value );
hash = g_str_hash( s ); hash = g_str_hash( s );
printf( "vips_value_hash: no case for %s\n", s );
g_free( s );
return( hash ); printf( "vips_value_hash: no case for %s\n", s );
printf( "\ttype %d, %s\n",
(int) G_VALUE_TYPE( value ),
g_type_name( G_VALUE_TYPE( value ) ) );
printf( "\tgeneric %d, %s\n",
(int) G_VALUE_TYPE( generic ),
g_type_name( generic ) );
g_free( s );
return( hash );
}
} }
} }
} }
/* generic is the general type of the value. For example, the value could be
* held in a GParamSpec allowing OBJECT, but the value could be of type
* VipsImage. generics are much faster to compare.
*/
static gboolean static gboolean
vips_value_equal( GValue *v1, GValue *v2 ) vips_value_equal( GType generic, GValue *v1, GValue *v2 )
{ {
GType t1 = G_VALUE_TYPE( v1 ); GType t1 = G_VALUE_TYPE( v1 );
GType t2 = G_VALUE_TYPE( v2 ); GType t2 = G_VALUE_TYPE( v2 );
@ -225,21 +251,38 @@ vips_value_equal( GValue *v1, GValue *v2 )
default: default:
{ {
/* Fallback: convert to a string and hash that. This is very /* These GTypes are not compile-time constants and need to be
* slow, print a warning if we use it so we can add another * in ifs.
* case.
*/ */
char *s1; if( generic == VIPS_TYPE_IMAGE )
char *s2; return( g_value_get_object( v1 ) ==
gboolean equal; g_value_get_object( v2 ) );
else {
/* Fallback: convert to a string and compare that.
* This is very slow, print a warning if we use it
* so we can add another case.
*/
char *s1;
char *s2;
gboolean equal;
s1 = g_strdup_value_contents( v1 ); s1 = g_strdup_value_contents( v1 );
s2 = g_strdup_value_contents( v2 ); s2 = g_strdup_value_contents( v2 );
equal = strcmp( s1, s2 ) == 0; equal = strcmp( s1, s2 ) == 0;
g_free( s1 );
g_free( s2 );
return( equal ); printf( "vips_value_equal: no case for %s, %s\n",
s1, s2 );
printf( "\tt1 %d, %s\n", (int) t1, g_type_name( t1 ) );
printf( "\tt2 %d, %s\n", (int) t2, g_type_name( t2 ) );
printf( "\tgeneric %d, %s\n",
(int) G_VALUE_TYPE( generic ),
g_type_name( generic ) );
g_free( s1 );
g_free( s2 );
return( equal );
}
} }
} }
} }
@ -262,7 +305,7 @@ vips_object_hash_arg( VipsObject *object,
g_value_init( &value, type ); g_value_init( &value, type );
g_object_get_property( G_OBJECT( object ), g_object_get_property( G_OBJECT( object ),
g_param_spec_get_name( pspec ), &value ); g_param_spec_get_name( pspec ), &value );
*hash = (*hash << 1) ^ vips_value_hash( &value ); *hash = (*hash << 1) ^ vips_value_hash( type, &value );
g_value_unset( &value ); g_value_unset( &value );
} }
@ -318,7 +361,7 @@ vips_object_equal_arg( VipsObject *object,
g_value_init( &v2, type ); g_value_init( &v2, type );
g_object_get_property( G_OBJECT( object ), name, &v1 ); g_object_get_property( G_OBJECT( object ), name, &v1 );
g_object_get_property( G_OBJECT( other ), name, &v2 ); g_object_get_property( G_OBJECT( other ), name, &v2 );
equal = vips_value_equal( &v1, &v2 ); equal = vips_value_equal( type, &v1, &v2 );
g_value_unset( &v1 ); g_value_unset( &v1 );
g_value_unset( &v2 ); g_value_unset( &v2 );

View File

@ -469,8 +469,10 @@ vips_operation_get_valist_optional( VipsOperation *operation, va_list ap )
return( 0 ); return( 0 );
} }
/* This can change operation to point at an old, cached one.
*/
static int static int
vips_call_required_optional( VipsOperation *operation, vips_call_required_optional( VipsOperation **operation,
va_list required, va_list optional ) va_list required, va_list optional )
{ {
int result; int result;
@ -483,22 +485,22 @@ vips_call_required_optional( VipsOperation *operation,
*/ */
va_copy( a, required ); va_copy( a, required );
va_copy( b, optional ); va_copy( b, optional );
result = vips_operation_set_valist_required( operation, a ) || result = vips_operation_set_valist_required( *operation, a ) ||
vips_operation_set_valist_optional( operation, b ); vips_operation_set_valist_optional( *operation, b );
va_end( a ); va_end( a );
va_end( b ); va_end( b );
/* Build from cache. /* Build from cache.
*/ */
if( vips_object_build_cache( (VipsObject **) &operation ) ) if( vips_object_build_cache( (VipsObject **) operation ) )
return( -1 ); return( -1 );
/* Walk args again, writing output. /* Walk args again, writing output.
*/ */
va_copy( a, required ); va_copy( a, required );
va_copy( b, optional ); va_copy( b, optional );
result = vips_operation_get_valist_required( operation, required ) || result = vips_operation_get_valist_required( *operation, required ) ||
vips_operation_get_valist_optional( operation, optional ); vips_operation_get_valist_optional( *operation, optional );
va_end( a ); va_end( a );
va_end( b ); va_end( b );
@ -548,7 +550,7 @@ vips_call( const char *operation_name, ... )
} }
} VIPS_ARGUMENT_FOR_ALL_END } VIPS_ARGUMENT_FOR_ALL_END
result = vips_call_required_optional( operation, required, optional ); result = vips_call_required_optional( &operation, required, optional );
va_end( required ); va_end( required );
va_end( optional ); va_end( optional );
@ -589,7 +591,7 @@ vips_call_split( const char *operation_name, va_list optional, ... )
#endif /*VIPS_DEBUG*/ #endif /*VIPS_DEBUG*/
va_start( required, optional ); va_start( required, optional );
result = vips_call_required_optional( operation, required, optional ); result = vips_call_required_optional( &operation, required, optional );
va_end( required ); va_end( required );
/* Build failed: junk args and back out. /* Build failed: junk args and back out.