foreign uses the cache
This commit is contained in:
parent
30ec51699d
commit
5e037e4c68
@ -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
15
TODO
@ -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)
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 * );
|
||||
|
||||
|
@ -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 * );
|
||||
|
||||
|
@ -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, ... );
|
||||
|
@ -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
|
||||
if( vips__cache_print )
|
||||
vips_cache_print();
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
/* 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();
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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 );
|
||||
|
Loading…
x
Reference in New Issue
Block a user