blob: 293f61622e43d98a0816285746f586cca95a0e29 [file] [log] [blame]
/* $Id$ */
/*
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* 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
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/os.h>
#include <pj/compat/high_precision.h>
#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
#define U32MAX (0xFFFFFFFFUL)
#define NANOSEC (1000000000UL)
#define USEC (1000000UL)
#define MSEC (1000)
#define u64tohighprec(u64) ((pj_highprec_t)((pj_int64_t)(u64)))
static pj_highprec_t get_elapsed( const pj_timestamp *start,
const pj_timestamp *stop )
{
#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
return u64tohighprec(stop->u64 - start->u64);
#else
pj_highprec_t elapsed_hi, elapsed_lo;
elapsed_hi = stop->u32.hi - start->u32.hi;
elapsed_lo = stop->u32.lo - start->u32.lo;
/* elapsed_hi = elapsed_hi * U32MAX */
pj_highprec_mul(elapsed_hi, U32MAX);
return elapsed_hi + elapsed_lo;
#endif
}
static pj_highprec_t elapsed_msec( const pj_timestamp *start,
const pj_timestamp *stop )
{
pj_timestamp ts_freq;
pj_highprec_t freq, elapsed;
if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
return 0;
/* Convert frequency timestamp */
#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
freq = u64tohighprec(ts_freq.u64);
#else
freq = ts_freq.u32.hi;
pj_highprec_mul(freq, U32MAX);
freq += ts_freq.u32.lo;
#endif
/* Avoid division by zero. */
if (freq == 0) freq = 1;
/* Get elapsed time in cycles. */
elapsed = get_elapsed(start, stop);
/* usec = elapsed * MSEC / freq */
pj_highprec_mul(elapsed, MSEC);
pj_highprec_div(elapsed, freq);
return elapsed;
}
static pj_highprec_t elapsed_usec( const pj_timestamp *start,
const pj_timestamp *stop )
{
pj_timestamp ts_freq;
pj_highprec_t freq, elapsed;
if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
return 0;
/* Convert frequency timestamp */
#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
freq = u64tohighprec(ts_freq.u64);
#else
freq = ts_freq.u32.hi;
pj_highprec_mul(freq, U32MAX);
freq += ts_freq.u32.lo;
#endif
/* Avoid division by zero. */
if (freq == 0) freq = 1;
/* Get elapsed time in cycles. */
elapsed = get_elapsed(start, stop);
/* usec = elapsed * USEC / freq */
pj_highprec_mul(elapsed, USEC);
pj_highprec_div(elapsed, freq);
return elapsed;
}
PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
const pj_timestamp *stop )
{
pj_timestamp ts_freq;
pj_highprec_t freq, elapsed;
if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
return 0;
/* Convert frequency timestamp */
#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
freq = u64tohighprec(ts_freq.u64);
#else
freq = ts_freq.u32.hi;
pj_highprec_mul(freq, U32MAX);
freq += ts_freq.u32.lo;
#endif
/* Avoid division by zero. */
if (freq == 0) freq = 1;
/* Get elapsed time in cycles. */
elapsed = get_elapsed(start, stop);
/* usec = elapsed * USEC / freq */
pj_highprec_mul(elapsed, NANOSEC);
pj_highprec_div(elapsed, freq);
return (pj_uint32_t)elapsed;
}
PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
const pj_timestamp *stop )
{
return (pj_uint32_t)elapsed_usec(start, stop);
}
PJ_DEF(pj_uint32_t) pj_elapsed_msec( const pj_timestamp *start,
const pj_timestamp *stop )
{
return (pj_uint32_t)elapsed_msec(start, stop);
}
PJ_DEF(pj_uint64_t) pj_elapsed_msec64(const pj_timestamp *start,
const pj_timestamp *stop )
{
return (pj_uint64_t)elapsed_msec(start, stop);
}
PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
const pj_timestamp *stop )
{
pj_highprec_t elapsed = elapsed_msec(start, stop);
pj_time_val tv_elapsed;
if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {
tv_elapsed.sec = tv_elapsed.msec = 0;
return tv_elapsed;
} else {
pj_highprec_t sec, msec;
sec = elapsed;
pj_highprec_div(sec, MSEC);
tv_elapsed.sec = (long)sec;
msec = elapsed;
pj_highprec_mod(msec, MSEC);
tv_elapsed.msec = (long)msec;
return tv_elapsed;
}
}
PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
const pj_timestamp *stop )
{
return stop->u32.lo - start->u32.lo;
}
#endif /* PJ_HAS_HIGH_RES_TIMER */