]> git.sesse.net Git - vlc/blob - src/misc/stats.c
d88ef18e1cf58799785dc94e97de1e0e5bf7541b
[vlc] / src / misc / stats.c
1 /*****************************************************************************
2  * stats.c: Statistics handling
3  *****************************************************************************
4  * Copyright (C) 1998-2005 the VideoLAN team
5  * $Id: messages.c 12729 2005-10-02 08:00:06Z courmisch $
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdio.h>                                               /* required */
28
29 #include <vlc/vlc.h>
30 #include <vlc_input.h>
31
32 /*****************************************************************************
33  * Local prototypes
34  *****************************************************************************/
35 static counter_t *stats_GetCounter( stats_handler_t *p_handler, int i_object_id,
36                             char *psz_name );
37 static int stats_CounterUpdate( stats_handler_t *p_handler,
38                                 counter_t *p_counter,
39                                 vlc_value_t val );
40 static stats_handler_t* stats_HandlerCreate( vlc_object_t *p_this );
41 static stats_handler_t *stats_HandlerGet( vlc_object_t *p_this );
42
43 /*****************************************************************************
44  * Exported functions
45  *****************************************************************************/
46
47 int __stats_Create( vlc_object_t *p_this, char *psz_name, int i_type,
48                     int i_compute_type )
49 {
50     counter_t *p_counter;
51     stats_handler_t *p_handler = stats_HandlerGet( p_this );
52     if( !p_handler ) return VLC_ENOMEM;
53
54     vlc_mutex_lock( &p_handler->object_lock );
55
56     p_counter = (counter_t*) malloc( sizeof( counter_t ) ) ;
57
58     p_counter->psz_name = strdup( psz_name );
59     p_counter->i_source_object = p_this->i_object_id;
60     p_counter->i_compute_type = i_compute_type;
61     p_counter->i_type = i_type;
62     p_counter->i_samples = 0;
63     p_counter->pp_samples = NULL;
64
65     INSERT_ELEM( p_handler->pp_counters,
66                  p_handler->i_counters,
67                  p_handler->i_counters,
68                  p_counter );
69
70     vlc_mutex_unlock( &p_handler->object_lock );
71
72     return VLC_SUCCESS;
73 }
74
75
76
77 int __stats_Update( vlc_object_t *p_this, char *psz_name, vlc_value_t val )
78 {
79     int i_ret;
80     counter_t *p_counter;
81
82     /* Get stats handler singleton */
83     stats_handler_t *p_handler = stats_HandlerGet( p_this );
84     if( !p_handler ) return VLC_ENOMEM;
85
86     vlc_mutex_lock( &p_handler->object_lock );
87
88     /* Look for existing element */
89     p_counter = stats_GetCounter( p_handler, p_this->i_object_id,
90                                   psz_name );
91     if( !p_counter )
92     {
93         vlc_mutex_unlock( &p_handler->object_lock );
94         vlc_object_release( p_handler );
95         return VLC_ENOOBJ;
96     }
97
98     i_ret = stats_CounterUpdate( p_handler, p_counter, val );
99     vlc_mutex_unlock( &p_handler->object_lock );
100
101     return i_ret;
102 }
103
104 int __stats_Get( vlc_object_t *p_this, int i_object_id, char *psz_name, vlc_value_t *val )
105 {
106     counter_t *p_counter;
107
108     /* Get stats handler singleton */
109     stats_handler_t *p_handler = stats_HandlerGet( p_this );
110     if( !p_handler ) return VLC_ENOMEM;
111     vlc_mutex_lock( &p_handler->object_lock );
112
113
114     /* Look for existing element */
115     p_counter = stats_GetCounter( p_handler, i_object_id,
116                                   psz_name );
117     if( !p_counter )
118     {
119         vlc_mutex_unlock( &p_handler->object_lock );
120         vlc_object_release( p_handler );
121         return VLC_ENOOBJ;
122     }
123
124     if( p_counter->i_samples == 0 )
125     {
126         vlc_mutex_unlock( &p_handler->object_lock );
127         return VLC_EGENERIC;
128     }
129
130     /* FIXME: Does not work for all types, maybe */
131     *val = p_counter->pp_samples[0]->value;
132     vlc_object_release( p_handler );
133
134     vlc_mutex_unlock( &p_handler->object_lock );
135     return VLC_SUCCESS;;
136 }
137
138 void stats_ComputeInputStats( input_thread_t *p_input,
139                               input_stats_t *p_stats )
140 {
141     vlc_mutex_lock( &p_stats->lock );
142     /* read_packets and read_bytes are common to all streams */
143     stats_GetInteger( p_input, p_input->i_object_id, "read_packets",
144                        &p_stats->i_read_packets );
145     stats_GetInteger( p_input, p_input->i_object_id, "read_bytes",
146                        &p_stats->i_read_bytes );
147     vlc_mutex_unlock( &p_stats->lock );
148 }
149
150 void stats_ReinitInputStats( input_stats_t *p_stats )
151 {
152     p_stats->i_read_packets = p_stats->i_read_bytes =
153         p_stats->f_last_bitrate = p_stats->f_average_bitrate =
154         p_stats->i_displayed_pictures = p_stats->i_lost_pictures = 0;
155 }
156
157 void stats_DumpInputStats( input_stats_t *p_stats  )
158 {
159     vlc_mutex_lock( &p_stats->lock );
160     fprintf( stderr, "Read packets : %i (%i bytes)\n",
161                     p_stats->i_read_packets, p_stats->i_read_bytes );
162     vlc_mutex_unlock( &p_stats->lock );
163 }
164
165
166 /********************************************************************
167  * Following functions are local
168  ********************************************************************/
169
170 /**
171  * Update a statistics counter, according to its type
172  * If needed, perform a bit of computation (derivative, mostly)
173  * This function must be entered with stats handler lock
174  * \param p_handler stats handler singleton
175  * \param p_counter the counter to update
176  * \param val the "new" value
177  * \return an error code
178  */
179 static int stats_CounterUpdate( stats_handler_t *p_handler,
180                                 counter_t *p_counter,
181                                 vlc_value_t val )
182 {
183     switch( p_counter->i_compute_type )
184     {
185     case STATS_LAST:
186     case STATS_MIN:
187     case STATS_MAX:
188         if( p_counter->i_samples > 1)
189         {
190             msg_Err( p_handler, "LAST counter has several samples !" );
191             return VLC_EGENERIC;
192         }
193         if( p_counter->i_type != VLC_VAR_FLOAT &&
194             p_counter->i_type != VLC_VAR_INTEGER &&
195             p_counter->i_compute_type != STATS_LAST )
196         {
197             msg_Err( p_handler, "Unable to compute MIN or MAX for this type");
198             return VLC_EGENERIC;
199         }
200
201         if( p_counter->i_samples == 0 )
202         {
203             counter_sample_t *p_new = (counter_sample_t*)malloc(
204                                                sizeof( counter_sample_t ) );
205             p_new->value.psz_string = NULL;
206
207             INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
208                          p_counter->i_samples, p_new );
209         }
210         if( p_counter->i_samples == 1 )
211         {
212             /* Update if : LAST or (MAX and bigger) or (MIN and bigger) */
213             if( p_counter->i_compute_type == STATS_LAST ||
214                 ( p_counter->i_compute_type == STATS_MAX &&
215                    ( ( p_counter->i_type == VLC_VAR_INTEGER &&
216                        p_counter->pp_samples[0]->value.i_int > val.i_int ) ||
217                      ( p_counter->i_type == VLC_VAR_FLOAT &&
218                        p_counter->pp_samples[0]->value.f_float > val.f_float )
219                    ) ) ||
220                 ( p_counter->i_compute_type == STATS_MIN &&
221                    ( ( p_counter->i_type == VLC_VAR_INTEGER &&
222                        p_counter->pp_samples[0]->value.i_int < val.i_int ) ||
223                      ( p_counter->i_type == VLC_VAR_FLOAT &&
224                        p_counter->pp_samples[0]->value.f_float < val.f_float )
225                    ) ) )
226             {
227                 if( p_counter->i_type == VLC_VAR_STRING &&
228                     p_counter->pp_samples[0]->value.psz_string )
229                 {
230                     free( p_counter->pp_samples[0]->value.psz_string );
231                 }
232                 p_counter->pp_samples[0]->value = val;
233             }
234         }
235         break;
236
237     case STATS_COUNTER:
238         if( p_counter->i_samples > 1)
239         {
240             msg_Err( p_handler, "LAST counter has several samples !" );
241             return VLC_EGENERIC;
242         }
243         if( p_counter->i_samples == 0 )
244         {
245             counter_sample_t *p_new = (counter_sample_t*)malloc(
246                                                sizeof( counter_sample_t ) );
247             p_new->value.psz_string = NULL;
248
249             INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
250                          p_counter->i_samples, p_new );
251         }
252         if( p_counter->i_samples == 1 )
253         {
254             switch( p_counter->i_type )
255             {
256             case VLC_VAR_INTEGER:
257             case VLC_VAR_FLOAT:
258                 p_counter->pp_samples[0]->value.i_int += val.i_int;
259                 break;
260             default:
261                 msg_Err( p_handler, "Trying to increment invalid variable %s",
262                          p_counter->psz_name );
263                 return VLC_EGENERIC;
264             }
265         }
266         break;
267     }
268     return VLC_SUCCESS;
269 }
270
271
272 static counter_t *stats_GetCounter( stats_handler_t *p_handler, int i_object_id,
273                                     char *psz_name )
274 {
275     int i;
276     for( i = 0; i< p_handler->i_counters; i++ )
277     {
278         counter_t *p_counter = p_handler->pp_counters[i];
279         if( p_counter->i_source_object == i_object_id &&
280             !strcmp( p_counter->psz_name, psz_name ) )
281         {
282             return p_counter;
283         }
284     }
285     return NULL;
286 }
287
288 static stats_handler_t *stats_HandlerGet( vlc_object_t *p_this )
289 {
290     stats_handler_t *p_handler = (stats_handler_t*)
291                           vlc_object_find( p_this->p_vlc, VLC_OBJECT_STATS,
292                                            FIND_ANYWHERE );
293     if( !p_handler )
294     {
295         p_handler = stats_HandlerCreate( p_this );
296         if( !p_handler )
297         {
298             return NULL;
299         }
300         vlc_object_yield( p_handler );
301     }
302     return p_handler;
303 }
304
305 /**
306  * Initialize statistics handler
307  *
308  * This function initializes the global statistics handler singleton,
309  * \param p_this the parent VLC object
310  */
311 static stats_handler_t* stats_HandlerCreate( vlc_object_t *p_this )
312 {
313     stats_handler_t *p_handler;
314
315     msg_Dbg( p_this, "creating statistics handler" );
316
317     p_handler = (stats_handler_t*) vlc_object_create( p_this,
318                                                       VLC_OBJECT_STATS );
319
320     if( !p_handler )
321     {
322         msg_Err( p_this, "out of memory" );
323         return NULL;
324     }
325     p_handler->i_counters = 0;
326     p_handler->pp_counters = NULL;
327
328     /// \bug is it p_vlc or p_libvlc ?
329     vlc_object_attach( p_handler, p_this->p_vlc );
330
331     return p_handler;
332 }
333
334