add VIPS_DEBUG_MSG

This commit is contained in:
John Cupitt 2010-04-06 09:02:26 +00:00
parent cd9bdf48c0
commit 5b00c86bab
7 changed files with 337 additions and 23 deletions

View File

@ -9,6 +9,8 @@
- added im_mpercent_hist()
- im_maplut() casts the index image to one of the uint types
- fixed a couple of /0 problems with scale == 0 masks
- set G_LOG_DOMAIN to VIPS so we can use g_warning etc.
- added VIPS_DEBUG_MSG() macro
16/1/10 started 7.21.2
- "invalidate" is careful to keep images alive, so invalidate callbacks can do

18
TODO
View File

@ -1,4 +1,22 @@
- how about
#define VIPS_DEBUG_MSG( STR ) printf( ...)
nicer than lots of #ifdef DEBUG ...
- vips_sink() needs to be able to supply a thread start / stop function
it needs to be able to start and stop sequences, and to guarantee that stops
get called in all paths
for example, if one thread sets stop in allocate, not all threads will get
to run again, they can be shut down by vips_threadpool first
- look at moving im_iterate() to thereadpool
split im_render into two parts: the asynch tile renderer, and the thing to

View File

@ -42,6 +42,8 @@ AC_SUBST(LIBRARY_AGE)
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED(G_LOG_DOMAIN, "VIPS", [Domain for glib logging messages.])
AC_MSG_CHECKING([for native Win32])
case "$host" in
*-*-mingw*)

View File

@ -34,6 +34,30 @@
extern "C" {
#endif /*__cplusplus*/
#ifdef VIPS_DEBUG
#define VIPS_DEBUG_MSG( FMT, ... ) printf( FMT, __VA_ARGS__ )
#else
#define VIPS_DEBUG_MSG( FMT, ... )
#endif /*VIPS_DEBUG*/
#ifdef VIPS_DEBUG_RED
#define VIPS_DEBUG_MSG_RED( FMT, ... ) printf( "red: " FMT, __VA_ARGS__ )
#else
#define VIPS_DEBUG_MSG_RED( FMT, ... )
#endif /*VIPS_DEBUG_RED*/
#ifdef VIPS_DEBUG_AMBER
#define VIPS_DEBUG_MSG_AMBER( FMT, ... ) printf( "amber: " FMT, __VA_ARGS__ )
#else
#define VIPS_DEBUG_MSG_AMBER( FMT, ... )
#endif /*VIPS_DEBUG_AMBER*/
#ifdef VIPS_DEBUG_GREEN
#define VIPS_DEBUG_MSG_GREEN( FMT, ... ) printf( "green: " FMT, __VA_ARGS__ )
#else
#define VIPS_DEBUG_MSG_GREEN( FMT, ... )
#endif /*VIPS_DEBUG_GREEN*/
/* All open image descriptors ... see im_init() and im_close().
*/
extern GSList *im__open_images;

View File

@ -51,7 +51,7 @@ typedef struct _VipsThreadState {
*/
REGION *reg;
/* The rest are neither used nor set, do what you lke with them.
/* The rest are neither used nor set, do what you like with them.
*/
Rect pos;
int x, y;

280
libvips/iofuncs/sink.c Normal file
View File

@ -0,0 +1,280 @@
/* A sink that's not attached to anything, eg. find image average,
*
* 28/3/10
* - from im_iterate(), reworked for threadpool
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/thread.h>
#include <vips/internal.h>
#include <vips/debug.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* Per-call state.
*/
typedef struct _Sink {
VipsImage *im;
/* We need a temp "p" image between the source image and us to
* make sure we can't damage the original.
*/
VipsImage *t;
/* The position we're at in the image.
*/
int x;
int y;
/* The tilesize we've picked.
*/
int tile_width;
int tile_height;
int nlines;
/* Keep the sequence value in VipsThreadState->d.
*/
im_start_fn start;
im_generate_fn generate;
im_stop_fn stop;
void *a;
void *b;
} Sink;
static void
sink_free( Sink *sink )
{
IM_FREEF( im_close, sink->t );
}
static int
sink_init( Sink *sink,
VipsImage *im,
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
void *a, void *b )
{
sink->im = im;
sink->t = NULL;
sink->start = start;
sink->generate = generate;
sink->stop = stop;
sink->a = a;
sink->b = b;
if( !(sink->t = im_open( "iterate", "p" )) ||
im_copy( sink->im, sink->t ) ) {
sink_free( sink );
return( -1 );
}
vips_get_tile_size( im,
&sink->tile_width, &sink->tile_height, &sink->nlines );
return( 0 );
}
/* Call the start function for this thread, if necessary.
*/
static int
sink_call_start( Sink *sink, VipsThreadState *state )
{
if( !state->d && sink->start ) {
#ifdef DEBUG
printf( "sink_call_start: state = %p\n", state );
#endif /*DEBUG*/
state->d = sink->start( sink->t, sink->a, sink->b );
if( !state->d ) {
im_error( "vips_sink",
_( "start function failed for image \"%s\"" ),
sink->im->filename );
return( -1 );
}
}
return( 0 );
}
/* Call a thread's stop function.
*/
static int
sink_call_stop( Sink *sink, VipsThreadState *state )
{
if( state->d && sink->stop ) {
#ifdef DEBUG
printf( "sink_call_stop: state = %p\n", state );
#endif /*DEBUG*/
if( sink->stop( state->d, sink->a, sink->b ) ) {
im_error( "vips_sink",
_( "stop function failed for image \"%s\"" ),
sink->im->filename );
return( -1 );
}
state->d = NULL;
}
return( 0 );
}
static int
sink_allocate( VipsThreadState *state,
void *a, void *b, void *c, gboolean *stop )
{
Sink *sink = (Sink *) a;
Rect image, tile;
/* Is the state x/y OK? New line or maybe all done.
*/
if( sink->x >= sink->im->Xsize ) {
sink->x = 0;
sink->y += sink->tile_height;
if( sink->y >= sink->im->Ysize ) {
sink_call_stop( sink, state );
*stop = TRUE;
return( 0 );
}
}
sink_call_start( sink, state );
/* x, y and buf are good: save params for thread.
*/
image.left = 0;
image.top = 0;
image.width = sink->im->Xsize;
image.height = sink->im->Ysize;
tile.left = sink->x;
tile.top = sink->y;
tile.width = sink->tile_width;
tile.height = sink->tile_height;
im_rect_intersectrect( &image, &tile, &state->pos );
/* Move state on.
*/
write->x += write->tile_width;
return( 0 );
}
static int
sink_work( VipsThreadState *state, void *a, void *b, void *c )
{
Sink *sink = (Sink *) a;
if( im_prepare( state->reg, &state->pos ) ||
sink->generate( state->reg, state->d, sink->a, sink->b ) ) {
sink_call_stop( sink, state );
return( -1 );
}
return( 0 );
}
static int
sink_progress( void *a, void *b, void *c )
{
Sink *sink = (Sink *) a;
/* Trigger any eval callbacks on our source image and
* check for errors.
*/
if( im__handle_eval( sink->im,
sink->tile_width, sink->tile_height ) )
return( -1 );
return( 0 );
}
/**
* vips_sink:
* @im: scan over this image
* @start: start sequences with this function
* @generate: generate pixels with this function
* @stop: stop sequences with this function
* @a: user data
* @b: user data
*
* Loops over an image. @generate is called for every pixel in the image, with
* the @reg argument being a region of pixels for processing. im_iterate() is
* used to implement operations like im_avg() which have no image output.
*
* See also: im_generate(), im_open().
*
* Returns: 0 on success, or -1 on error.
*/
int
vips_sink( VipsImage *im,
VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b )
{
Sink sink;
int result;
g_assert( !im_image_sanity( im ) );
/* We don't use this, but make sure it's set in case any old binaries
* are expecting it.
*/
im->Bbits = im_bits_of_fmt( im->BandFmt );
if( sink_init( &sink, im, start, generate, stop, a, b ) )
return( -1 );
if( im__start_eval( sink.t ) ) {
sink_free( &sink );
return( -1 );
}
result = vips_threadpool_run( im,
sink_allocate, sink_work, sink_progress, &sink, NULL );
im__end_eval( sink.t );
sink_free( &sink );
return( result );
}

View File

@ -37,8 +37,8 @@
/*
#define TIME_THREAD
#define DEBUG_CREATE
#define DEBUG_IO
#define VIPS_DEBUG_RED
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
@ -56,6 +56,7 @@
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/thread.h>
#include <vips/debug.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
@ -186,10 +187,7 @@ vips_thread_free( VipsThread *thr )
/* Return value is always NULL (see thread_main_loop).
*/
(void) g_thread_join( thr->thread );
#ifdef DEBUG_CREATE
printf( "thread_free: g_thread_join()\n" );
#endif /*DEBUG_CREATE*/
VIPS_DEBUG_MSG_RED( "thread_free: g_thread_join()\n" );
thr->thread = NULL;
}
@ -342,9 +340,7 @@ vips_thread_new( VipsThreadpool *pool )
return( NULL );
}
#ifdef DEBUG_CREATE
printf( "vips_thread_new: g_thread_create_full()\n" );
#endif /*DEBUG_CREATE*/
VIPS_DEBUG_MSG_RED( "vips_thread_new: g_thread_create_full()\n" );
#endif /*HAVE_THREADS*/
return( thr );
@ -362,20 +358,16 @@ vips_threadpool_kill_threads( VipsThreadpool *pool )
vips_thread_free( pool->thr[i] );
pool->thr = NULL;
#ifdef DEBUG_IO
printf( "vips_threadpool_kill_threads: killed %d threads\n",
pool->nthr );
#endif /*DEBUG_IO*/
VIPS_DEBUG_MSG( "vips_threadpool_kill_threads: "
"killed %d threads\n", pool->nthr );
}
}
static int
vips_threadpool_free( VipsThreadpool *pool )
{
#ifdef DEBUG_IO
printf( "vips_threadpool_free: \"%s\" (%p)\n",
VIPS_DEBUG_MSG( "vips_threadpool_free: \"%s\" (%p)\n",
pool->im->filename, pool );
#endif /*DEBUG_IO*/
vips_threadpool_kill_threads( pool );
IM_FREEF( g_mutex_free, pool->allocate_lock );
@ -413,10 +405,8 @@ vips_threadpool_new( VipsImage *im )
return( NULL );
}
#ifdef DEBUG_IO
printf( "vips_threadpool_new: \"%s\" (%p), with %d threads\n",
VIPS_DEBUG_MSG( "vips_threadpool_new: \"%s\" (%p), with %d threads\n",
im->filename, pool, pool->nthr );
#endif /*DEBUG_IO*/
return( pool );
}
@ -668,10 +658,8 @@ vips_get_tile_size( VipsImage *im,
*/
g_assert( *nlines % *tile_height == 0 );
#ifdef DEBUG_IO
printf( "vips_get_tile_size: %d by %d patches, "
VIPS_DEBUG_MSG( "vips_get_tile_size: %d by %d patches, "
"groups of %d scanlines\n",
*tile_width, *tile_height, *nlines );
#endif /*DEBUG_IO*/
}