1 /*****************************************************************************
2 * stats.c: Statistics handling
3 *****************************************************************************
4 * Copyright (C) 2006 VLC authors and VideoLAN
7 * Authors: Clément Stenac <zorglub@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <stdio.h> /* required */
35 #include "input/input_internal.h"
37 /*****************************************************************************
39 *****************************************************************************/
40 static int CounterUpdate( vlc_object_t *p_this,
42 vlc_value_t val, vlc_value_t * );
44 /*****************************************************************************
46 *****************************************************************************/
48 #undef stats_CounterCreate
50 * Create a statistics counter
51 * \param p_this a VLC object
52 * \param i_type the type of stored data. One of VLC_VAR_STRING,
53 * VLC_VAR_INTEGER, VLC_VAR_FLOAT
54 * \param i_compute_type the aggregation type. One of STATS_LAST (always
55 * keep the last value), STATS_COUNTER (increment by the passed value),
56 * STATS_MAX (keep the maximum passed value), STATS_MIN, or STATS_DERIVATIVE
57 * (keep a time derivative of the value)
59 counter_t * stats_CounterCreate( vlc_object_t *p_this,
60 int i_type, int i_compute_type )
62 counter_t *p_counter = (counter_t*) malloc( sizeof( counter_t ) ) ;
65 if( !p_counter ) return NULL;
66 p_counter->i_compute_type = i_compute_type;
67 p_counter->i_type = i_type;
68 p_counter->i_samples = 0;
69 p_counter->pp_samples = NULL;
71 p_counter->update_interval = 0;
72 p_counter->last_update = 0;
77 /** Update a counter element with new values
78 * \param p_this a VLC object
79 * \param p_counter the counter to update
80 * \param val the vlc_value union containing the new value to aggregate. For
81 * more information on how data is aggregated, \see stats_Create
82 * \param val_new a pointer that will be filled with new data
84 int stats_Update( vlc_object_t *p_this, counter_t *p_counter,
85 vlc_value_t val, vlc_value_t *val_new )
87 if( !libvlc_stats (p_this) || !p_counter ) return VLC_EGENERIC;
88 return CounterUpdate( p_this, p_counter, val, val_new );
92 /** Get the aggregated value for a counter
93 * \param p_this an object
94 * \param p_counter the counter
95 * \param val a pointer to an initialized vlc_value union. It will contain the
97 * \return an error code
99 int stats_Get( vlc_object_t *p_this, counter_t *p_counter, vlc_value_t *val )
101 if( !libvlc_stats (p_this) || !p_counter || p_counter->i_samples == 0 )
107 switch( p_counter->i_compute_type )
110 *val = p_counter->pp_samples[0]->value;
112 case STATS_DERIVATIVE:
114 if( p_counter->i_samples < 2 )
119 if( p_counter->i_type == VLC_VAR_INTEGER )
121 float f = ( p_counter->pp_samples[0]->value.i_int -
122 p_counter->pp_samples[1]->value.i_int ) /
123 (float)( p_counter->pp_samples[0]->date -
124 p_counter->pp_samples[1]->date );
125 val->i_int = (int64_t)f;
129 float f = (float)( p_counter->pp_samples[0]->value.f_float -
130 p_counter->pp_samples[1]->value.f_float ) /
131 (float)( p_counter->pp_samples[0]->date -
132 p_counter->pp_samples[1]->date );
140 input_stats_t *stats_NewInputStats( input_thread_t *p_input )
143 input_stats_t *p_stats = calloc( 1, sizeof(input_stats_t) );
147 vlc_mutex_init( &p_stats->lock );
148 stats_ReinitInputStats( p_stats );
153 void stats_ComputeInputStats( input_thread_t *p_input, input_stats_t *p_stats )
155 if( !libvlc_stats (p_input) ) return;
157 vlc_mutex_lock( &p_input->p->counters.counters_lock );
158 vlc_mutex_lock( &p_stats->lock );
161 stats_GetInteger( p_input, p_input->p->counters.p_read_packets,
162 &p_stats->i_read_packets );
163 stats_GetInteger( p_input, p_input->p->counters.p_read_bytes,
164 &p_stats->i_read_bytes );
165 stats_GetFloat( p_input, p_input->p->counters.p_input_bitrate,
166 &p_stats->f_input_bitrate );
167 stats_GetInteger( p_input, p_input->p->counters.p_demux_read,
168 &p_stats->i_demux_read_bytes );
169 stats_GetFloat( p_input, p_input->p->counters.p_demux_bitrate,
170 &p_stats->f_demux_bitrate );
171 stats_GetInteger( p_input, p_input->p->counters.p_demux_corrupted,
172 &p_stats->i_demux_corrupted );
173 stats_GetInteger( p_input, p_input->p->counters.p_demux_discontinuity,
174 &p_stats->i_demux_discontinuity );
177 stats_GetInteger( p_input, p_input->p->counters.p_decoded_video,
178 &p_stats->i_decoded_video );
179 stats_GetInteger( p_input, p_input->p->counters.p_decoded_audio,
180 &p_stats->i_decoded_audio );
183 if( p_input->p->counters.p_sout_send_bitrate )
185 stats_GetInteger( p_input, p_input->p->counters.p_sout_sent_packets,
186 &p_stats->i_sent_packets );
187 stats_GetInteger( p_input, p_input->p->counters.p_sout_sent_bytes,
188 &p_stats->i_sent_bytes );
189 stats_GetFloat ( p_input, p_input->p->counters.p_sout_send_bitrate,
190 &p_stats->f_send_bitrate );
194 stats_GetInteger( p_input, p_input->p->counters.p_played_abuffers,
195 &p_stats->i_played_abuffers );
196 stats_GetInteger( p_input, p_input->p->counters.p_lost_abuffers,
197 &p_stats->i_lost_abuffers );
200 stats_GetInteger( p_input, p_input->p->counters.p_displayed_pictures,
201 &p_stats->i_displayed_pictures );
202 stats_GetInteger( p_input, p_input->p->counters.p_lost_pictures,
203 &p_stats->i_lost_pictures );
205 vlc_mutex_unlock( &p_stats->lock );
206 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
209 void stats_ReinitInputStats( input_stats_t *p_stats )
211 vlc_mutex_lock( &p_stats->lock );
212 p_stats->i_read_packets = p_stats->i_read_bytes =
213 p_stats->f_input_bitrate = p_stats->f_average_input_bitrate =
214 p_stats->i_demux_read_packets = p_stats->i_demux_read_bytes =
215 p_stats->f_demux_bitrate = p_stats->f_average_demux_bitrate =
216 p_stats->i_demux_corrupted = p_stats->i_demux_discontinuity =
217 p_stats->i_displayed_pictures = p_stats->i_lost_pictures =
218 p_stats->i_played_abuffers = p_stats->i_lost_abuffers =
219 p_stats->i_decoded_video = p_stats->i_decoded_audio =
220 p_stats->i_sent_bytes = p_stats->i_sent_packets = p_stats->f_send_bitrate
222 vlc_mutex_unlock( &p_stats->lock );
225 void stats_CounterClean( counter_t *p_c )
229 int i = p_c->i_samples - 1 ;
232 counter_sample_t *p_s = p_c->pp_samples[i];
233 REMOVE_ELEM( p_c->pp_samples, p_c->i_samples, i );
242 /********************************************************************
243 * Following functions are local
244 ********************************************************************/
247 * Update a statistics counter, according to its type
248 * If needed, perform a bit of computation (derivative, mostly)
249 * This function must be entered with stats handler lock
250 * \param p_counter the counter to update
251 * \param val the "new" value
252 * \return an error code
254 static int CounterUpdate( vlc_object_t *p_handler,
255 counter_t *p_counter,
256 vlc_value_t val, vlc_value_t *new_val )
258 switch( p_counter->i_compute_type )
260 case STATS_DERIVATIVE:
262 counter_sample_t *p_new, *p_old;
263 mtime_t now = mdate();
264 if( now - p_counter->last_update < p_counter->update_interval )
268 p_counter->last_update = now;
269 if( p_counter->i_type != VLC_VAR_FLOAT &&
270 p_counter->i_type != VLC_VAR_INTEGER )
272 msg_Err( p_handler, "Unable to compute DERIVATIVE for this type");
275 /* Insert the new one at the beginning */
276 p_new = (counter_sample_t*)malloc( sizeof( counter_sample_t ) );
278 p_new->date = p_counter->last_update;
279 INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
282 if( p_counter->i_samples == 3 )
284 p_old = p_counter->pp_samples[2];
285 REMOVE_ELEM( p_counter->pp_samples, p_counter->i_samples, 2 );
291 if( p_counter->i_samples > 1)
293 msg_Err( p_handler, "LAST counter has several samples !" );
296 if( p_counter->i_samples == 0 )
298 counter_sample_t *p_new = (counter_sample_t*)malloc(
299 sizeof( counter_sample_t ) );
300 p_new->value.i_int = 0;
302 INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
303 p_counter->i_samples, p_new );
305 if( p_counter->i_samples == 1 )
307 switch( p_counter->i_type )
309 case VLC_VAR_INTEGER:
310 p_counter->pp_samples[0]->value.i_int += val.i_int;
312 new_val->i_int = p_counter->pp_samples[0]->value.i_int;
315 p_counter->pp_samples[0]->value.f_float += val.f_float;
317 new_val->f_float = p_counter->pp_samples[0]->value.f_float;