stats.c 21.6 KB
Newer Older
1
2
3
/*****************************************************************************
 * stats.c: Statistics handling
 *****************************************************************************
4
5
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
6
 *
7
 * Authors: Clément Stenac <zorglub@videolan.org>
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
23
24
25
26
27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

28
29
30
31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc/vlc.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
33
#include <stdio.h>                                               /* required */
zorglub's avatar
zorglub committed
34
35

#include "input/input_internal.h"
36
37
38
39

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
40
41
42
static int CounterUpdate( vlc_object_t *p_this,
                          counter_t *p_counter,
                          vlc_value_t val, vlc_value_t * );
43
static void TimerDump( vlc_object_t *p_this, counter_t *p_counter, bool);
zorglub's avatar
zorglub committed
44

45
46
47
48
/*****************************************************************************
 * Exported functions
 *****************************************************************************/

49
50
/**
 * Create a statistics counter
51
 * \param p_this a VLC object
52
53
54
55
56
57
58
 * \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)
 */
59
60
counter_t * __stats_CounterCreate( vlc_object_t *p_this,
                                   int i_type, int i_compute_type )
61
{
zorglub's avatar
zorglub committed
62
    counter_t *p_counter = (counter_t*) malloc( sizeof( counter_t ) ) ;
63
    (void)p_this;
64

Jean-Paul Saman's avatar
Jean-Paul Saman committed
65
    if( !p_counter ) return NULL;
66
67
68
69
    p_counter->i_compute_type = i_compute_type;
    p_counter->i_type = i_type;
    p_counter->i_samples = 0;
    p_counter->pp_samples = NULL;
70
    p_counter->psz_name = NULL;
71

72
73
74
    p_counter->update_interval = 0;
    p_counter->last_update = 0;

75
    return p_counter;
76
77
}

78
/** Update a counter element with new values
79
80
 * \param p_this a VLC object
 * \param p_counter the counter to update
81
82
 * \param val the vlc_value union containing the new value to aggregate. For
 * more information on how data is aggregated, \see __stats_Create
83
 * \param val_new a pointer that will be filled with new data
84
 */
85
int __stats_Update( vlc_object_t *p_this, counter_t *p_counter,
zorglub's avatar
zorglub committed
86
                    vlc_value_t val, vlc_value_t *val_new )
87
{
88
    if( !libvlc_stats (p_this) || !p_counter ) return VLC_EGENERIC;
89
    return CounterUpdate( p_this, p_counter, val, val_new );
zorglub's avatar
zorglub committed
90
91
}

92
93
/** Get the aggregated value for a counter
 * \param p_this an object
94
 * \param p_counter the counter
95
96
97
98
 * \param val a pointer to an initialized vlc_value union. It will contain the
 * retrieved value
 * \return an error code
 */
99
int __stats_Get( vlc_object_t *p_this, counter_t *p_counter, vlc_value_t *val )
zorglub's avatar
zorglub committed
100
{
101
    if( !libvlc_stats (p_this) || !p_counter || p_counter->i_samples == 0 )
zorglub's avatar
zorglub committed
102
    {
zorglub's avatar
zorglub committed
103
        val->i_int = val->f_float = 0.0;
zorglub's avatar
zorglub committed
104
105
106
        return VLC_EGENERIC;
    }

107
108
109
110
111
112
113
114
115
    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:
zorglub's avatar
zorglub committed
116
117
118
119
120
121
122
        /* Not ready yet */
        if( p_counter->i_samples < 2 )
        {
            val->i_int = 0; val->f_float = 0.0;
            return VLC_EGENERIC;
        }
        if( p_counter->i_type == VLC_VAR_INTEGER )
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
        {
            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->f_float = f;
        }
        break;
    }
zorglub's avatar
zorglub committed
140
    return VLC_SUCCESS;;
141
142
}

143
144
input_stats_t *stats_NewInputStats( input_thread_t *p_input )
{
145
    (void)p_input;
146
147
148
149
150
151
    input_stats_t *p_stats = malloc( sizeof(input_stats_t) );

    if( !p_stats )
        return NULL;

    memset( p_stats, 0, sizeof(*p_stats) );
152
    vlc_mutex_init( &p_stats->lock );
153
154
155
156
157
    stats_ReinitInputStats( p_stats );

    return p_stats;
}

158
void stats_ComputeInputStats( input_thread_t *p_input, input_stats_t *p_stats )
zorglub's avatar
zorglub committed
159
{
160
    if( !libvlc_stats (p_input) ) return;
161

zorglub's avatar
zorglub committed
162
    vlc_mutex_lock( &p_input->p->counters.counters_lock );
zorglub's avatar
zorglub committed
163
    vlc_mutex_lock( &p_stats->lock );
zorglub's avatar
zorglub committed
164
165

    /* Input */
zorglub's avatar
zorglub committed
166
    stats_GetInteger( p_input, p_input->p->counters.p_read_packets,
167
                      &p_stats->i_read_packets );
zorglub's avatar
zorglub committed
168
    stats_GetInteger( p_input, p_input->p->counters.p_read_bytes,
169
                      &p_stats->i_read_bytes );
zorglub's avatar
zorglub committed
170
    stats_GetFloat( p_input, p_input->p->counters.p_input_bitrate,
171
                    &p_stats->f_input_bitrate );
zorglub's avatar
zorglub committed
172
    stats_GetInteger( p_input, p_input->p->counters.p_demux_read,
zorglub's avatar
zorglub committed
173
                      &p_stats->i_demux_read_bytes );
zorglub's avatar
zorglub committed
174
    stats_GetFloat( p_input, p_input->p->counters.p_demux_bitrate,
175
                    &p_stats->f_demux_bitrate );
zorglub's avatar
zorglub committed
176

177
    /* Decoders */
zorglub's avatar
zorglub committed
178
    stats_GetInteger( p_input, p_input->p->counters.p_decoded_video,
zorglub's avatar
zorglub committed
179
                      &p_stats->i_decoded_video );
zorglub's avatar
zorglub committed
180
    stats_GetInteger( p_input, p_input->p->counters.p_decoded_audio,
zorglub's avatar
zorglub committed
181
182
                      &p_stats->i_decoded_audio );

zorglub's avatar
zorglub committed
183
    /* Sout */
zorglub's avatar
zorglub committed
184
    if( p_input->p->counters.p_sout_send_bitrate )
185
    {
zorglub's avatar
zorglub committed
186
        stats_GetInteger( p_input, p_input->p->counters.p_sout_sent_packets,
187
                          &p_stats->i_sent_packets );
zorglub's avatar
zorglub committed
188
        stats_GetInteger( p_input, p_input->p->counters.p_sout_sent_bytes,
189
                          &p_stats->i_sent_bytes );
zorglub's avatar
zorglub committed
190
        stats_GetFloat  ( p_input, p_input->p->counters.p_sout_send_bitrate,
191
192
193
194
                          &p_stats->f_send_bitrate );
    }

    /* Aout */
zorglub's avatar
zorglub committed
195
    stats_GetInteger( p_input, p_input->p->counters.p_played_abuffers,
zorglub's avatar
zorglub committed
196
                      &p_stats->i_played_abuffers );
zorglub's avatar
zorglub committed
197
    stats_GetInteger( p_input, p_input->p->counters.p_lost_abuffers,
zorglub's avatar
zorglub committed
198
199
                      &p_stats->i_lost_abuffers );

200
    /* Vouts */
zorglub's avatar
zorglub committed
201
    stats_GetInteger( p_input, p_input->p->counters.p_displayed_pictures,
202
                      &p_stats->i_displayed_pictures );
zorglub's avatar
zorglub committed
203
    stats_GetInteger( p_input, p_input->p->counters.p_lost_pictures,
204
                      &p_stats->i_lost_pictures );
zorglub's avatar
zorglub committed
205

zorglub's avatar
zorglub committed
206
    vlc_mutex_unlock( &p_stats->lock );
zorglub's avatar
zorglub committed
207
    vlc_mutex_unlock( &p_input->p->counters.counters_lock );
zorglub's avatar
zorglub committed
208
209
210
211
}

void stats_ReinitInputStats( input_stats_t *p_stats )
{
212
    vlc_mutex_lock( &p_stats->lock );
zorglub's avatar
zorglub committed
213
    p_stats->i_read_packets = p_stats->i_read_bytes =
214
215
216
217
    p_stats->f_input_bitrate = p_stats->f_average_input_bitrate =
    p_stats->i_demux_read_packets = p_stats->i_demux_read_bytes =
    p_stats->f_demux_bitrate = p_stats->f_average_demux_bitrate =
    p_stats->i_displayed_pictures = p_stats->i_lost_pictures =
zorglub's avatar
zorglub committed
218
    p_stats->i_played_abuffers = p_stats->i_lost_abuffers =
zorglub's avatar
zorglub committed
219
220
221
    p_stats->i_decoded_video = p_stats->i_decoded_audio =
    p_stats->i_sent_bytes = p_stats->i_sent_packets = p_stats->f_send_bitrate
     = 0;
222
    vlc_mutex_unlock( &p_stats->lock );
zorglub's avatar
zorglub committed
223
224
225
226
227
}

void stats_DumpInputStats( input_stats_t *p_stats  )
{
    vlc_mutex_lock( &p_stats->lock );
228
229
    /* f_bitrate is in bytes / microsecond
     * *1000 => bytes / millisecond => kbytes / seconds */
230
231
232
    fprintf( stderr, "Input : %i (%i bytes) - %f kB/s - "
                     "Demux : %i (%i bytes) - %f kB/s\n"
                     " - Vout : %i/%i - Aout : %i/%i - Sout : %f\n",
233
                    p_stats->i_read_packets, p_stats->i_read_bytes,
zorglub's avatar
zorglub committed
234
                    p_stats->f_input_bitrate * 1000,
235
236
                    p_stats->i_demux_read_packets, p_stats->i_demux_read_bytes,
                    p_stats->f_demux_bitrate * 1000,
zorglub's avatar
zorglub committed
237
                    p_stats->i_displayed_pictures, p_stats->i_lost_pictures,
zorglub's avatar
zorglub committed
238
239
                    p_stats->i_played_abuffers, p_stats->i_lost_abuffers,
                    p_stats->f_send_bitrate );
zorglub's avatar
zorglub committed
240
241
242
    vlc_mutex_unlock( &p_stats->lock );
}

243
void __stats_ComputeGlobalStats( vlc_object_t *p_obj, global_stats_t *p_stats )
zorglub's avatar
zorglub committed
244
245
246
{
    vlc_list_t *p_list;
    int i_index;
247

248
    if( !libvlc_stats (p_obj) ) return;
249

zorglub's avatar
zorglub committed
250
251
    vlc_mutex_lock( &p_stats->lock );

252
    p_list = vlc_list_find( p_obj, VLC_OBJECT_INPUT, FIND_ANYWHERE );
zorglub's avatar
zorglub committed
253
254
    if( p_list )
    {
255
        float f_total_in = 0, f_total_out = 0,f_total_demux = 0;
zorglub's avatar
zorglub committed
256
257
        for( i_index = 0; i_index < p_list->i_count ; i_index ++ )
        {
258
            float f_in = 0, f_out = 0, f_demux = 0;
259
260
            input_thread_t *p_input = (input_thread_t *)
                             p_list->p_values[i_index].p_object;
zorglub's avatar
zorglub committed
261
262
263
264
            vlc_mutex_lock( &p_input->p->counters.counters_lock );
            stats_GetFloat( p_obj, p_input->p->counters.p_input_bitrate, &f_in );
            if( p_input->p->counters.p_sout_send_bitrate )
                stats_GetFloat( p_obj, p_input->p->counters.p_sout_send_bitrate,
265
                                    &f_out );
zorglub's avatar
zorglub committed
266
            stats_GetFloat( p_obj, p_input->p->counters.p_demux_bitrate,
267
                                &f_demux );
zorglub's avatar
zorglub committed
268
            vlc_mutex_unlock( &p_input->p->counters.counters_lock );
269
            f_total_in += f_in; f_total_out += f_out;f_total_demux += f_demux;
zorglub's avatar
zorglub committed
270
        }
271
272
273
        p_stats->f_input_bitrate = f_total_in;
        p_stats->f_output_bitrate = f_total_out;
        p_stats->f_demux_bitrate = f_total_demux;
zorglub's avatar
zorglub committed
274
275
276
277
278
279
        vlc_list_release( p_list );
    }

    vlc_mutex_unlock( &p_stats->lock );
}

280
281
void __stats_TimerStart( vlc_object_t *p_obj, const char *psz_name,
                         unsigned int i_id )
zorglub's avatar
zorglub committed
282
{
283
    libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
284
    counter_t *p_counter = NULL;
285

286
287
288
289
290
    if( !priv->b_stats ) return;

    vlc_mutex_lock( &priv->timer_lock );

    for( int i = 0 ; i < priv->i_timers; i++ )
291
    {
292
293
        if( priv->pp_timers[i]->i_id == i_id
            && priv->pp_timers[i]->p_obj == p_obj )
294
        {
295
            p_counter = priv->pp_timers[i];
296
297
298
            break;
        }
    }
zorglub's avatar
zorglub committed
299
300
301
    if( !p_counter )
    {
        counter_sample_t *p_sample;
302
        p_counter = stats_CounterCreate( p_obj->p_libvlc, VLC_VAR_TIME,
303
                                         STATS_TIMER );
304
        if( !p_counter )
305
            goto out;
306
307
        p_counter->psz_name = strdup( psz_name );
        p_counter->i_id = i_id;
308
        p_counter->p_obj = p_obj;
309
310
        INSERT_ELEM( priv->pp_timers, priv->i_timers,
                     priv->i_timers, p_counter );
311

zorglub's avatar
zorglub committed
312
313
314
315
316
317
318
319
320
321
322
        /* 1st sample : if started: start_date, else last_time, b_started */
        p_sample = (counter_sample_t *)malloc( sizeof( counter_sample_t ) );
        INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
                     p_counter->i_samples, p_sample );
        p_sample->date = 0; p_sample->value.b_bool = 0;
        /* 2nd sample : global_time, i_samples */
        p_sample = (counter_sample_t *)malloc( sizeof( counter_sample_t ) );
        INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
                     p_counter->i_samples, p_sample );
        p_sample->date = 0; p_sample->value.i_int = 0;
    }
323
    if( p_counter->pp_samples[0]->value.b_bool == true )
zorglub's avatar
zorglub committed
324
    {
325
        msg_Warn( p_obj, "timer '%s' was already started !", psz_name );
326
        goto out;
zorglub's avatar
zorglub committed
327
    }
328
    p_counter->pp_samples[0]->value.b_bool = true;
zorglub's avatar
zorglub committed
329
    p_counter->pp_samples[0]->date = mdate();
330
331
out:
    vlc_mutex_unlock( &priv->timer_lock );
zorglub's avatar
zorglub committed
332
333
}

334
void __stats_TimerStop( vlc_object_t *p_obj, unsigned int i_id )
zorglub's avatar
zorglub committed
335
{
336
    counter_t *p_counter = NULL;
337
338
339
340
341
    libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);

    if( !priv->b_stats ) return;
    vlc_mutex_lock( &priv->timer_lock );
    for( int i = 0 ; i < priv->i_timers; i++ )
342
    {
343
344
        if( priv->pp_timers[i]->i_id == i_id
            && priv->pp_timers[i]->p_obj == p_obj )
345
        {
346
            p_counter = priv->pp_timers[i];
347
348
349
            break;
        }
    }
zorglub's avatar
zorglub committed
350
351
    if( !p_counter || p_counter->i_samples != 2 )
    {
352
        msg_Err( p_obj, "timer does not exist" );
353
        goto out;
zorglub's avatar
zorglub committed
354
    }
355
    p_counter->pp_samples[0]->value.b_bool = false;
zorglub's avatar
zorglub committed
356
357
358
    p_counter->pp_samples[1]->value.i_int += 1;
    p_counter->pp_samples[0]->date = mdate() - p_counter->pp_samples[0]->date;
    p_counter->pp_samples[1]->date += p_counter->pp_samples[0]->date;
359
360
out:
    vlc_mutex_unlock( &priv->timer_lock );
zorglub's avatar
zorglub committed
361
362
}

363
void __stats_TimerDump( vlc_object_t *p_obj, unsigned int i_id )
zorglub's avatar
zorglub committed
364
{
365
    counter_t *p_counter = NULL;
366
367
368
369
370
    libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);

    if( !priv->b_stats ) return;
    vlc_mutex_lock( &priv->timer_lock );
    for( int i = 0 ; i < priv->i_timers; i++ )
371
    {
372
373
        if( priv->pp_timers[i]->i_id == i_id
            && priv->pp_timers[i]->p_obj == p_obj )
374
        {
375
            p_counter = priv->pp_timers[i];
376
377
378
            break;
        }
    }
379
    TimerDump( p_obj, p_counter, true );
380
    vlc_mutex_unlock( &priv->timer_lock );
zorglub's avatar
zorglub committed
381
382
383
384
}

void __stats_TimersDumpAll( vlc_object_t *p_obj )
{
385
386
387
388
389
390
391
    libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);

    if( !priv->b_stats ) return;
    vlc_mutex_lock( &priv->timer_lock );
    for ( int i = 0 ; i < priv->i_timers ; i++ )
        TimerDump( p_obj, priv->pp_timers[i], false );
    vlc_mutex_unlock( &priv->timer_lock );
392
}
zorglub's avatar
zorglub committed
393

394
void __stats_TimerClean( vlc_object_t *p_obj, unsigned int i_id )
395
{
396
397
398
399
    libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);

    vlc_mutex_lock( &priv->timer_lock );
    for ( int i = priv->i_timers -1 ; i >= 0; i-- )
400
    {
401
        counter_t *p_counter = priv->pp_timers[i];
402
403
        if( p_counter->i_id == i_id && p_counter->p_obj == p_obj )
        {
404
            REMOVE_ELEM( priv->pp_timers, priv->i_timers, i );
405
406
407
            stats_CounterClean( p_counter );
        }
    }
408
    vlc_mutex_unlock( &priv->timer_lock );
409
410
411
}

void __stats_TimersCleanAll( vlc_object_t *p_obj )
412
{
413
414
415
416
    libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);

    vlc_mutex_lock( &priv->timer_lock );
    for ( int i = priv->i_timers -1 ; i >= 0; i-- )
zorglub's avatar
zorglub committed
417
    {
418
419
        counter_t *p_counter = priv->pp_timers[i];
        REMOVE_ELEM( priv->pp_timers, priv->i_timers, i );
420
        stats_CounterClean( p_counter );
zorglub's avatar
zorglub committed
421
    }
422
    vlc_mutex_unlock( &priv->timer_lock );
423
424
425
426
}

void stats_CounterClean( counter_t *p_c )
{
427
    if( p_c )
428
    {
429
        int i = p_c->i_samples - 1 ;
430
        while( i >= 0 )
431
432
433
434
        {
            counter_sample_t *p_s = p_c->pp_samples[i];
            REMOVE_ELEM( p_c->pp_samples, p_c->i_samples, i );
            free( p_s );
435
            i--;
436
        }
437
        free( p_c->psz_name );
438
        free( p_c );
439
    }
zorglub's avatar
zorglub committed
440
441
}

zorglub's avatar
zorglub committed
442
443
444
445
446
447
448
449
450
451
452
453
454

/********************************************************************
 * Following functions are local
 ********************************************************************/

/**
 * Update a statistics counter, according to its type
 * If needed, perform a bit of computation (derivative, mostly)
 * This function must be entered with stats handler lock
 * \param p_counter the counter to update
 * \param val the "new" value
 * \return an error code
 */
455
456
457
static int CounterUpdate( vlc_object_t *p_handler,
                          counter_t *p_counter,
                          vlc_value_t val, vlc_value_t *new_val )
458
459
460
{
    switch( p_counter->i_compute_type )
    {
zorglub's avatar
zorglub committed
461
462
    case STATS_LAST:
    case STATS_MIN:
zorglub's avatar
zorglub committed
463
    case STATS_MAX:
464
465
466
467
468
        if( p_counter->i_samples > 1)
        {
            msg_Err( p_handler, "LAST counter has several samples !" );
            return VLC_EGENERIC;
        }
zorglub's avatar
zorglub committed
469
470
471
472
        if( p_counter->i_type != VLC_VAR_FLOAT &&
            p_counter->i_type != VLC_VAR_INTEGER &&
            p_counter->i_compute_type != STATS_LAST )
        {
zorglub's avatar
zorglub committed
473
            msg_Err( p_handler, "unable to compute MIN or MAX for this type");
zorglub's avatar
zorglub committed
474
475
476
            return VLC_EGENERIC;
        }

477
478
479
480
481
482
483
484
485
486
487
        if( p_counter->i_samples == 0 )
        {
            counter_sample_t *p_new = (counter_sample_t*)malloc(
                                               sizeof( counter_sample_t ) );
            p_new->value.psz_string = NULL;

            INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
                         p_counter->i_samples, p_new );
        }
        if( p_counter->i_samples == 1 )
        {
zorglub's avatar
zorglub committed
488
489
490
491
492
493
494
495
496
497
498
499
500
501
            /* Update if : LAST or (MAX and bigger) or (MIN and bigger) */
            if( p_counter->i_compute_type == STATS_LAST ||
                ( p_counter->i_compute_type == STATS_MAX &&
                   ( ( p_counter->i_type == VLC_VAR_INTEGER &&
                       p_counter->pp_samples[0]->value.i_int > val.i_int ) ||
                     ( p_counter->i_type == VLC_VAR_FLOAT &&
                       p_counter->pp_samples[0]->value.f_float > val.f_float )
                   ) ) ||
                ( p_counter->i_compute_type == STATS_MIN &&
                   ( ( p_counter->i_type == VLC_VAR_INTEGER &&
                       p_counter->pp_samples[0]->value.i_int < val.i_int ) ||
                     ( p_counter->i_type == VLC_VAR_FLOAT &&
                       p_counter->pp_samples[0]->value.f_float < val.f_float )
                   ) ) )
502
            {
zorglub's avatar
zorglub committed
503
504
505
506
507
508
                if( p_counter->i_type == VLC_VAR_STRING &&
                    p_counter->pp_samples[0]->value.psz_string )
                {
                    free( p_counter->pp_samples[0]->value.psz_string );
                }
                p_counter->pp_samples[0]->value = val;
zorglub's avatar
zorglub committed
509
                *new_val = p_counter->pp_samples[0]->value;
510
511
512
            }
        }
        break;
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
    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;
    }
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
    case STATS_COUNTER:
        if( p_counter->i_samples > 1)
        {
            msg_Err( p_handler, "LAST counter has several samples !" );
            return VLC_EGENERIC;
        }
        if( p_counter->i_samples == 0 )
        {
            counter_sample_t *p_new = (counter_sample_t*)malloc(
                                               sizeof( counter_sample_t ) );
            p_new->value.psz_string = NULL;

            INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
                         p_counter->i_samples, p_new );
        }
        if( p_counter->i_samples == 1 )
        {
            switch( p_counter->i_type )
            {
            case VLC_VAR_INTEGER:
                p_counter->pp_samples[0]->value.i_int += val.i_int;
zorglub's avatar
zorglub committed
563
564
                if( new_val )
                    new_val->i_int = p_counter->pp_samples[0]->value.i_int;
565
                break;
zorglub's avatar
zorglub committed
566
567
568
569
            case VLC_VAR_FLOAT:
                p_counter->pp_samples[0]->value.f_float += val.f_float;
                if( new_val )
                    new_val->f_float = p_counter->pp_samples[0]->value.f_float;
570
571
572
573
574
575
576
577
578
579
580
            default:
                msg_Err( p_handler, "Trying to increment invalid variable %s",
                         p_counter->psz_name );
                return VLC_EGENERIC;
            }
        }
        break;
    }
    return VLC_SUCCESS;
}

zorglub's avatar
zorglub committed
581
static void TimerDump( vlc_object_t *p_obj, counter_t *p_counter,
582
                       bool b_total )
zorglub's avatar
zorglub committed
583
584
585
586
587
{
    mtime_t last, total;
    int i_total;
    if( !p_counter || p_counter->i_samples != 2 )
    {
588
        msg_Err( p_obj, "timer %s does not exist", p_counter->psz_name );
zorglub's avatar
zorglub committed
589
590
591
592
        return;
    }
    i_total = p_counter->pp_samples[1]->value.i_int;
    total = p_counter->pp_samples[1]->date;
593
    if( p_counter->pp_samples[0]->value.b_bool == true )
zorglub's avatar
zorglub committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
    {
        last = mdate() - p_counter->pp_samples[0]->date;
        i_total += 1;
        total += last;
    }
    else
    {
        last = p_counter->pp_samples[0]->date;
    }
    if( b_total )
    {
        msg_Dbg( p_obj,
             "TIMER %s : %.3f ms - Total %.3f ms / %i intvls (Avg %.3f ms)",
             p_counter->psz_name, (float)last/1000, (float)total/1000, i_total,
             (float)(total)/(1000*(float)i_total ) );
    }
    else
    {
        msg_Dbg( p_obj,
             "TIMER %s : Total %.3f ms / %i intvls (Avg %.3f ms)",
             p_counter->psz_name, (float)total/1000, i_total,
             (float)(total)/(1000*(float)i_total ) );
    }
}