foreign uses the cache

This commit is contained in:
John Cupitt 2011-12-02 13:15:05 +00:00
parent 30ec51699d
commit 5e037e4c68
11 changed files with 148 additions and 75 deletions

View File

@ -22,7 +22,7 @@
- VipsMin stops search early if it can
- C API supports optional output args
- switch back to int-valued operations
- add the operation cache
- add the operation cache, various --vips-cache-* flags
- fallback vips_init()
- vips_tracked_malloc() tracks allocation size and can report total mem usage
- cache limits, drop, init, flush plus command-line controls

15
TODO
View File

@ -1,13 +1,14 @@
- try:
- print_usage could show more about pspecs, eg. for "in" we have:
$ vips copy x.jpg x.v
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsCopy, in ) );
operation cache is printed twice ... once in atexit?
but only display:
jpegload is not added
operation object print is unhelpful, we want a list of args, not a usage
message
in :: VipsImage (input)

View File

@ -175,7 +175,7 @@ vips_remainder_class_init( VipsRemainderClass *class )
object_class->nickname = "remainder";
object_class->description =
_( "remainder after integer division for a pair of images" );
_( "remainder after integer division of two images" );
object_class->build = vips_remainder_build;
vips_arithmetic_set_format_table( aclass, vips_bandfmt_remainder );
@ -324,7 +324,7 @@ vips_remainder_const_class_init( VipsRemainderConstClass *class )
object_class->nickname = "remainder_const";
object_class->description =
_( "remainder after integer division for an image "
_( "remainder after integer division of an image "
"and a constant" );
object_class->build = vips_remainder_const_build;

View File

@ -80,6 +80,7 @@ extern char *vips__disc_threshold;
extern char *vips__cache_max;
extern char *vips__cache_max_mem;
extern char *vips__cache_max_files;
extern gboolean vips__cache_print;
typedef int (*im__fftproc_fn)( VipsImage *, VipsImage *, VipsImage * );

View File

@ -265,6 +265,10 @@ typedef void *(*VipsArgumentMapFn)( VipsObject *, GParamSpec *,
VipsArgumentClass *, VipsArgumentInstance *, void *a, void *b );
void *vips_argument_map( VipsObject *object,
VipsArgumentMapFn fn, void *a, void *b );
typedef void *(*VipsArgumentClassMapFn)( VipsObjectClass *, GParamSpec *,
VipsArgumentClass *, void *a, void *b );
void *vips_argument_class_map( VipsObjectClass *object_class,
VipsArgumentClassMapFn fn, void *a, void *b );
int vips_object_get_argument( VipsObject *object, const char *name,
GParamSpec **pspec,
VipsArgumentClass **argument_class,
@ -348,6 +352,7 @@ struct _VipsObjectClass {
int (*build)( VipsObject *object );
/* Try to print something about the class, handy for help displays.
* Keep to one line.
*/
void (*print_class)( struct _VipsObjectClass *, VipsBuf * );

View File

@ -69,10 +69,15 @@ typedef struct _VipsOperation {
typedef struct _VipsOperationClass {
VipsObjectClass parent_class;
/* Print the usage message.
*/
void (*print_usage)( struct _VipsOperationClass *, VipsBuf * );
} VipsOperationClass;
GType vips_operation_get_type( void );
void vips_operation_class_print_usage( VipsOperationClass *operation_class );
int vips_operation_call_valist( VipsOperation *operation, va_list ap );
VipsOperation *vips_operation_new( const char *name );
int vips_call( const char *operation_name, ... );

View File

@ -46,8 +46,8 @@
*/
/*
*/
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -71,6 +71,7 @@
char *vips__cache_max = NULL;
char *vips__cache_max_mem = NULL;
char *vips__cache_max_files = NULL;
gboolean vips__cache_print = FALSE;
/* Max number of cached operations.
*/
@ -409,7 +410,6 @@ vips_cache_init( void )
}
}
#ifdef VIPS_DEBUG
static void
vips_cache_print( void )
{
@ -419,11 +419,16 @@ vips_cache_print( void )
printf( "Operation cache:\n" );
g_hash_table_iter_init( &iter, vips_cache_table );
while( g_hash_table_iter_next( &iter, &key, &value ) )
vips_object_print( VIPS_OBJECT( key ) );
while( g_hash_table_iter_next( &iter, &key, &value ) ) {
char str[32768];
VipsBuf buf = VIPS_BUF_STATIC( str );
vips_object_to_string( VIPS_OBJECT( key ), &buf );
printf( "%p - %s\n", key, vips_buf_all( &buf ) );
}
}
}
#endif /*VIPS_DEBUG*/
static void *
vips_object_unref_arg( VipsObject *object,
@ -483,9 +488,8 @@ void
vips_cache_drop_all( void )
{
if( vips_cache_table ) {
#ifdef VIPS_DEBUG
vips_cache_print();
#endif /*VIPS_DEBUG*/
if( vips__cache_print )
vips_cache_print();
/* We can't modify the hash in the callback from
* g_hash_table_foreach() and friends. Repeatedly drop the
@ -501,6 +505,8 @@ vips_cache_drop_all( void )
vips_cache_drop( (VipsOperation *) key );
}
VIPS_FREEF( g_hash_table_unref, vips_cache_table );
}
}
@ -599,6 +605,8 @@ vips_cache_operation_build( VipsOperation **operation )
{
VipsOperation *hit;
g_assert( VIPS_IS_OPERATION( *operation ) );
VIPS_DEBUG_MSG( "vips_cache_operation_build: %p\n", *operation );
vips_cache_init();

View File

@ -395,6 +395,9 @@ static GOptionEntry option_entries[] = {
{ "vips-cache-max-files", 'l', 0,
G_OPTION_ARG_STRING, &vips__cache_max_files,
N_( "allow at most N open files" ), "N" },
{ "vips-cache-print", 'r', 0,
G_OPTION_ARG_NONE, &vips__cache_print,
N_( "print operation cache on exit" ), NULL },
{ NULL }
};

View File

@ -192,7 +192,7 @@ vips_object_build( VipsObject *object )
void
vips_object_print_class( VipsObjectClass *class )
{
char str[1000];
char str[2048];
VipsBuf buf = VIPS_BUF_STATIC( str );
class->print_class( class, &buf );
@ -204,13 +204,9 @@ vips_object_print( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
/* This is used for printing image headers, so we may need lots of
* space. See header.c.
*/
char str[32768];
char str[2048];
VipsBuf buf = VIPS_BUF_STATIC( str );
vips_object_print_class( class );
class->print( object, &buf );
printf( "%s\n", vips_buf_all( &buf ) );
}
@ -324,6 +320,37 @@ vips_argument_map( VipsObject *object,
return( NULL );
}
/* And loop over a class. Same as ^^, but with no VipsArgumentInstance.
*/
void *
vips_argument_class_map( VipsObjectClass *object_class,
VipsArgumentClassMapFn fn, void *a, void *b )
{
GSList *p;
for( p = object_class->argument_table_traverse; p; p = p->next ) {
VipsArgumentClass *arg_class =
(VipsArgumentClass *) p->data;
VipsArgument *argument = (VipsArgument *) arg_class;
GParamSpec *pspec = argument->pspec;
/* We have many props on the arg table ... filter out the
* ones for this class.
*/
if( g_object_class_find_property(
G_OBJECT_CLASS( object_class ),
g_param_spec_get_name( pspec ) ) == pspec ) {
void *result;
if( (result =
fn( object_class, pspec, arg_class, a, b )) )
return( result );
}
}
return( NULL );
}
/* Create a VipsArgumentInstance for each installed argument property. Ideally
* we'd do this during _init() but g_object_class_find_property() does not seem
* to work then :-( so we have to delay it until first access. See
@ -1244,14 +1271,15 @@ vips_object_set_argument_from_string( VipsObject *object,
VipsObject *new_object;
VipsImage *out;
/* Use VipsFile to build images, then pull @out from it and
/* Use VipsForeign to build images, then pull @out from it and
* use that to set the value.
*/
if( !(new_object =
vips_object_new_from_string( oclass, value )) )
return( -1 );
if( vips_object_build( new_object ) ) {
if( vips_cache_operation_build(
(VipsOperation **) &new_object ) ) {
g_object_unref( new_object );
return( -1 );
}
@ -1283,6 +1311,9 @@ vips_object_set_argument_from_string( VipsObject *object,
vips_object_new_from_string( oclass, value )) )
return( -1 );
/* Not necessarily a VipsOperation subclass so we don't use
* the cache. We could have a separate case for this.
*/
if( vips_object_build( new_object ) ) {
g_object_unref( new_object );
return( -1 );
@ -1430,7 +1461,7 @@ vips_object_get_argument_to_string( VipsObject *object,
VipsObject *new_object;
VipsImage *in;
/* Use VipsFile to make a saver, set 'in' on that and run
/* Use VipsForeign to make a saver, set 'in' on that and run
* build to make it write.
*/
if( !(new_object =
@ -1441,7 +1472,8 @@ vips_object_get_argument_to_string( VipsObject *object,
g_object_set( new_object, "in", in, NULL );
g_object_unref( in );
if( vips_object_build( new_object ) ) {
if( vips_cache_operation_build(
(VipsOperation **) &new_object ) ) {
g_object_unref( new_object );
return( -1 );
}

View File

@ -74,13 +74,12 @@ typedef struct {
gboolean required; /* show required args or optional */
gboolean oftype; /* "is of type" message */
int n; /* Arg number */
} VipsOperationPrint;
} VipsOperationClassPrint;
static void *
vips_operation_print_arg( VipsObject *object, GParamSpec *pspec,
VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance,
VipsBuf *buf, VipsOperationPrint *print )
vips_operation_class_print_arg( VipsObjectClass *object_class,
GParamSpec *pspec, VipsArgumentClass *argument_class,
VipsBuf *buf, VipsOperationClassPrint *print )
{
/* Only show construct args ... others are internal.
*/
@ -109,6 +108,46 @@ vips_operation_print_arg( VipsObject *object, GParamSpec *pspec,
return( NULL );
}
static void
vips_operation_print_usage( VipsOperationClass *class, VipsBuf *buf )
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
VipsOperationClassPrint print;
/* First pass through args: show the required names.
*/
vips_buf_appendf( buf, " %s ", object_class->nickname );
print.message = NULL;
print.required = TRUE;
print.oftype = FALSE;
print.n = 0;
vips_argument_class_map( object_class,
(VipsArgumentClassMapFn) vips_operation_class_print_arg,
buf, &print );
vips_buf_appends( buf, "\n" );
/* Show required types.
*/
print.message = "where:";
print.required = TRUE;
print.oftype = TRUE;
print.n = 0;
vips_argument_class_map( object_class,
(VipsArgumentClassMapFn) vips_operation_class_print_arg,
buf, &print );
/* Show optional args.
*/
print.message = "optional arguments:";
print.required = FALSE;
print.oftype = TRUE;
print.n = 0;
vips_argument_class_map( object_class,
(VipsArgumentClassMapFn) vips_operation_class_print_arg,
buf, &print );
}
#ifdef VIPS_DEBUG
static void *
vips_operation_call_argument( VipsObject *object, GParamSpec *pspec,
@ -137,53 +176,16 @@ vips_operation_call_argument( VipsObject *object, GParamSpec *pspec,
static void
vips_operation_print( VipsObject *object, VipsBuf *buf )
{
#ifdef VIPS_DEBUG
VipsOperation *operation = VIPS_OPERATION( object );
VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
VipsOperationPrint print;
#ifdef VIPS_DEBUG
printf( "%s args:\n", object_class->nickname );
vips_argument_map( VIPS_OBJECT( operation ),
(VipsArgumentMapFn) vips_operation_call_argument, NULL, NULL );
#endif /*VIPS_DEBUG*/
/* First pass through args: show the required names.
*/
vips_buf_appendf( buf, " %s ", object_class->nickname );
print.message = NULL;
print.required = TRUE;
print.oftype = FALSE;
print.n = 0;
vips_argument_map( VIPS_OBJECT( operation ),
(VipsArgumentMapFn) vips_operation_print_arg, buf, &print );
vips_buf_appends( buf, "\n" );
/* Show required types.
*/
print.message = "where:";
print.required = TRUE;
print.oftype = TRUE;
print.n = 0;
vips_argument_map( VIPS_OBJECT( operation ),
(VipsArgumentMapFn) vips_operation_print_arg, buf, &print );
/* Show optional args.
*/
print.message = "optional arguments:";
print.required = FALSE;
print.oftype = TRUE;
print.n = 0;
vips_argument_map( VIPS_OBJECT( operation ),
(VipsArgumentMapFn) vips_operation_print_arg, buf, &print );
}
static int
vips_operation_build( VipsObject *object )
{
if( VIPS_OBJECT_CLASS( vips_operation_parent_class )->build( object ) )
return( -1 );
return( 0 );
VIPS_OBJECT_CLASS( vips_operation_parent_class )->print( object, buf );
}
static void
@ -196,9 +198,10 @@ vips_operation_class_init( VipsOperationClass *class )
gobject_class->dispose = vips_operation_dispose;
vobject_class->nickname = "operation";
vobject_class->description = _( "VIPS operations" );
vobject_class->description = _( "operations" );
vobject_class->print = vips_operation_print;
vobject_class->build = vips_operation_build;
class->print_usage = vips_operation_print_usage;
}
static void
@ -208,6 +211,17 @@ vips_operation_init( VipsOperation *operation )
*/
}
void
vips_operation_class_print_usage( VipsOperationClass *operation_class )
{
char str[2048];
VipsBuf buf = VIPS_BUF_STATIC( str );
operation_class->print_usage( operation_class, &buf );
printf( "%s", _( "usage:" ) );
printf( "\n%s", vips_buf_all( &buf ) );
}
VipsOperation *
vips_operation_new( const char *name )
{
@ -896,6 +910,9 @@ vips_call_argv( VipsOperation *operation, int argc, char **argv )
return( -1 );
}
/* We can't use the operation cache, we need to be able to change the
* operation pointer. The cache probably wouldn't help anyway.
*/
if( vips_object_build( VIPS_OBJECT( operation ) ) )
return( -1 );

View File

@ -1073,7 +1073,8 @@ main( int argc, char **argv )
if( vips_call_argv( operation, argc - 1, argv + 1 ) ) {
if( argc == 1 )
vips_object_print( VIPS_OBJECT( operation ) );
vips_operation_class_print_usage(
VIPS_OPERATION_GET_CLASS( operation ) );
vips_object_unref_outputs( VIPS_OBJECT( operation ) );
g_object_unref( operation );