1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <pj/os.h>
21 #include <pj/compat/high_precision.h>
22 
23 #if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
24 
25 #define U32MAX  (0xFFFFFFFFUL)
26 #define NANOSEC (1000000000UL)
27 #define USEC    (1000000UL)
28 #define MSEC    (1000)
29 
30 #define u64tohighprec(u64)	((pj_highprec_t)((pj_int64_t)(u64)))
31 
get_elapsed(const pj_timestamp * start,const pj_timestamp * stop)32 static pj_highprec_t get_elapsed( const pj_timestamp *start,
33                                   const pj_timestamp *stop )
34 {
35 #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
36     return u64tohighprec(stop->u64 - start->u64);
37 #else
38     pj_highprec_t elapsed_hi, elapsed_lo;
39 
40     elapsed_hi = stop->u32.hi - start->u32.hi;
41     elapsed_lo = stop->u32.lo - start->u32.lo;
42 
43     /* elapsed_hi = elapsed_hi * U32MAX */
44     pj_highprec_mul(elapsed_hi, U32MAX);
45 
46     return elapsed_hi + elapsed_lo;
47 #endif
48 }
49 
elapsed_msec(const pj_timestamp * start,const pj_timestamp * stop)50 static pj_highprec_t elapsed_msec( const pj_timestamp *start,
51                                    const pj_timestamp *stop )
52 {
53     pj_timestamp ts_freq;
54     pj_highprec_t freq, elapsed;
55 
56     if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
57         return 0;
58 
59     /* Convert frequency timestamp */
60 #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
61     freq = u64tohighprec(ts_freq.u64);
62 #else
63     freq = ts_freq.u32.hi;
64     pj_highprec_mul(freq, U32MAX);
65     freq += ts_freq.u32.lo;
66 #endif
67 
68     /* Avoid division by zero. */
69     if (freq == 0) freq = 1;
70 
71     /* Get elapsed time in cycles. */
72     elapsed = get_elapsed(start, stop);
73 
74     /* usec = elapsed * MSEC / freq */
75     pj_highprec_mul(elapsed, MSEC);
76     pj_highprec_div(elapsed, freq);
77 
78     return elapsed;
79 }
80 
elapsed_usec(const pj_timestamp * start,const pj_timestamp * stop)81 static pj_highprec_t elapsed_usec( const pj_timestamp *start,
82                                    const pj_timestamp *stop )
83 {
84     pj_timestamp ts_freq;
85     pj_highprec_t freq, elapsed;
86 
87     if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
88         return 0;
89 
90     /* Convert frequency timestamp */
91 #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
92     freq = u64tohighprec(ts_freq.u64);
93 #else
94     freq = ts_freq.u32.hi;
95     pj_highprec_mul(freq, U32MAX);
96     freq += ts_freq.u32.lo;
97 #endif
98 
99     /* Avoid division by zero. */
100     if (freq == 0) freq = 1;
101 
102     /* Get elapsed time in cycles. */
103     elapsed = get_elapsed(start, stop);
104 
105     /* usec = elapsed * USEC / freq */
106     pj_highprec_mul(elapsed, USEC);
107     pj_highprec_div(elapsed, freq);
108 
109     return elapsed;
110 }
111 
pj_elapsed_nanosec(const pj_timestamp * start,const pj_timestamp * stop)112 PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
113                                         const pj_timestamp *stop )
114 {
115     pj_timestamp ts_freq;
116     pj_highprec_t freq, elapsed;
117 
118     if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
119         return 0;
120 
121     /* Convert frequency timestamp */
122 #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
123     freq = u64tohighprec(ts_freq.u64);
124 #else
125     freq = ts_freq.u32.hi;
126     pj_highprec_mul(freq, U32MAX);
127     freq += ts_freq.u32.lo;
128 #endif
129 
130     /* Avoid division by zero. */
131     if (freq == 0) freq = 1;
132 
133     /* Get elapsed time in cycles. */
134     elapsed = get_elapsed(start, stop);
135 
136     /* usec = elapsed * USEC / freq */
137     pj_highprec_mul(elapsed, NANOSEC);
138     pj_highprec_div(elapsed, freq);
139 
140     return (pj_uint32_t)elapsed;
141 }
142 
pj_elapsed_usec(const pj_timestamp * start,const pj_timestamp * stop)143 PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
144                                      const pj_timestamp *stop )
145 {
146     return (pj_uint32_t)elapsed_usec(start, stop);
147 }
148 
pj_elapsed_msec(const pj_timestamp * start,const pj_timestamp * stop)149 PJ_DEF(pj_uint32_t) pj_elapsed_msec( const pj_timestamp *start,
150                                      const pj_timestamp *stop )
151 {
152     return (pj_uint32_t)elapsed_msec(start, stop);
153 }
154 
pj_elapsed_msec64(const pj_timestamp * start,const pj_timestamp * stop)155 PJ_DEF(pj_uint64_t) pj_elapsed_msec64(const pj_timestamp *start,
156                                       const pj_timestamp *stop )
157 {
158     return (pj_uint64_t)elapsed_msec(start, stop);
159 }
160 
pj_elapsed_time(const pj_timestamp * start,const pj_timestamp * stop)161 PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
162                                      const pj_timestamp *stop )
163 {
164     pj_highprec_t elapsed = elapsed_msec(start, stop);
165     pj_time_val tv_elapsed;
166 
167     if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {
168         tv_elapsed.sec = tv_elapsed.msec = 0;
169         return tv_elapsed;
170     } else {
171         pj_highprec_t sec, msec;
172 
173         sec = elapsed;
174         pj_highprec_div(sec, MSEC);
175         tv_elapsed.sec = (long)sec;
176 
177         msec = elapsed;
178         pj_highprec_mod(msec, MSEC);
179         tv_elapsed.msec = (long)msec;
180 
181         return tv_elapsed;
182     }
183 }
184 
pj_elapsed_cycle(const pj_timestamp * start,const pj_timestamp * stop)185 PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
186                                       const pj_timestamp *stop )
187 {
188     return stop->u32.lo - start->u32.lo;
189 }
190 
pj_gettickcount(pj_time_val * tv)191 PJ_DEF(pj_status_t) pj_gettickcount(pj_time_val *tv)
192 {
193     pj_timestamp ts, start;
194     pj_status_t status;
195 
196     if ((status = pj_get_timestamp(&ts)) != PJ_SUCCESS)
197         return status;
198 
199     pj_set_timestamp32(&start, 0, 0);
200     *tv = pj_elapsed_time(&start, &ts);
201 
202     return PJ_SUCCESS;
203 }
204 
205 #endif  /* PJ_HAS_HIGH_RES_TIMER */
206 
207