stats.c 7.04 KB
Newer Older
1 2 3
/*****************************************************************************
 * stats.c: Statistics handling
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2006 VLC authors and VideoLAN
5
 * $Id$
6
 *
7
 * Authors: Clément Stenac <zorglub@videolan.org>
8
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
9 10 11
 * This program 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.1 of the License, or
12 13 14 15
 * (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
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
19 20 21
 * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23
 *****************************************************************************/

24 25 26 27
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

28
#include <vlc_common.h>
29
#include "input/input_internal.h"
30

31 32 33 34 35 36 37
/**
 * Create a statistics counter
 * \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)
 */
38
counter_t * stats_CounterCreate( int i_compute_type )
39
{
Clément Stenac's avatar
Clément Stenac committed
40
    counter_t *p_counter = (counter_t*) malloc( sizeof( counter_t ) ) ;
41

42
    if( !p_counter ) return NULL;
43 44 45 46
    p_counter->i_compute_type = i_compute_type;
    p_counter->i_samples = 0;
    p_counter->pp_samples = NULL;

47 48
    p_counter->last_update = 0;

49
    return p_counter;
50 51
}

52
static inline int64_t stats_GetTotal(const counter_t *counter)
53
{
54 55 56
    if (counter == NULL || counter->i_samples == 0)
        return 0;
    return counter->pp_samples[0]->value;
57 58
}

59
static inline float stats_GetRate(const counter_t *counter)
60
{
61 62
    if (counter == NULL || counter->i_samples < 2)
        return 0.;
63

64 65
    return (counter->pp_samples[0]->value - counter->pp_samples[1]->value)
        / (float)(counter->pp_samples[0]->date - counter->pp_samples[1]->date);
66 67
}

68 69
input_stats_t *stats_NewInputStats( input_thread_t *p_input )
{
70
    (void)p_input;
71
    input_stats_t *p_stats = calloc( 1, sizeof(input_stats_t) );
72 73 74
    if( !p_stats )
        return NULL;

75
    vlc_mutex_init( &p_stats->lock );
76 77 78 79 80
    stats_ReinitInputStats( p_stats );

    return p_stats;
}

81
void stats_ComputeInputStats(input_thread_t *input, input_stats_t *st)
82
{
83 84
    input_thread_private_t *priv = input_priv(input);

85 86
    if (!libvlc_stats(input))
        return;
87

88
    vlc_mutex_lock(&priv->counters.counters_lock);
89
    vlc_mutex_lock(&st->lock);
90 91

    /* Input */
92 93 94 95 96 97 98
    st->i_read_packets = stats_GetTotal(priv->counters.p_read_packets);
    st->i_read_bytes = stats_GetTotal(priv->counters.p_read_bytes);
    st->f_input_bitrate = stats_GetRate(priv->counters.p_input_bitrate);
    st->i_demux_read_bytes = stats_GetTotal(priv->counters.p_demux_read);
    st->f_demux_bitrate = stats_GetRate(priv->counters.p_demux_bitrate);
    st->i_demux_corrupted = stats_GetTotal(priv->counters.p_demux_corrupted);
    st->i_demux_discontinuity = stats_GetTotal(priv->counters.p_demux_discontinuity);
99

100
    /* Decoders */
101 102
    st->i_decoded_video = stats_GetTotal(priv->counters.p_decoded_video);
    st->i_decoded_audio = stats_GetTotal(priv->counters.p_decoded_audio);
103

104
    /* Sout */
105
    if (priv->counters.p_sout_send_bitrate)
106
    {
107 108 109
        st->i_sent_packets = stats_GetTotal(priv->counters.p_sout_sent_packets);
        st->i_sent_bytes = stats_GetTotal(priv->counters.p_sout_sent_bytes);
        st->f_send_bitrate = stats_GetRate(priv->counters.p_sout_send_bitrate);
110 111 112
    }

    /* Aout */
113 114
    st->i_played_abuffers = stats_GetTotal(priv->counters.p_played_abuffers);
    st->i_lost_abuffers = stats_GetTotal(priv->counters.p_lost_abuffers);
Clément Stenac's avatar
Clément Stenac committed
115

116
    /* Vouts */
117 118
    st->i_displayed_pictures = stats_GetTotal(priv->counters.p_displayed_pictures);
    st->i_lost_pictures = stats_GetTotal(priv->counters.p_lost_pictures);
Clément Stenac's avatar
Clément Stenac committed
119

120
    vlc_mutex_unlock(&st->lock);
121
    vlc_mutex_unlock(&priv->counters.counters_lock);
122 123 124 125
}

void stats_ReinitInputStats( input_stats_t *p_stats )
{
126
    vlc_mutex_lock( &p_stats->lock );
127
    p_stats->i_read_packets = p_stats->i_read_bytes =
128 129 130
    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 =
131
    p_stats->i_demux_corrupted = p_stats->i_demux_discontinuity =
132
    p_stats->i_displayed_pictures = p_stats->i_lost_pictures =
Clément Stenac's avatar
Clément Stenac committed
133
    p_stats->i_played_abuffers = p_stats->i_lost_abuffers =
134 135 136
    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;
137
    vlc_mutex_unlock( &p_stats->lock );
138 139
}

140 141
void stats_CounterClean( counter_t *p_c )
{
142
    if( p_c )
143
    {
144 145 146
        for( int i = 0; i < p_c->i_samples; i++ )
            free( p_c->pp_samples[i] );
        TAB_CLEAN(p_c->i_samples, p_c->pp_samples);
147
        free( p_c );
148
    }
149 150
}

151

152
/** Update a counter element with new values
153
 * \param p_counter the counter to update
154 155 156
 * \param val the vlc_value union containing the new value to aggregate. For
 * more information on how data is aggregated, \see stats_Create
 * \param val_new a pointer that will be filled with new data
157
 */
158
void stats_Update( counter_t *p_counter, uint64_t val, uint64_t *new_val )
159
{
160 161 162
    if( !p_counter )
        return;

163 164
    switch( p_counter->i_compute_type )
    {
165 166 167
    case STATS_DERIVATIVE:
    {
        counter_sample_t *p_new, *p_old;
168
        mtime_t now = mdate();
169
        if( now - p_counter->last_update < CLOCK_FREQ )
170
            return;
171
        p_counter->last_update = now;
172 173
        /* Insert the new one at the beginning */
        p_new = (counter_sample_t*)malloc( sizeof( counter_sample_t ) );
174 175 176
        if (unlikely(p_new == NULL))
            return; /* NOTE: Losing sample here */

177 178
        p_new->value = val;
        p_new->date = p_counter->last_update;
179
        TAB_INSERT(p_counter->i_samples, p_counter->pp_samples, p_new, 0);
180 181 182 183

        if( p_counter->i_samples == 3 )
        {
            p_old = p_counter->pp_samples[2];
184
            TAB_ERASE(p_counter->i_samples, p_counter->pp_samples, 2);
185 186 187 188
            free( p_old );
        }
        break;
    }
189 190 191 192 193
    case STATS_COUNTER:
        if( p_counter->i_samples == 0 )
        {
            counter_sample_t *p_new = (counter_sample_t*)malloc(
                                               sizeof( counter_sample_t ) );
194 195 196
            if (unlikely(p_new == NULL))
                return; /* NOTE: Losing sample here */

197
            p_new->value = 0;
198

199
            TAB_APPEND(p_counter->i_samples, p_counter->pp_samples, p_new);
200 201 202
        }
        if( p_counter->i_samples == 1 )
        {
203 204 205
            p_counter->pp_samples[0]->value += val;
            if( new_val )
                *new_val = p_counter->pp_samples[0]->value;
206 207 208 209
        }
        break;
    }
}