stats.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:21k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * stats.c: Statistics handling
  3.  *****************************************************************************
  4.  * Copyright (C) 2006 the VideoLAN team
  5.  * $Id: 048b61ba45ac171a220abb1284162c6a82e3eddf $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <stdio.h>                                               /* required */
  31. #include "input/input_internal.h"
  32. /*****************************************************************************
  33.  * Local prototypes
  34.  *****************************************************************************/
  35. static int CounterUpdate( vlc_object_t *p_this,
  36.                           counter_t *p_counter,
  37.                           vlc_value_t val, vlc_value_t * );
  38. static void TimerDump( vlc_object_t *p_this, counter_t *p_counter, bool);
  39. /*****************************************************************************
  40.  * Exported functions
  41.  *****************************************************************************/
  42. /**
  43.  * Create a statistics counter
  44.  * param p_this a VLC object
  45.  * param i_type the type of stored data. One of VLC_VAR_STRING,
  46.  * VLC_VAR_INTEGER, VLC_VAR_FLOAT
  47.  * param i_compute_type the aggregation type. One of STATS_LAST (always
  48.  * keep the last value), STATS_COUNTER (increment by the passed value),
  49.  * STATS_MAX (keep the maximum passed value), STATS_MIN, or STATS_DERIVATIVE
  50.  * (keep a time derivative of the value)
  51.  */
  52. counter_t * __stats_CounterCreate( vlc_object_t *p_this,
  53.                                    int i_type, int i_compute_type )
  54. {
  55.     counter_t *p_counter = (counter_t*) malloc( sizeof( counter_t ) ) ;
  56.     (void)p_this;
  57.     if( !p_counter ) return NULL;
  58.     p_counter->i_compute_type = i_compute_type;
  59.     p_counter->i_type = i_type;
  60.     p_counter->i_samples = 0;
  61.     p_counter->pp_samples = NULL;
  62.     p_counter->psz_name = NULL;
  63.     p_counter->update_interval = 0;
  64.     p_counter->last_update = 0;
  65.     return p_counter;
  66. }
  67. /** Update a counter element with new values
  68.  * param p_this a VLC object
  69.  * param p_counter the counter to update
  70.  * param val the vlc_value union containing the new value to aggregate. For
  71.  * more information on how data is aggregated, see __stats_Create
  72.  * param val_new a pointer that will be filled with new data
  73.  */
  74. int __stats_Update( vlc_object_t *p_this, counter_t *p_counter,
  75.                     vlc_value_t val, vlc_value_t *val_new )
  76. {
  77.     if( !libvlc_stats (p_this) || !p_counter ) return VLC_EGENERIC;
  78.     return CounterUpdate( p_this, p_counter, val, val_new );
  79. }
  80. /** Get the aggregated value for a counter
  81.  * param p_this an object
  82.  * param p_counter the counter
  83.  * param val a pointer to an initialized vlc_value union. It will contain the
  84.  * retrieved value
  85.  * return an error code
  86.  */
  87. int __stats_Get( vlc_object_t *p_this, counter_t *p_counter, vlc_value_t *val )
  88. {
  89.     if( !libvlc_stats (p_this) || !p_counter || p_counter->i_samples == 0 )
  90.     {
  91.         val->i_int = val->f_float = 0.0;
  92.         return VLC_EGENERIC;
  93.     }
  94.     switch( p_counter->i_compute_type )
  95.     {
  96.     case STATS_LAST:
  97.     case STATS_MIN:
  98.     case STATS_MAX:
  99.     case STATS_COUNTER:
  100.         *val = p_counter->pp_samples[0]->value;
  101.         break;
  102.     case STATS_DERIVATIVE:
  103.         /* Not ready yet */
  104.         if( p_counter->i_samples < 2 )
  105.         {
  106.             val->i_int = 0; val->f_float = 0.0;
  107.             return VLC_EGENERIC;
  108.         }
  109.         if( p_counter->i_type == VLC_VAR_INTEGER )
  110.         {
  111.             float f = ( p_counter->pp_samples[0]->value.i_int -
  112.                         p_counter->pp_samples[1]->value.i_int ) /
  113.                     (float)(  p_counter->pp_samples[0]->date -
  114.                               p_counter->pp_samples[1]->date );
  115.             val->i_int = (int)f;
  116.         }
  117.         else
  118.         {
  119.             float f = (float)( p_counter->pp_samples[0]->value.f_float -
  120.                                p_counter->pp_samples[1]->value.f_float ) /
  121.                       (float)( p_counter->pp_samples[0]->date -
  122.                                p_counter->pp_samples[1]->date );
  123.             val->f_float = f;
  124.         }
  125.         break;
  126.     }
  127.     return VLC_SUCCESS;;
  128. }
  129. input_stats_t *stats_NewInputStats( input_thread_t *p_input )
  130. {
  131.     (void)p_input;
  132.     input_stats_t *p_stats = calloc( 1, sizeof(input_stats_t) );
  133.     if( !p_stats )
  134.         return NULL;
  135.     vlc_mutex_init( &p_stats->lock );
  136.     stats_ReinitInputStats( p_stats );
  137.     return p_stats;
  138. }
  139. void stats_ComputeInputStats( input_thread_t *p_input, input_stats_t *p_stats )
  140. {
  141.     if( !libvlc_stats (p_input) ) return;
  142.     vlc_mutex_lock( &p_input->p->counters.counters_lock );
  143.     vlc_mutex_lock( &p_stats->lock );
  144.     /* Input */
  145.     stats_GetInteger( p_input, p_input->p->counters.p_read_packets,
  146.                       &p_stats->i_read_packets );
  147.     stats_GetInteger( p_input, p_input->p->counters.p_read_bytes,
  148.                       &p_stats->i_read_bytes );
  149.     stats_GetFloat( p_input, p_input->p->counters.p_input_bitrate,
  150.                     &p_stats->f_input_bitrate );
  151.     stats_GetInteger( p_input, p_input->p->counters.p_demux_read,
  152.                       &p_stats->i_demux_read_bytes );
  153.     stats_GetFloat( p_input, p_input->p->counters.p_demux_bitrate,
  154.                     &p_stats->f_demux_bitrate );
  155.     stats_GetInteger( p_input, p_input->p->counters.p_demux_corrupted,
  156.                       &p_stats->i_demux_corrupted );
  157.     stats_GetInteger( p_input, p_input->p->counters.p_demux_discontinuity,
  158.                       &p_stats->i_demux_discontinuity );
  159.     /* Decoders */
  160.     stats_GetInteger( p_input, p_input->p->counters.p_decoded_video,
  161.                       &p_stats->i_decoded_video );
  162.     stats_GetInteger( p_input, p_input->p->counters.p_decoded_audio,
  163.                       &p_stats->i_decoded_audio );
  164.     /* Sout */
  165.     if( p_input->p->counters.p_sout_send_bitrate )
  166.     {
  167.         stats_GetInteger( p_input, p_input->p->counters.p_sout_sent_packets,
  168.                           &p_stats->i_sent_packets );
  169.         stats_GetInteger( p_input, p_input->p->counters.p_sout_sent_bytes,
  170.                           &p_stats->i_sent_bytes );
  171.         stats_GetFloat  ( p_input, p_input->p->counters.p_sout_send_bitrate,
  172.                           &p_stats->f_send_bitrate );
  173.     }
  174.     /* Aout */
  175.     stats_GetInteger( p_input, p_input->p->counters.p_played_abuffers,
  176.                       &p_stats->i_played_abuffers );
  177.     stats_GetInteger( p_input, p_input->p->counters.p_lost_abuffers,
  178.                       &p_stats->i_lost_abuffers );
  179.     /* Vouts */
  180.     stats_GetInteger( p_input, p_input->p->counters.p_displayed_pictures,
  181.                       &p_stats->i_displayed_pictures );
  182.     stats_GetInteger( p_input, p_input->p->counters.p_lost_pictures,
  183.                       &p_stats->i_lost_pictures );
  184.     vlc_mutex_unlock( &p_stats->lock );
  185.     vlc_mutex_unlock( &p_input->p->counters.counters_lock );
  186. }
  187. void stats_ReinitInputStats( input_stats_t *p_stats )
  188. {
  189.     vlc_mutex_lock( &p_stats->lock );
  190.     p_stats->i_read_packets = p_stats->i_read_bytes =
  191.     p_stats->f_input_bitrate = p_stats->f_average_input_bitrate =
  192.     p_stats->i_demux_read_packets = p_stats->i_demux_read_bytes =
  193.     p_stats->f_demux_bitrate = p_stats->f_average_demux_bitrate =
  194.     p_stats->i_demux_corrupted = p_stats->i_demux_discontinuity =
  195.     p_stats->i_displayed_pictures = p_stats->i_lost_pictures =
  196.     p_stats->i_played_abuffers = p_stats->i_lost_abuffers =
  197.     p_stats->i_decoded_video = p_stats->i_decoded_audio =
  198.     p_stats->i_sent_bytes = p_stats->i_sent_packets = p_stats->f_send_bitrate
  199.      = 0;
  200.     vlc_mutex_unlock( &p_stats->lock );
  201. }
  202. void stats_DumpInputStats( input_stats_t *p_stats  )
  203. {
  204.     vlc_mutex_lock( &p_stats->lock );
  205.     /* f_bitrate is in bytes / microsecond
  206.      * *1000 => bytes / millisecond => kbytes / seconds */
  207.     fprintf( stderr, "Input : %i (%i bytes) - %f kB/s - "
  208.                      "Demux : %i (%i bytes) - %f kB/sn"
  209.                      " - Vout : %i/%i - Aout : %i/%i - Sout : %fn",
  210.                     p_stats->i_read_packets, p_stats->i_read_bytes,
  211.                     p_stats->f_input_bitrate * 1000,
  212.                     p_stats->i_demux_read_packets, p_stats->i_demux_read_bytes,
  213.                     p_stats->f_demux_bitrate * 1000,
  214.                     p_stats->i_displayed_pictures, p_stats->i_lost_pictures,
  215.                     p_stats->i_played_abuffers, p_stats->i_lost_abuffers,
  216.                     p_stats->f_send_bitrate );
  217.     vlc_mutex_unlock( &p_stats->lock );
  218. }
  219. void __stats_TimerStart( vlc_object_t *p_obj, const char *psz_name,
  220.                          unsigned int i_id )
  221. {
  222.     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
  223.     counter_t *p_counter = NULL;
  224.     if( !priv->b_stats ) return;
  225.     vlc_mutex_lock( &priv->timer_lock );
  226.     for( int i = 0 ; i < priv->i_timers; i++ )
  227.     {
  228.         if( priv->pp_timers[i]->i_id == i_id
  229.             && priv->pp_timers[i]->p_obj == p_obj )
  230.         {
  231.             p_counter = priv->pp_timers[i];
  232.             break;
  233.         }
  234.     }
  235.     if( !p_counter )
  236.     {
  237.         counter_sample_t *p_sample;
  238.         p_counter = stats_CounterCreate( p_obj->p_libvlc, VLC_VAR_TIME,
  239.                                          STATS_TIMER );
  240.         if( !p_counter )
  241.             goto out;
  242.         p_counter->psz_name = strdup( psz_name );
  243.         p_counter->i_id = i_id;
  244.         p_counter->p_obj = p_obj;
  245.         INSERT_ELEM( priv->pp_timers, priv->i_timers,
  246.                      priv->i_timers, p_counter );
  247.         /* 1st sample : if started: start_date, else last_time, b_started */
  248.         p_sample = (counter_sample_t *)malloc( sizeof( counter_sample_t ) );
  249.         INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
  250.                      p_counter->i_samples, p_sample );
  251.         p_sample->date = 0; p_sample->value.b_bool = 0;
  252.         /* 2nd sample : global_time, i_samples */
  253.         p_sample = (counter_sample_t *)malloc( sizeof( counter_sample_t ) );
  254.         INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
  255.                      p_counter->i_samples, p_sample );
  256.         p_sample->date = 0; p_sample->value.i_int = 0;
  257.     }
  258.     if( p_counter->pp_samples[0]->value.b_bool == true )
  259.     {
  260.         msg_Warn( p_obj, "timer '%s' was already started !", psz_name );
  261.         goto out;
  262.     }
  263.     p_counter->pp_samples[0]->value.b_bool = true;
  264.     p_counter->pp_samples[0]->date = mdate();
  265. out:
  266.     vlc_mutex_unlock( &priv->timer_lock );
  267. }
  268. void __stats_TimerStop( vlc_object_t *p_obj, unsigned int i_id )
  269. {
  270.     counter_t *p_counter = NULL;
  271.     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
  272.     if( !priv->b_stats ) return;
  273.     vlc_mutex_lock( &priv->timer_lock );
  274.     for( int i = 0 ; i < priv->i_timers; i++ )
  275.     {
  276.         if( priv->pp_timers[i]->i_id == i_id
  277.             && priv->pp_timers[i]->p_obj == p_obj )
  278.         {
  279.             p_counter = priv->pp_timers[i];
  280.             break;
  281.         }
  282.     }
  283.     if( !p_counter || p_counter->i_samples != 2 )
  284.     {
  285.         msg_Err( p_obj, "timer does not exist" );
  286.         goto out;
  287.     }
  288.     p_counter->pp_samples[0]->value.b_bool = false;
  289.     p_counter->pp_samples[1]->value.i_int += 1;
  290.     p_counter->pp_samples[0]->date = mdate() - p_counter->pp_samples[0]->date;
  291.     p_counter->pp_samples[1]->date += p_counter->pp_samples[0]->date;
  292. out:
  293.     vlc_mutex_unlock( &priv->timer_lock );
  294. }
  295. void __stats_TimerDump( vlc_object_t *p_obj, unsigned int i_id )
  296. {
  297.     counter_t *p_counter = NULL;
  298.     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
  299.     if( !priv->b_stats ) return;
  300.     vlc_mutex_lock( &priv->timer_lock );
  301.     for( int i = 0 ; i < priv->i_timers; i++ )
  302.     {
  303.         if( priv->pp_timers[i]->i_id == i_id
  304.             && priv->pp_timers[i]->p_obj == p_obj )
  305.         {
  306.             p_counter = priv->pp_timers[i];
  307.             break;
  308.         }
  309.     }
  310.     TimerDump( p_obj, p_counter, true );
  311.     vlc_mutex_unlock( &priv->timer_lock );
  312. }
  313. void __stats_TimersDumpAll( vlc_object_t *p_obj )
  314. {
  315.     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
  316.     if( !priv->b_stats ) return;
  317.     vlc_mutex_lock( &priv->timer_lock );
  318.     for ( int i = 0 ; i < priv->i_timers ; i++ )
  319.         TimerDump( p_obj, priv->pp_timers[i], false );
  320.     vlc_mutex_unlock( &priv->timer_lock );
  321. }
  322. void __stats_TimerClean( vlc_object_t *p_obj, unsigned int i_id )
  323. {
  324.     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
  325.     vlc_mutex_lock( &priv->timer_lock );
  326.     for ( int i = priv->i_timers -1 ; i >= 0; i-- )
  327.     {
  328.         counter_t *p_counter = priv->pp_timers[i];
  329.         if( p_counter->i_id == i_id && p_counter->p_obj == p_obj )
  330.         {
  331.             REMOVE_ELEM( priv->pp_timers, priv->i_timers, i );
  332.             stats_CounterClean( p_counter );
  333.         }
  334.     }
  335.     vlc_mutex_unlock( &priv->timer_lock );
  336. }
  337. void __stats_TimersCleanAll( vlc_object_t *p_obj )
  338. {
  339.     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
  340.     vlc_mutex_lock( &priv->timer_lock );
  341.     for ( int i = priv->i_timers -1 ; i >= 0; i-- )
  342.     {
  343.         counter_t *p_counter = priv->pp_timers[i];
  344.         REMOVE_ELEM( priv->pp_timers, priv->i_timers, i );
  345.         stats_CounterClean( p_counter );
  346.     }
  347.     vlc_mutex_unlock( &priv->timer_lock );
  348. }
  349. void stats_CounterClean( counter_t *p_c )
  350. {
  351.     if( p_c )
  352.     {
  353.         int i = p_c->i_samples - 1 ;
  354.         while( i >= 0 )
  355.         {
  356.             counter_sample_t *p_s = p_c->pp_samples[i];
  357.             REMOVE_ELEM( p_c->pp_samples, p_c->i_samples, i );
  358.             free( p_s );
  359.             i--;
  360.         }
  361.         free( p_c->psz_name );
  362.         free( p_c );
  363.     }
  364. }
  365. /********************************************************************
  366.  * Following functions are local
  367.  ********************************************************************/
  368. /**
  369.  * Update a statistics counter, according to its type
  370.  * If needed, perform a bit of computation (derivative, mostly)
  371.  * This function must be entered with stats handler lock
  372.  * param p_counter the counter to update
  373.  * param val the "new" value
  374.  * return an error code
  375.  */
  376. static int CounterUpdate( vlc_object_t *p_handler,
  377.                           counter_t *p_counter,
  378.                           vlc_value_t val, vlc_value_t *new_val )
  379. {
  380.     switch( p_counter->i_compute_type )
  381.     {
  382.     case STATS_LAST:
  383.     case STATS_MIN:
  384.     case STATS_MAX:
  385.         if( p_counter->i_samples > 1)
  386.         {
  387.             msg_Err( p_handler, "LAST counter has several samples !" );
  388.             return VLC_EGENERIC;
  389.         }
  390.         if( p_counter->i_type != VLC_VAR_FLOAT &&
  391.             p_counter->i_type != VLC_VAR_INTEGER &&
  392.             p_counter->i_compute_type != STATS_LAST )
  393.         {
  394.             msg_Err( p_handler, "unable to compute MIN or MAX for this type");
  395.             return VLC_EGENERIC;
  396.         }
  397.         if( p_counter->i_samples == 0 )
  398.         {
  399.             counter_sample_t *p_new = (counter_sample_t*)malloc(
  400.                                                sizeof( counter_sample_t ) );
  401.             p_new->value.psz_string = NULL;
  402.             INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
  403.                          p_counter->i_samples, p_new );
  404.         }
  405.         if( p_counter->i_samples == 1 )
  406.         {
  407.             /* Update if : LAST or (MAX and bigger) or (MIN and bigger) */
  408.             if( p_counter->i_compute_type == STATS_LAST ||
  409.                 ( p_counter->i_compute_type == STATS_MAX &&
  410.                    ( ( p_counter->i_type == VLC_VAR_INTEGER &&
  411.                        p_counter->pp_samples[0]->value.i_int > val.i_int ) ||
  412.                      ( p_counter->i_type == VLC_VAR_FLOAT &&
  413.                        p_counter->pp_samples[0]->value.f_float > val.f_float )
  414.                    ) ) ||
  415.                 ( p_counter->i_compute_type == STATS_MIN &&
  416.                    ( ( p_counter->i_type == VLC_VAR_INTEGER &&
  417.                        p_counter->pp_samples[0]->value.i_int < val.i_int ) ||
  418.                      ( p_counter->i_type == VLC_VAR_FLOAT &&
  419.                        p_counter->pp_samples[0]->value.f_float < val.f_float )
  420.                    ) ) )
  421.             {
  422.                 if( p_counter->i_type == VLC_VAR_STRING &&
  423.                     p_counter->pp_samples[0]->value.psz_string )
  424.                 {
  425.                     free( p_counter->pp_samples[0]->value.psz_string );
  426.                 }
  427.                 p_counter->pp_samples[0]->value = val;
  428.                 *new_val = p_counter->pp_samples[0]->value;
  429.             }
  430.         }
  431.         break;
  432.     case STATS_DERIVATIVE:
  433.     {
  434.         counter_sample_t *p_new, *p_old;
  435.         mtime_t now = mdate();
  436.         if( now - p_counter->last_update < p_counter->update_interval )
  437.         {
  438.             return VLC_EGENERIC;
  439.         }
  440.         p_counter->last_update = now;
  441.         if( p_counter->i_type != VLC_VAR_FLOAT &&
  442.             p_counter->i_type != VLC_VAR_INTEGER )
  443.         {
  444.             msg_Err( p_handler, "Unable to compute DERIVATIVE for this type");
  445.             return VLC_EGENERIC;
  446.         }
  447.         /* Insert the new one at the beginning */
  448.         p_new = (counter_sample_t*)malloc( sizeof( counter_sample_t ) );
  449.         p_new->value = val;
  450.         p_new->date = p_counter->last_update;
  451.         INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
  452.                      0, p_new );
  453.         if( p_counter->i_samples == 3 )
  454.         {
  455.             p_old = p_counter->pp_samples[2];
  456.             REMOVE_ELEM( p_counter->pp_samples, p_counter->i_samples, 2 );
  457.             free( p_old );
  458.         }
  459.         break;
  460.     }
  461.     case STATS_COUNTER:
  462.         if( p_counter->i_samples > 1)
  463.         {
  464.             msg_Err( p_handler, "LAST counter has several samples !" );
  465.             return VLC_EGENERIC;
  466.         }
  467.         if( p_counter->i_samples == 0 )
  468.         {
  469.             counter_sample_t *p_new = (counter_sample_t*)malloc(
  470.                                                sizeof( counter_sample_t ) );
  471.             p_new->value.psz_string = NULL;
  472.             INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples,
  473.                          p_counter->i_samples, p_new );
  474.         }
  475.         if( p_counter->i_samples == 1 )
  476.         {
  477.             switch( p_counter->i_type )
  478.             {
  479.             case VLC_VAR_INTEGER:
  480.                 p_counter->pp_samples[0]->value.i_int += val.i_int;
  481.                 if( new_val )
  482.                     new_val->i_int = p_counter->pp_samples[0]->value.i_int;
  483.                 break;
  484.             case VLC_VAR_FLOAT:
  485.                 p_counter->pp_samples[0]->value.f_float += val.f_float;
  486.                 if( new_val )
  487.                     new_val->f_float = p_counter->pp_samples[0]->value.f_float;
  488.             default:
  489.                 msg_Err( p_handler, "Trying to increment invalid variable %s",
  490.                          p_counter->psz_name );
  491.                 return VLC_EGENERIC;
  492.             }
  493.         }
  494.         break;
  495.     }
  496.     return VLC_SUCCESS;
  497. }
  498. static void TimerDump( vlc_object_t *p_obj, counter_t *p_counter,
  499.                        bool b_total )
  500. {
  501.     if( !p_counter )
  502.         return;
  503.     mtime_t last, total;
  504.     int i_total;
  505.     if( p_counter->i_samples != 2 )
  506.     {
  507.         msg_Err( p_obj, "timer %s does not exist", p_counter->psz_name );
  508.         return;
  509.     }
  510.     i_total = p_counter->pp_samples[1]->value.i_int;
  511.     total = p_counter->pp_samples[1]->date;
  512.     if( p_counter->pp_samples[0]->value.b_bool == true )
  513.     {
  514.         last = mdate() - p_counter->pp_samples[0]->date;
  515.         i_total += 1;
  516.         total += last;
  517.     }
  518.     else
  519.     {
  520.         last = p_counter->pp_samples[0]->date;
  521.     }
  522.     if( b_total )
  523.     {
  524.         msg_Dbg( p_obj,
  525.              "TIMER %s : %.3f ms - Total %.3f ms / %i intvls (Avg %.3f ms)",
  526.              p_counter->psz_name, (float)last/1000, (float)total/1000, i_total,
  527.              (float)(total)/(1000*(float)i_total ) );
  528.     }
  529.     else
  530.     {
  531.         msg_Dbg( p_obj,
  532.              "TIMER %s : Total %.3f ms / %i intvls (Avg %.3f ms)",
  533.              p_counter->psz_name, (float)total/1000, i_total,
  534.              (float)(total)/(1000*(float)i_total ) );
  535.     }
  536. }