summaryrefslogtreecommitdiff
path: root/pjlib/src/pj/os_timestamp_common.c
blob: 630ffb2776b092617ff45231095d34c0b2e60b75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_common.c 2     10/14/05 12:26a Bennylp $ */
/* 
 * $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_common.c $
 * 
 * 2     10/14/05 12:26a Bennylp
 * Finished error code framework, some fixes in ioqueue, etc. Pretty
 * major.
 * 
 * 1     10/09/05 2:56p Bennylp
 * Created.
 * 
 */
#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)

static pj_highprec_t get_elapsed( const pj_timestamp *start,
                                  const pj_timestamp *stop )
{
    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;
}

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 */
    freq = ts_freq.u32.hi;
    pj_highprec_mul(freq, U32MAX);
    freq += ts_freq.u32.lo;

    /* 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 */
    freq = ts_freq.u32.hi;
    pj_highprec_mul(freq, U32MAX);
    freq += ts_freq.u32.lo;

    /* 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_time_val) pj_elapsed_time( const pj_timestamp *start,
                                     const pj_timestamp *stop )
{
    pj_highprec_t elapsed = elapsed_usec(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, USEC);
        tv_elapsed.sec = (long)sec;

        msec = elapsed;
        pj_highprec_mod(msec, USEC);
        pj_highprec_div(msec, 1000);
        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 */