Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /*
16 : Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17 :
18 : Permission is hereby granted, free of charge, to any person obtaining
19 : a copy of this software and associated documentation files (the
20 : "Software"), to deal in the Software without restriction, including
21 : without limitation the rights to use, copy, modify, merge, publish,
22 : distribute, sublicense, and/or sell copies of the Software, and to
23 : permit persons to whom the Software is furnished to do so, subject to
24 : the following conditions:
25 :
26 : The above copyright notice and this permission notice shall be
27 : included in all copies or substantial portions of the Software.
28 :
29 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 : EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 : MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 : NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 : OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 : WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 : */
37 :
38 : #ifndef included_time_h
39 : #define included_time_h
40 :
41 : #include <vppinfra/clib.h>
42 : #include <vppinfra/format.h>
43 :
44 : typedef struct
45 : {
46 : /* Total run time in clock cycles
47 : since clib_time_init call. */
48 : u64 total_cpu_time;
49 :
50 : /* Last recorded time stamp. */
51 : u64 last_cpu_time;
52 :
53 : /* CPU clock frequency. */
54 : f64 clocks_per_second;
55 :
56 : /* 1 / cpu clock frequency: conversion factor
57 : from clock cycles into seconds. */
58 : f64 seconds_per_clock;
59 :
60 : /* Time stamp of call to clib_time_init call. */
61 : u64 init_cpu_time;
62 : f64 init_reference_time;
63 :
64 : u64 last_verify_cpu_time;
65 :
66 : /* Same but for reference time (if present). */
67 : f64 last_verify_reference_time;
68 :
69 : u32 log2_clocks_per_second, log2_clocks_per_frequency_verify;
70 :
71 : /* Damping constant */
72 : f64 damping_constant;
73 :
74 : } clib_time_t;
75 :
76 : format_function_t format_clib_time;
77 :
78 : /* Return CPU time stamp as 64bit number. */
79 : #if defined(__x86_64__) || defined(i386)
80 : always_inline u64
81 2920977571 : clib_cpu_time_now (void)
82 : {
83 : u32 a, d;
84 2920977571 : asm volatile ("rdtsc":"=a" (a), "=d" (d));
85 2921022732 : return (u64) a + ((u64) d << (u64) 32);
86 : }
87 :
88 : #elif defined (__powerpc64__)
89 :
90 : always_inline u64
91 : clib_cpu_time_now (void)
92 : {
93 : u64 t;
94 : asm volatile ("mftb %0":"=r" (t));
95 : return t;
96 : }
97 :
98 : #elif defined (__SPU__)
99 :
100 : always_inline u64
101 : clib_cpu_time_now (void)
102 : {
103 : #ifdef _XLC
104 : return spu_rdch (0x8);
105 : #else
106 : return 0 /* __builtin_si_rdch (0x8) FIXME */ ;
107 : #endif
108 : }
109 :
110 : #elif defined (__powerpc__)
111 :
112 : always_inline u64
113 : clib_cpu_time_now (void)
114 : {
115 : u32 hi1, hi2, lo;
116 : asm volatile ("1:\n"
117 : "mftbu %[hi1]\n"
118 : "mftb %[lo]\n"
119 : "mftbu %[hi2]\n"
120 : "cmpw %[hi1],%[hi2]\n"
121 : "bne 1b\n":[hi1] "=r" (hi1),[hi2] "=r" (hi2),[lo] "=r" (lo));
122 : return (u64) lo + ((u64) hi2 << (u64) 32);
123 : }
124 :
125 : #elif defined (__aarch64__)
126 : always_inline u64
127 : clib_cpu_time_now (void)
128 : {
129 : u64 vct;
130 : /* User access to cntvct_el0 is enabled in Linux kernel since 3.12. */
131 : asm volatile ("mrs %0, cntvct_el0":"=r" (vct));
132 : return vct;
133 : }
134 :
135 : #elif defined (__arm__)
136 : #if defined(__ARM_ARCH_8A__)
137 : always_inline u64
138 : clib_cpu_time_now (void) /* We may run arm64 in aarch32 mode, to leverage 64bit counter */
139 : {
140 : u64 tsc;
141 : asm volatile ("mrrc p15, 0, %Q0, %R0, c9":"=r" (tsc));
142 : return tsc;
143 : }
144 : #elif defined(__ARM_ARCH_7A__)
145 : always_inline u64
146 : clib_cpu_time_now (void)
147 : {
148 : u32 tsc;
149 : asm volatile ("mrc p15, 0, %0, c9, c13, 0":"=r" (tsc));
150 : return (u64) tsc;
151 : }
152 : #else
153 : always_inline u64
154 : clib_cpu_time_now (void)
155 : {
156 : u32 lo;
157 : asm volatile ("mrc p15, 0, %[lo], c15, c12, 1":[lo] "=r" (lo));
158 : return (u64) lo;
159 : }
160 : #endif
161 :
162 : #elif defined (__xtensa__)
163 :
164 : /* Stub for now. */
165 : always_inline u64
166 : clib_cpu_time_now (void)
167 : {
168 : return 0;
169 : }
170 :
171 : #elif defined (__TMS320C6X__)
172 :
173 : always_inline u64
174 : clib_cpu_time_now (void)
175 : {
176 : u32 l, h;
177 :
178 : asm volatile (" dint\n"
179 : " mvc .s2 TSCL,%0\n"
180 : " mvc .s2 TSCH,%1\n" " rint\n":"=b" (l), "=b" (h));
181 :
182 : return ((u64) h << 32) | l;
183 : }
184 :
185 : #elif defined(_mips) && __mips == 64
186 :
187 : always_inline u64
188 : clib_cpu_time_now (void)
189 : {
190 : u64 result;
191 : asm volatile ("rdhwr %0,$31\n":"=r" (result));
192 : return result;
193 : }
194 :
195 : #elif defined(__riscv)
196 :
197 : always_inline u64
198 : clib_cpu_time_now (void)
199 : {
200 : u64 result;
201 : asm volatile("rdcycle %0\n" : "=r"(result));
202 : return result;
203 : }
204 : #else
205 : #error "don't know how to read CPU time stamp"
206 :
207 : #endif
208 :
209 : void clib_time_verify_frequency (clib_time_t * c);
210 :
211 : /* Define it as the type returned by clib_time_now */
212 : typedef f64 clib_time_type_t;
213 : typedef u64 clib_us_time_t;
214 :
215 : #define CLIB_US_TIME_PERIOD (1e-6)
216 : #define CLIB_US_TIME_FREQ (1.0/CLIB_US_TIME_PERIOD)
217 :
218 : always_inline f64
219 1698365737 : clib_time_now_internal (clib_time_t * c, u64 n)
220 : {
221 1698365737 : u64 l = c->last_cpu_time;
222 1698365737 : u64 t = c->total_cpu_time;
223 : f64 rv;
224 1698365737 : t += n - l;
225 1698365737 : c->total_cpu_time = t;
226 1698365737 : c->last_cpu_time = n;
227 1698365737 : rv = t * c->seconds_per_clock;
228 1698365737 : if (PREDICT_FALSE
229 : ((c->last_cpu_time -
230 : c->last_verify_cpu_time) >> c->log2_clocks_per_frequency_verify))
231 470 : clib_time_verify_frequency (c);
232 1698984748 : return rv;
233 : }
234 :
235 : /* Maximum f64 value as max clib_time */
236 : #define CLIB_TIME_MAX (1.7976931348623157e+308)
237 :
238 : always_inline f64
239 1146442170 : clib_time_now (clib_time_t * c)
240 : {
241 1146442170 : return clib_time_now_internal (c, clib_cpu_time_now ());
242 : }
243 :
244 : always_inline void
245 : clib_cpu_time_wait (u64 dt)
246 : {
247 : u64 t_end = clib_cpu_time_now () + dt;
248 : while (clib_cpu_time_now () < t_end)
249 : ;
250 : }
251 :
252 : void clib_time_init (clib_time_t * c);
253 :
254 : #ifdef CLIB_UNIX
255 :
256 : #include <time.h>
257 : #include <sys/time.h>
258 : #include <sys/resource.h>
259 : #include <unistd.h>
260 : #include <sys/syscall.h>
261 :
262 : /* Use 64bit floating point to represent time offset from epoch. */
263 : always_inline f64
264 3992 : unix_time_now (void)
265 : {
266 : struct timespec ts;
267 : #ifdef __MACH__
268 : clock_gettime (CLOCK_REALTIME, &ts);
269 : #else
270 : /* clock_gettime without indirect syscall uses GLIBC wrappers which
271 : we don't want. Just the bare metal, please. */
272 3992 : syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
273 : #endif
274 3996 : return ts.tv_sec + 1e-9 * ts.tv_nsec;
275 : }
276 :
277 : /* As above but integer number of nano-seconds. */
278 : always_inline u64
279 1677 : unix_time_now_nsec (void)
280 : {
281 : struct timespec ts;
282 : #ifdef __MACH__
283 : clock_gettime (CLOCK_REALTIME, &ts);
284 : #else
285 1677 : syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
286 : #endif
287 1677 : return 1e9 * ts.tv_sec + ts.tv_nsec;
288 : }
289 :
290 : always_inline void
291 182 : unix_time_now_nsec_fraction (u32 * sec, u32 * nsec)
292 : {
293 : struct timespec ts;
294 : #ifdef __MACH__
295 : clock_gettime (CLOCK_REALTIME, &ts);
296 : #else
297 182 : syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
298 : #endif
299 182 : *sec = ts.tv_sec;
300 182 : *nsec = ts.tv_nsec;
301 182 : }
302 :
303 : always_inline f64
304 : unix_usage_now (void)
305 : {
306 : struct rusage u;
307 : getrusage (RUSAGE_SELF, &u);
308 : return u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec
309 : + u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec;
310 : }
311 :
312 : always_inline void
313 : unix_sleep (f64 dt)
314 : {
315 : struct timespec ts, tsrem;
316 : ts.tv_sec = dt;
317 : ts.tv_nsec = 1e9 * (dt - (f64) ts.tv_sec);
318 :
319 : while (nanosleep (&ts, &tsrem) < 0)
320 : ts = tsrem;
321 : }
322 :
323 : #else /* ! CLIB_UNIX */
324 :
325 : always_inline f64
326 : unix_time_now (void)
327 : {
328 : return 0;
329 : }
330 :
331 : always_inline u64
332 : unix_time_now_nsec (void)
333 : {
334 : return 0;
335 : }
336 :
337 : always_inline void
338 : unix_time_now_nsec_fraction (u32 * sec, u32 * nsec)
339 : {
340 : }
341 :
342 : always_inline f64
343 : unix_usage_now (void)
344 : {
345 : return 0;
346 : }
347 :
348 : always_inline void
349 : unix_sleep (f64 dt)
350 : {
351 : }
352 :
353 : #endif
354 :
355 : #endif /* included_time_h */
356 :
357 : /*
358 : * fd.io coding-style-patch-verification: ON
359 : *
360 : * Local Variables:
361 : * eval: (c-set-style "gnu")
362 : * End:
363 : */
|