From a5058059abe0fbf691227e9242565939e71f5a0c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Cl=C3=A9ment=20Stenac?= Date: Thu, 12 Jan 2006 21:21:36 +0000 Subject: [PATCH] Support for moving averages (Refs:#473) Get input bitrate --- include/vlc_messages.h | 26 ++++++- include/vlc_symbols.h | 4 ++ src/input/input.c | 5 ++ src/input/stream.c | 11 ++- src/misc/stats.c | 146 +++++++++++++++++++++++++++++++++++----- src/playlist/playlist.c | 10 ++- 6 files changed, 181 insertions(+), 21 deletions(-) diff --git a/include/vlc_messages.h b/include/vlc_messages.h index 4027fa510e..bbe3ff5076 100644 --- a/include/vlc_messages.h +++ b/include/vlc_messages.h @@ -229,6 +229,9 @@ struct counter_t int i_type; int i_samples; counter_sample_t ** pp_samples; + + mtime_t update_interval; + mtime_t last_update; }; struct stats_handler_t @@ -245,6 +248,8 @@ VLC_EXPORT( int, __stats_Update, (vlc_object_t*, char *, vlc_value_t) ); VLC_EXPORT( int, __stats_Create, (vlc_object_t*, char *, int, int) ); #define stats_Get( a,b,c,d ) __stats_Create( VLC_OBJECT(a), b, c, d ) VLC_EXPORT( int, __stats_Get, (vlc_object_t*, int, char *, vlc_value_t*) ); +#define stats_CounterGet( a,b,c) __stats_CounterGet( VLC_OBJECT(a), b, c ) +VLC_EXPORT( counter_t*, __stats_CounterGet, (vlc_object_t*, int, char * ) ); #define stats_GetInteger( a,b,c,d ) __stats_GetInteger( VLC_OBJECT(a), b, c, d ) static inline int __stats_GetInteger( vlc_object_t *p_obj, int i_id, @@ -256,6 +261,15 @@ static inline int __stats_GetInteger( vlc_object_t *p_obj, int i_id, return i_ret; } +#define stats_GetFloat(a,b,c,d ) __stats_GetFloat( VLC_OBJECT(a), b, c, d ) +static inline int __stats_GetFloat( vlc_object_t *p_obj, int i_id, + char *psz_name, float *value ) +{ + vlc_value_t val; + int i_ret = __stats_Get( p_obj, i_id, psz_name, &val ); + *value = val.f_float; + return i_ret; +} #define stats_UpdateInteger( a,b,c ) __stats_UpdateInteger( VLC_OBJECT(a),b,c ) static inline int __stats_UpdateInteger( vlc_object_t *p_obj, char *psz_name, int i ) @@ -264,7 +278,14 @@ static inline int __stats_UpdateInteger( vlc_object_t *p_obj, char *psz_name, val.i_int = i; return __stats_Update( p_obj, psz_name, val ); } - +#define stats_UpdateFloat( a,b,c ) __stats_UpdateFloat( VLC_OBJECT(a),b,c ) +static inline int __stats_UpdateFloat( vlc_object_t *p_obj, char *psz_name, + float f ) +{ + vlc_value_t val; + val.f_float = f; + return __stats_Update( p_obj, psz_name, val ); +} struct input_stats_t { @@ -275,7 +296,8 @@ struct input_stats_t int i_read_packets; int i_read_bytes; - float f_last_bitrate; + float f_bitrate; + float f_average_bitrate; /* Decoders */ diff --git a/include/vlc_symbols.h b/include/vlc_symbols.h index 97f7c433cf..b3ba93ab3b 100644 --- a/include/vlc_symbols.h +++ b/include/vlc_symbols.h @@ -145,6 +145,7 @@ int vlc_getnameinfo (const struct sockaddr *, int, char *, int, int *, int); int vlm_ExecuteCommand (vlm_t *, const char *, vlm_message_t **); char * config_GetUserDir (void); httpd_stream_t * httpd_StreamNew (httpd_host_t *, const char *psz_url, const char *psz_mime, const char *psz_user, const char *psz_password, const vlc_acl_t *p_acl); +int __stats_CounterGet (vlc_object_t*, int, char *); int __config_GetType (vlc_object_t *, const char *); void __vlc_thread_ready (vlc_object_t *); int playlist_Export (playlist_t *, const char *, const char *); @@ -881,6 +882,7 @@ struct module_symbols_t void (*stats_ComputeInputStats_inner) (input_thread_t*, input_stats_t*); void (*stats_DumpInputStats_inner) (input_stats_t *); void (*stats_ReinitInputStats_inner) (input_stats_t *); + int (*__stats_CounterGet_inner) (vlc_object_t*, int, char *); }; # if defined (__PLUGIN__) # define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner @@ -1307,6 +1309,7 @@ struct module_symbols_t # define stats_ComputeInputStats (p_symbols)->stats_ComputeInputStats_inner # define stats_DumpInputStats (p_symbols)->stats_DumpInputStats_inner # define stats_ReinitInputStats (p_symbols)->stats_ReinitInputStats_inner +# define __stats_CounterGet (p_symbols)->__stats_CounterGet_inner # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__) /****************************************************************** * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access. @@ -1736,6 +1739,7 @@ struct module_symbols_t ((p_symbols)->stats_ComputeInputStats_inner) = stats_ComputeInputStats; \ ((p_symbols)->stats_DumpInputStats_inner) = stats_DumpInputStats; \ ((p_symbols)->stats_ReinitInputStats_inner) = stats_ReinitInputStats; \ + ((p_symbols)->__stats_CounterGet_inner) = __stats_CounterGet; \ (p_symbols)->net_ConvertIPv4_deprecated = NULL; \ # endif /* __PLUGIN__ */ diff --git a/src/input/input.c b/src/input/input.c index c34104dbe8..8a7696252d 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -674,10 +674,15 @@ static int Init( input_thread_t * p_input, vlc_bool_t b_quick ) */ if( !b_quick ) { + counter_t *p_counter; stats_Create( p_input, "read_bytes", VLC_VAR_INTEGER, STATS_COUNTER ); stats_Create( p_input, "read_packets", VLC_VAR_INTEGER, STATS_COUNTER ); stats_Create( p_input, "input_bitrate", VLC_VAR_FLOAT, STATS_DERIVATIVE ); + p_counter = stats_CounterGet( p_input, p_input->i_object_id, + "input_bitrate" ); + if( p_counter ) p_counter->update_interval = 1000000; + psz = var_GetString( p_input, "sout" ); if( *psz && strncasecmp( p_input->input.p_item->psz_uri, "vlc:", 4 ) ) { diff --git a/src/input/stream.c b/src/input/stream.c index c3bec91be2..620ce36a23 100644 --- a/src/input/stream.c +++ b/src/input/stream.c @@ -1565,12 +1565,16 @@ static int AReadStream( stream_t *s, void *p_read, int i_read ) stream_sys_t *p_sys = s->p_sys; access_t *p_access = p_sys->p_access; int i_read_orig = i_read; + int i_total; if( !p_sys->i_list ) { i_read = p_access->pf_read( p_access, p_read, i_read ); stats_UpdateInteger( s->p_parent->p_parent , "read_bytes", i_read ); - stats_UpdateInteger( s->p_parent->p_parent , "input_bitrate", i_read ); + stats_GetInteger( s, s->p_parent->p_parent->i_object_id, + "read_bytes", &i_total ); + stats_UpdateFloat( s->p_parent->p_parent , "input_bitrate", + (float)i_total ); stats_UpdateInteger( s->p_parent->p_parent , "read_packets", 1 ); return i_read; } @@ -1601,7 +1605,10 @@ static int AReadStream( stream_t *s, void *p_read, int i_read ) /* Update read bytes in input */ stats_UpdateInteger( s->p_parent->p_parent , "read_bytes", i_read ); - stats_UpdateInteger( s->p_parent->p_parent , "input_bitrate", i_read ); + stats_GetInteger( s, s->p_parent->p_parent->i_object_id, + "read_bytes", &i_total ); + stats_UpdateFloat( s->p_parent->p_parent , "input_bitrate", + (float)i_total ); stats_UpdateInteger( s->p_parent->p_parent , "read_packets", 1 ); return i_read; } diff --git a/src/misc/stats.c b/src/misc/stats.c index d88ef18e1c..6f2d33b29f 100644 --- a/src/misc/stats.c +++ b/src/misc/stats.c @@ -32,7 +32,7 @@ /***************************************************************************** * Local prototypes *****************************************************************************/ -static counter_t *stats_GetCounter( stats_handler_t *p_handler, int i_object_id, +static counter_t *GetCounter( stats_handler_t *p_handler, int i_object_id, char *psz_name ); static int stats_CounterUpdate( stats_handler_t *p_handler, counter_t *p_counter, @@ -44,6 +44,17 @@ static stats_handler_t *stats_HandlerGet( vlc_object_t *p_this ); * Exported functions *****************************************************************************/ +/** + * Create a statistics counter + * \param p_this the object for which to create the counter + * \param psz_name the name + * \param i_type the type of stored data. One of VLC_VAR_STRING, + * VLC_VAR_INTEGER, VLC_VAR_FLOAT + * \param i_compute_type the aggregation type. One of STATS_LAST (always + * keep the last value), STATS_COUNTER (increment by the passed value), + * STATS_MAX (keep the maximum passed value), STATS_MIN, or STATS_DERIVATIVE + * (keep a time derivative of the value) + */ int __stats_Create( vlc_object_t *p_this, char *psz_name, int i_type, int i_compute_type ) { @@ -62,6 +73,9 @@ int __stats_Create( vlc_object_t *p_this, char *psz_name, int i_type, p_counter->i_samples = 0; p_counter->pp_samples = NULL; + p_counter->update_interval = 0; + p_counter->last_update = 0; + INSERT_ELEM( p_handler->pp_counters, p_handler->i_counters, p_handler->i_counters, @@ -72,8 +86,12 @@ int __stats_Create( vlc_object_t *p_this, char *psz_name, int i_type, return VLC_SUCCESS; } - - +/** Update a counter element with new values + * \param p_this the object in which to update + * \param psz_name the name + * \param val the vlc_value union containing the new value to aggregate. For + * more information on how data is aggregated, \see __stats_Create + */ int __stats_Update( vlc_object_t *p_this, char *psz_name, vlc_value_t val ) { int i_ret; @@ -86,8 +104,8 @@ int __stats_Update( vlc_object_t *p_this, char *psz_name, vlc_value_t val ) vlc_mutex_lock( &p_handler->object_lock ); /* Look for existing element */ - p_counter = stats_GetCounter( p_handler, p_this->i_object_id, - psz_name ); + p_counter = GetCounter( p_handler, p_this->i_object_id, + psz_name ); if( !p_counter ) { vlc_mutex_unlock( &p_handler->object_lock ); @@ -101,6 +119,14 @@ int __stats_Update( vlc_object_t *p_this, char *psz_name, vlc_value_t val ) return i_ret; } +/** Get the aggregated value for a counter + * \param p_this an object + * \param i_object_id the object id from which we want the data + * \param psz_name the name of the couner + * \param val a pointer to an initialized vlc_value union. It will contain the + * retrieved value + * \return an error code + */ int __stats_Get( vlc_object_t *p_this, int i_object_id, char *psz_name, vlc_value_t *val ) { counter_t *p_counter; @@ -112,8 +138,8 @@ int __stats_Get( vlc_object_t *p_this, int i_object_id, char *psz_name, vlc_valu /* Look for existing element */ - p_counter = stats_GetCounter( p_handler, i_object_id, - psz_name ); + p_counter = GetCounter( p_handler, i_object_id, + psz_name ); if( !p_counter ) { vlc_mutex_unlock( &p_handler->object_lock ); @@ -127,14 +153,67 @@ int __stats_Get( vlc_object_t *p_this, int i_object_id, char *psz_name, vlc_valu return VLC_EGENERIC; } - /* FIXME: Does not work for all types, maybe */ - *val = p_counter->pp_samples[0]->value; + switch( p_counter->i_compute_type ) + { + case STATS_LAST: + case STATS_MIN: + case STATS_MAX: + case STATS_COUNTER: + *val = p_counter->pp_samples[0]->value; + break; + case STATS_DERIVATIVE: + if( p_counter->i_type == VLC_VAR_INTEGER ) + { + float f = ( p_counter->pp_samples[0]->value.i_int - + p_counter->pp_samples[1]->value.i_int ) / + (float)( p_counter->pp_samples[0]->date - + p_counter->pp_samples[1]->date ); + val->i_int = (int)f; + } + else + { + float f = (float)( p_counter->pp_samples[0]->value.f_float - + p_counter->pp_samples[1]->value.f_float ) / + (float)( p_counter->pp_samples[0]->date - + p_counter->pp_samples[1]->date ); + val->i_int = (int)f; + val->f_float = f; + } + break; + } vlc_object_release( p_handler ); vlc_mutex_unlock( &p_handler->object_lock ); return VLC_SUCCESS;; } +/** Get a statistics counter structure. This allows for low-level modifications + * \param p_this a parent object + * \param i_object_id the object from which to retrieve data + * \param psz_name the name + * \return the counter, or NULL if not found (or handler not created yet) + */ +counter_t *__stats_CounterGet( vlc_object_t *p_this, int i_object_id, + char *psz_name ) +{ + counter_t *p_counter; + + /* Get stats handler singleton */ + stats_handler_t *p_handler = stats_HandlerGet( p_this ); + if( !p_handler ) return NULL; + + vlc_mutex_lock( &p_handler->object_lock ); + + /* Look for existing element */ + p_counter = GetCounter( p_handler, p_this->i_object_id, + psz_name ); + vlc_mutex_unlock( &p_handler->object_lock ); + vlc_object_release( p_handler ); + + return p_counter; +} + + void stats_ComputeInputStats( input_thread_t *p_input, input_stats_t *p_stats ) { @@ -144,21 +223,26 @@ void stats_ComputeInputStats( input_thread_t *p_input, &p_stats->i_read_packets ); stats_GetInteger( p_input, p_input->i_object_id, "read_bytes", &p_stats->i_read_bytes ); + stats_GetFloat( p_input, p_input->i_object_id, "input_bitrate", + &p_stats->f_bitrate ); vlc_mutex_unlock( &p_stats->lock ); } void stats_ReinitInputStats( input_stats_t *p_stats ) { p_stats->i_read_packets = p_stats->i_read_bytes = - p_stats->f_last_bitrate = p_stats->f_average_bitrate = + p_stats->f_bitrate = p_stats->f_average_bitrate = p_stats->i_displayed_pictures = p_stats->i_lost_pictures = 0; } void stats_DumpInputStats( input_stats_t *p_stats ) { vlc_mutex_lock( &p_stats->lock ); - fprintf( stderr, "Read packets : %i (%i bytes)\n", - p_stats->i_read_packets, p_stats->i_read_bytes ); + /* f_bitrate is in bytes / microsecond + * *1000 => bytes / millisecond => kbytes / seconds */ + fprintf( stderr, "Read packets : %i (%i bytes) - %f kB/s\n", + p_stats->i_read_packets, p_stats->i_read_bytes, + p_stats->f_bitrate * 1000 ); vlc_mutex_unlock( &p_stats->lock ); } @@ -233,7 +317,35 @@ static int stats_CounterUpdate( stats_handler_t *p_handler, } } break; - + case STATS_DERIVATIVE: + { + counter_sample_t *p_new, *p_old; + if( mdate() - p_counter->last_update < p_counter->update_interval ) + { + return VLC_EGENERIC; + } + p_counter->last_update = mdate(); + if( p_counter->i_type != VLC_VAR_FLOAT && + p_counter->i_type != VLC_VAR_INTEGER ) + { + msg_Err( p_handler, "Unable to compute DERIVATIVE for this type"); + return VLC_EGENERIC; + } + /* Insert the new one at the beginning */ + p_new = (counter_sample_t*)malloc( sizeof( counter_sample_t ) ); + p_new->value = val; + p_new->date = p_counter->last_update; + INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples, + 0, p_new ); + + if( p_counter->i_samples == 3 ) + { + p_old = p_counter->pp_samples[2]; + REMOVE_ELEM( p_counter->pp_samples, p_counter->i_samples, 2 ); + free( p_old ); + } + break; + } case STATS_COUNTER: if( p_counter->i_samples > 1) { @@ -268,9 +380,8 @@ static int stats_CounterUpdate( stats_handler_t *p_handler, return VLC_SUCCESS; } - -static counter_t *stats_GetCounter( stats_handler_t *p_handler, int i_object_id, - char *psz_name ) +static counter_t *GetCounter( stats_handler_t *p_handler, int i_object_id, + char *psz_name ) { int i; for( i = 0; i< p_handler->i_counters; i++ ) @@ -285,6 +396,9 @@ static counter_t *stats_GetCounter( stats_handler_t *p_handler, int i_object_id, return NULL; } + + + static stats_handler_t *stats_HandlerGet( vlc_object_t *p_this ) { stats_handler_t *p_handler = (stats_handler_t*) diff --git a/src/playlist/playlist.c b/src/playlist/playlist.c index 00567988ab..303661ba4b 100644 --- a/src/playlist/playlist.c +++ b/src/playlist/playlist.c @@ -581,6 +581,8 @@ static void RunThread ( playlist_t *p_playlist ) mtime_t i_vout_destroyed_date = 0; mtime_t i_sout_destroyed_date = 0; + int i_loops; + playlist_item_t *p_autodelete_item = NULL; /* Tell above that we're ready */ @@ -588,6 +590,7 @@ static void RunThread ( playlist_t *p_playlist ) while( !p_playlist->b_die ) { + i_loops++; if( p_playlist->p_interaction ) { intf_InteractionManage( p_playlist ); @@ -618,8 +621,13 @@ static void RunThread ( playlist_t *p_playlist ) /* If there is an input, check that it doesn't need to die. */ if( p_playlist->p_input ) { - stats_ComputeInputStats( p_playlist->p_input, + if( i_loops % 5 == 0 ) + { + stats_ComputeInputStats( p_playlist->p_input, p_playlist->p_input->input.p_item->p_stats ); +// stats_DumpInputStats( +// p_playlist->p_input->input.p_item->p_stats ); + } /* This input is dead. Remove it ! */ if( p_playlist->p_input->b_dead ) -- 2.39.5