1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2005-2020. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 /* These need to be undef:ed to not break activation of
26 * micro level process accounting on /proc/self
27 */
28 #ifdef _LARGEFILE_SOURCE
29 # undef _LARGEFILE_SOURCE
30 #endif
31 #ifdef _FILE_OFFSET_BITS
32 # undef _FILE_OFFSET_BITS
33 #endif
34
35 #include <stdlib.h>
36 #include "sys.h"
37 #include "global.h"
38 #include "erl_os_monotonic_time_extender.h"
39
40 #undef ERTS_HAVE_ERTS_OS_TIMES_IMPL__
41 #undef ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
42
43 #if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \
44 || defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) \
45 || defined(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME)
46 # include <mach/clock.h>
47 # include <mach/mach.h>
48 # define ERTS_MACH_CLOCKS
49 #endif
50
51 #ifdef NO_SYSCONF
52 # define TICKS_PER_SEC() HZ
53 #else
54 #define TICKS_PER_SEC() sysconf(_SC_CLK_TCK)
55 #endif
56
57 #ifdef HAVE_GETHRVTIME_PROCFS_IOCTL
58 # include <unistd.h>
59 # include <sys/types.h>
60 # include <sys/stat.h>
61 # include <sys/signal.h>
62 # include <sys/fault.h>
63 # include <sys/syscall.h>
64 # include <sys/procfs.h>
65 # include <fcntl.h>
66 #endif
67
68 static void init_perf_counter(void);
69
70 /******************* Routines for time measurement *********************/
71
72 #undef ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__
73 #undef ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__
74 #undef ERTS_SYS_TIME_INTERNAL_STATE_READ_MOSTLY__
75
76 #if defined(OS_MONOTONIC_TIME_USING_TIMES)
77
78 static Uint32
get_tick_count(void)79 get_tick_count(void)
80 {
81 struct tms unused;
82 return (Uint32) times(&unused);
83 }
84
85 #define ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__
86 #define ERTS_SYS_TIME_INTERNAL_STATE_READ_MOSTLY__
87
88 #endif
89
90 /*
91 * init timers, chose a tick length, and return it.
92 * Unix is priviliged when it comes to time, as erl_time_sup.c
93 * does almost everything. Other platforms have to
94 * emulate Unix in this sense.
95 */
96
97 ErtsSysTimeData__ erts_sys_time_data__ erts_align_attribute(ERTS_CACHE_LINE_SIZE);
98
99 #if defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
100
101 #define ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__
102
103 static ErtsMonotonicTime clock_gettime_monotonic(void);
104 static ErtsMonotonicTime clock_gettime_monotonic_verified(void);
105 #if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
106 static ErtsMonotonicTime clock_gettime_monotonic_raw(void);
107 #endif
108 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
109 static void clock_gettime_times(ErtsMonotonicTime *, ErtsSystemTime *);
110 static void clock_gettime_times_verified(ErtsMonotonicTime *, ErtsSystemTime *);
111 #if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
112 static void clock_gettime_times_raw(ErtsMonotonicTime *, ErtsSystemTime *);
113 #endif
114 #endif
115
116 #endif /* defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) */
117
118 #ifdef ERTS_MACH_CLOCKS
119 # define ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__
120 typedef struct {
121 clock_id_t id;
122 clock_serv_t srv;
123 char *name;
124 } ErtsMachClock;
125
126 typedef struct {
127 host_name_port_t host;
128 struct {
129 ErtsMachClock monotonic;
130 ErtsMachClock wall;
131 } clock;
132 } ErtsMachClocks;
133 static void mach_clocks_init(void);
134 static void mach_clocks_fini(void);
135 # ifdef HAVE_CLOCK_GET_ATTRIBUTES
136 # define ERTS_HAVE_MACH_CLOCK_GETRES
137 static Sint64
138 mach_clock_getres(ErtsMachClock *clk);
139 # endif
140 #endif /* ERTS_MACH_CLOCKS */
141
142 #ifdef ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__
143 struct sys_time_internal_state_read_only__ {
144 #if defined(OS_MONOTONIC_TIME_USING_TIMES)
145 int times_shift;
146 #endif
147 #ifdef ERTS_MACH_CLOCKS
148 ErtsMachClocks mach;
149 #endif
150 };
151 #endif
152
153 #ifdef ERTS_SYS_TIME_INTERNAL_STATE_READ_MOSTLY__
154 struct sys_time_internal_state_read_mostly__ {
155 #if defined(OS_MONOTONIC_TIME_USING_TIMES)
156 ErtsOsMonotonicTimeExtendState os_mtime_xtnd;
157 #endif
158 };
159 #endif
160
161 #ifdef ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__
162 struct sys_time_internal_state_write_freq__ {
163 erts_mtx_t mtx;
164 #if defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
165 ErtsMonotonicTime last_delivered;
166 #endif
167 };
168 #endif
169
170 #if defined(ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__) \
171 || defined(ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__)
172 static struct {
173 #ifdef ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__
174 union {
175 struct sys_time_internal_state_read_only__ o;
176 char align__[(((sizeof(struct sys_time_internal_state_read_only__) - 1)
177 / ASSUMED_CACHE_LINE_SIZE) + 1)
178 * ASSUMED_CACHE_LINE_SIZE];
179 } r;
180 #endif
181 #ifdef ERTS_SYS_TIME_INTERNAL_STATE_READ_MOSTLY__
182 union {
183 struct sys_time_internal_state_read_mostly__ m;
184 char align__[(((sizeof(struct sys_time_internal_state_read_mostly__) - 1)
185 / ASSUMED_CACHE_LINE_SIZE) + 1)
186 * ASSUMED_CACHE_LINE_SIZE];
187 } wr;
188 #endif
189 #ifdef ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__
190 union {
191 struct sys_time_internal_state_write_freq__ f;
192 char align__[(((sizeof(struct sys_time_internal_state_write_freq__) - 1)
193 / ASSUMED_CACHE_LINE_SIZE) + 1)
194 * ASSUMED_CACHE_LINE_SIZE];
195 } w;
196 #endif
197 } internal_state erts_align_attribute(ERTS_CACHE_LINE_SIZE);
198 #endif
199
200 void
sys_init_time(ErtsSysInitTimeResult * init_resp)201 sys_init_time(ErtsSysInitTimeResult *init_resp)
202 {
203 #if defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT)
204 int major, minor, build, vsn;
205 #endif
206 #if defined(ERTS_MACH_CLOCKS)
207 mach_clocks_init();
208 #endif
209 #if !defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT)
210
211 init_resp->have_os_monotonic_time = 0;
212
213 #else /* defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) */
214
215 #ifdef ERTS_HAVE_CORRECTED_OS_MONOTONIC_TIME
216 init_resp->have_corrected_os_monotonic_time = 1;
217 #else
218 init_resp->have_corrected_os_monotonic_time = 0;
219 #endif
220
221 init_resp->os_monotonic_time_info.resolution = (Uint64) 1000*1000*1000;
222 #if defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID)
223 init_resp->os_monotonic_time_info.resolution
224 = mach_clock_getres(&internal_state.r.o.mach.clock.monotonic);
225 #elif defined(HAVE_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID)
226 {
227 struct timespec ts;
228 if (clock_getres(MONOTONIC_CLOCK_ID, &ts) == 0) {
229 if (ts.tv_sec == 0 && ts.tv_nsec != 0)
230 init_resp->os_monotonic_time_info.resolution /= ts.tv_nsec;
231 else if (ts.tv_sec >= 1)
232 init_resp->os_monotonic_time_info.resolution = 1;
233 }
234 }
235 #endif
236
237 #ifdef MONOTONIC_CLOCK_ID_STR
238 init_resp->os_monotonic_time_info.clock_id = MONOTONIC_CLOCK_ID_STR;
239 #else
240 init_resp->os_monotonic_time_info.clock_id = NULL;
241 #endif
242
243 init_resp->os_monotonic_time_info.locked_use = 0;
244
245 #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
246 init_resp->os_monotonic_time_info.func = "clock_gettime";
247 #elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME)
248 init_resp->os_monotonic_time_info.func = "clock_get_time";
249 #elif defined(OS_MONOTONIC_TIME_USING_GETHRTIME)
250 init_resp->os_monotonic_time_info.func = "gethrtime";
251 #elif defined(OS_MONOTONIC_TIME_USING_TIMES)
252 init_resp->os_monotonic_time_info.func = "times";
253 #else
254 # error Unknown erts_os_monotonic_time() implementation
255 #endif
256
257 init_resp->have_os_monotonic_time = 1;
258
259 os_version(&major, &minor, &build);
260
261 vsn = ERTS_MK_VSN_INT(major, minor, build);
262
263
264 #if defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
265 if (vsn >= ERTS_MK_VSN_INT(2, 6, 33)) {
266 erts_sys_time_data__.r.o.os_monotonic_time =
267 clock_gettime_monotonic;
268 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
269 erts_sys_time_data__.r.o.os_times =
270 clock_gettime_times;
271 #endif
272 }
273 else {
274 /*
275 * Linux versions prior to 2.6.33 have a
276 * known bug that sometimes cause the NTP
277 * adjusted monotonic clock to take small
278 * steps backwards. Use raw monotonic clock
279 * if it is present; otherwise, fall back
280 * on locked verification of values.
281 */
282 init_resp->have_corrected_os_monotonic_time = 0;
283 #if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
284 /* We know that CLOCK_MONOTONIC_RAW is defined,
285 but we don't know if we got a kernel that
286 supports it. Support for CLOCK_MONOTONIC_RAW
287 appeared in kernel 2.6.28... */
288 if (vsn >= ERTS_MK_VSN_INT(2, 6, 28)) {
289 erts_sys_time_data__.r.o.os_monotonic_time =
290 clock_gettime_monotonic_raw;
291 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
292 erts_sys_time_data__.r.o.os_times =
293 clock_gettime_times_raw;
294 #endif
295 init_resp->os_monotonic_time_info.clock_id =
296 "CLOCK_MONOTONIC_RAW";
297 }
298 else
299 #endif /* defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) */
300 {
301 erts_sys_time_data__.r.o.os_monotonic_time =
302 clock_gettime_monotonic_verified;
303 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
304 erts_sys_time_data__.r.o.os_times =
305 clock_gettime_times_verified;
306 #endif
307 erts_mtx_init(&internal_state.w.f.mtx, "os_monotonic_time", NIL,
308 ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_IO);
309 internal_state.w.f.last_delivered
310 = clock_gettime_monotonic();
311 init_resp->os_monotonic_time_info.locked_use = 1;
312 }
313 }
314 #else /* !(defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)) */
315 {
316 char flavor[1024];
317
318 os_flavor(flavor, sizeof(flavor));
319
320 if (sys_strcmp(flavor, "sunos") == 0) {
321 /*
322 * Don't trust hrtime on multi processors
323 * on SunOS prior to SunOS 5.8
324 */
325 if (vsn < ERTS_MK_VSN_INT(5, 8, 0)) {
326 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
327 if (sysconf(_SC_NPROCESSORS_CONF) > 1)
328 #endif
329 init_resp->have_os_monotonic_time = 0;
330 }
331 }
332 }
333 #endif /* !(defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)) */
334
335 #endif /* defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) */
336
337 #ifdef ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT
338 init_resp->os_monotonic_time_unit = ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT;
339 #endif
340 init_resp->sys_clock_resolution = SYS_CLOCK_RESOLUTION;
341
342 /*
343 * This (erts_sys_time_data__.r.o.ticks_per_sec) is only for
344 * times() (CLK_TCK), the resolution is always one millisecond..
345 */
346 if ((erts_sys_time_data__.r.o.ticks_per_sec = TICKS_PER_SEC()) < 0)
347 erts_exit(ERTS_ABORT_EXIT, "Can't get clock ticks/sec\n");
348
349 #if defined(OS_MONOTONIC_TIME_USING_TIMES)
350 #if ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT
351 # error Time unit is supposed to be determined at runtime...
352 #endif
353 {
354 ErtsMonotonicTime resolution = erts_sys_time_data__.r.o.ticks_per_sec;
355 ErtsMonotonicTime time_unit = resolution;
356 int shift = 0;
357
358 while (time_unit < 1000*1000) {
359 time_unit <<= 1;
360 shift++;
361 }
362
363 init_resp->os_monotonic_time_info.resolution = resolution;
364 init_resp->os_monotonic_time_unit = time_unit;
365 init_resp->os_monotonic_time_info.extended = 1;
366 internal_state.r.o.times_shift = shift;
367
368 erts_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd,
369 get_tick_count,
370 (1 << 29) / resolution);
371 }
372 #endif /* defined(OS_MONOTONIC_TIME_USING_TIMES) */
373
374 #ifdef WALL_CLOCK_ID_STR
375 init_resp->os_system_time_info.clock_id = WALL_CLOCK_ID_STR;
376 #else
377 init_resp->os_system_time_info.clock_id = NULL;
378 #endif
379
380 init_resp->os_system_time_info.locked_use = 0;
381 init_resp->os_system_time_info.resolution = (Uint64) 1000*1000*1000;
382 #if defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(WALL_CLOCK_ID)
383 init_resp->os_system_time_info.resolution
384 = mach_clock_getres(&internal_state.r.o.mach.clock.wall);
385 #elif defined(HAVE_CLOCK_GETRES) && defined(WALL_CLOCK_ID)
386 {
387 struct timespec ts;
388 if (clock_getres(WALL_CLOCK_ID, &ts) == 0) {
389 if (ts.tv_sec == 0 && ts.tv_nsec != 0)
390 init_resp->os_system_time_info.resolution /= ts.tv_nsec;
391 else if (ts.tv_sec >= 1)
392 init_resp->os_system_time_info.resolution = 1;
393 }
394 }
395 #endif
396
397 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
398 init_resp->os_system_time_info.func = "clock_gettime";
399 #elif defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
400 init_resp->os_system_time_info.func = "clock_get_time";
401 #elif defined(OS_SYSTEM_TIME_GETTIMEOFDAY)
402 init_resp->os_system_time_info.func = "gettimeofday";
403 init_resp->os_system_time_info.resolution = 1000*1000;
404 init_resp->os_system_time_info.clock_id = NULL;
405 #else
406 # error Missing erts_os_system_time() implementation
407 #endif
408
409 init_perf_counter();
410
411 }
412
413 void
erts_late_sys_init_time(void)414 erts_late_sys_init_time(void)
415 {
416 #if defined(OS_MONOTONIC_TIME_USING_TIMES)
417 erts_late_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd);
418 #endif
419 }
420
421 static ERTS_INLINE ErtsSystemTime
adj_stime_time_unit(ErtsSystemTime stime,Uint32 res)422 adj_stime_time_unit(ErtsSystemTime stime, Uint32 res)
423 {
424 if (res == ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT)
425 return stime;
426 if (res == (Uint32) 1000*1000*1000
427 && ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT == 1000*1000)
428 return stime/1000;
429 if (res == (Uint32) 1000*1000
430 && ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT == 1000*1000*1000)
431 return stime*1000;
432 return ((ErtsSystemTime)
433 erts_time_unit_conversion(stime,
434 (Uint32) res,
435 (Uint32) ERTS_MONOTONIC_TIME_UNIT));
436 }
437
438 #define ERTS_TimeSpec2Sint64(TS) \
439 ((((Sint64) (TS)->tv_sec) * ((Sint64) 1000*1000*1000)) \
440 + ((Sint64) (TS)->tv_nsec))
441
442 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
443 * POSIX clock_gettime() *
444 \* */
445
446 #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) \
447 || defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
448
449 static ERTS_INLINE Sint64
posix_clock_gettime(clockid_t id,char * name)450 posix_clock_gettime(clockid_t id, char *name)
451 {
452 struct timespec ts;
453
454 if (clock_gettime(id, &ts) != 0) {
455 int err = errno;
456 char *errstr = err ? strerror(err) : "unknown";
457 erts_exit(ERTS_ABORT_EXIT,
458 "clock_gettime(%s, _) failed: %s (%d)\n",
459 name, errstr, err);
460 }
461 return ERTS_TimeSpec2Sint64(&ts);
462 }
463
464 #endif /* defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) \
465 || defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
466
467 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
468
469 ErtsSystemTime
erts_os_system_time(void)470 erts_os_system_time(void)
471 {
472 Sint64 stime = posix_clock_gettime(WALL_CLOCK_ID,
473 WALL_CLOCK_ID_STR);
474 return adj_stime_time_unit((ErtsSystemTime) stime,
475 (Uint32) 1000*1000*1000);
476 }
477
478 #endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
479
480 #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
481
482 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
483
484 #define ERTS_HAVE_ERTS_OS_TIMES_IMPL__
485
486 static ERTS_INLINE void
posix_clock_gettime_times(clockid_t mid,char * mname,ErtsMonotonicTime * mtimep,clockid_t sid,char * sname,ErtsSystemTime * stimep)487 posix_clock_gettime_times(clockid_t mid, char *mname,
488 ErtsMonotonicTime *mtimep,
489 clockid_t sid, char *sname,
490 ErtsSystemTime *stimep)
491 {
492 struct timespec mts, sts;
493 int mres, sres, merr, serr;
494
495 mres = clock_gettime(mid, &mts);
496 merr = errno;
497 sres = clock_gettime(sid, &sts);
498 serr = errno;
499
500 if (mres != 0) {
501 char *errstr = merr ? strerror(merr) : "unknown";
502 erts_exit(ERTS_ABORT_EXIT,
503 "clock_gettime(%s, _) failed: %s (%d)\n",
504 mname, errstr, merr);
505 }
506 if (sres != 0) {
507 char *errstr = serr ? strerror(serr) : "unknown";
508 erts_exit(ERTS_ABORT_EXIT,
509 "clock_gettime(%s, _) failed: %s (%d)\n",
510 sname, errstr, serr);
511 }
512
513 *mtimep = (ErtsMonotonicTime) ERTS_TimeSpec2Sint64(&mts);
514 *stimep = (ErtsSystemTime) ERTS_TimeSpec2Sint64(&sts);
515 }
516
517 #endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
518
519 #if defined(__linux__)
520
clock_gettime_monotonic_verified(void)521 static ErtsMonotonicTime clock_gettime_monotonic_verified(void)
522 {
523 ErtsMonotonicTime mtime;
524
525 mtime = (ErtsMonotonicTime) posix_clock_gettime(MONOTONIC_CLOCK_ID,
526 MONOTONIC_CLOCK_ID_STR);
527
528 erts_mtx_lock(&internal_state.w.f.mtx);
529 if (mtime < internal_state.w.f.last_delivered)
530 mtime = internal_state.w.f.last_delivered;
531 else
532 internal_state.w.f.last_delivered = mtime;
533 erts_mtx_unlock(&internal_state.w.f.mtx);
534
535 return mtime;
536 }
537
538 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
539
clock_gettime_times_verified(ErtsMonotonicTime * mtimep,ErtsSystemTime * stimep)540 static void clock_gettime_times_verified(ErtsMonotonicTime *mtimep,
541 ErtsSystemTime *stimep)
542 {
543 posix_clock_gettime_times(MONOTONIC_CLOCK_ID,
544 MONOTONIC_CLOCK_ID_STR,
545 mtimep,
546 WALL_CLOCK_ID,
547 WALL_CLOCK_ID_STR,
548 stimep);
549
550 erts_mtx_lock(&internal_state.w.f.mtx);
551 if (*mtimep < internal_state.w.f.last_delivered)
552 *mtimep = internal_state.w.f.last_delivered;
553 else
554 internal_state.w.f.last_delivered = *mtimep;
555 erts_mtx_unlock(&internal_state.w.f.mtx);
556 }
557
558 #endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
559
clock_gettime_monotonic(void)560 static ErtsMonotonicTime clock_gettime_monotonic(void)
561 {
562 return (ErtsMonotonicTime) posix_clock_gettime(MONOTONIC_CLOCK_ID,
563 MONOTONIC_CLOCK_ID_STR);
564 }
565
566 #if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
567
clock_gettime_monotonic_raw(void)568 static ErtsMonotonicTime clock_gettime_monotonic_raw(void)
569 {
570 return (ErtsMonotonicTime) posix_clock_gettime(CLOCK_MONOTONIC_RAW,
571 "CLOCK_MONOTONIC_RAW");
572 }
573
574 #endif /* defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) */
575
576 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
577
clock_gettime_times(ErtsMonotonicTime * mtimep,ErtsSystemTime * stimep)578 static void clock_gettime_times(ErtsMonotonicTime *mtimep,
579 ErtsSystemTime *stimep)
580 {
581 posix_clock_gettime_times(MONOTONIC_CLOCK_ID,
582 MONOTONIC_CLOCK_ID_STR,
583 mtimep,
584 WALL_CLOCK_ID,
585 WALL_CLOCK_ID_STR,
586 stimep);
587 }
588
589 #if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
590
clock_gettime_times_raw(ErtsMonotonicTime * mtimep,ErtsSystemTime * stimep)591 static void clock_gettime_times_raw(ErtsMonotonicTime *mtimep,
592 ErtsSystemTime *stimep)
593 {
594 posix_clock_gettime_times(CLOCK_MONOTONIC_RAW,
595 "CLOCK_MONOTONIC_RAW",
596 mtimep,
597 WALL_CLOCK_ID,
598 WALL_CLOCK_ID_STR,
599 stimep);
600 }
601
602 #endif /* defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) */
603
604 #endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
605
606 #else /* !defined(__linux__) */
607
erts_os_monotonic_time(void)608 ErtsMonotonicTime erts_os_monotonic_time(void)
609 {
610 return posix_clock_gettime(MONOTONIC_CLOCK_ID,
611 MONOTONIC_CLOCK_ID_STR);
612 }
613
614 #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
615
erts_os_times(ErtsMonotonicTime * mtimep,ErtsSystemTime * stimep)616 void erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep)
617 {
618 posix_clock_gettime_times(MONOTONIC_CLOCK_ID,
619 MONOTONIC_CLOCK_ID_STR,
620 mtimep,
621 WALL_CLOCK_ID,
622 WALL_CLOCK_ID_STR,
623 stimep);
624 }
625
626 #endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
627
628 #endif /* !defined(__linux__) */
629
630 #endif /* defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) */
631
632 #if defined(SYS_HRTIME_USING_CLOCK_GETTIME)
633 # define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
634
635 ErtsSysHrTime
erts_sys_hrtime(void)636 erts_sys_hrtime(void)
637 {
638 return (ErtsSysHrTime) posix_clock_gettime(HRTIME_CLOCK_ID,
639 HRTIME_CLOCK_ID_STR);
640 }
641
642 #endif /* defined(SYS_HRTIME_USING_CLOCK_GETTIME) */
643
644 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
645 * MACH clock_get_time() *
646 \* */
647
648 #if defined(ERTS_MACH_CLOCKS)
649
650 static void
mach_clocks_fini(void)651 mach_clocks_fini(void)
652 {
653 mach_port_t task = mach_task_self();
654 mach_port_deallocate(task, internal_state.r.o.mach.host);
655 #if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME)
656 mach_port_deallocate(task, internal_state.r.o.mach.clock.monotonic.srv);
657 #endif
658 #if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
659 mach_port_deallocate(task, internal_state.r.o.mach.clock.wall.srv);
660 #endif
661 }
662
663 static void
mach_clocks_init(void)664 mach_clocks_init(void)
665 {
666 kern_return_t kret;
667 host_name_port_t host;
668 clock_id_t id;
669 clock_serv_t *clck_srv_p;
670 char *name;
671
672 host = internal_state.r.o.mach.host = mach_host_self();
673
674 #if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \
675 || defined(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME)
676 id = internal_state.r.o.mach.clock.monotonic.id = MONOTONIC_CLOCK_ID;
677 name = internal_state.r.o.mach.clock.monotonic.name = MONOTONIC_CLOCK_ID_STR;
678 clck_srv_p = &internal_state.r.o.mach.clock.monotonic.srv;
679 kret = host_get_clock_service(host, id, clck_srv_p);
680 if (kret != KERN_SUCCESS) {
681 erts_exit(ERTS_ABORT_EXIT,
682 "host_get_clock_service(_, %s, _) failed\n",
683 name);
684 }
685 #endif
686
687 #if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
688 id = internal_state.r.o.mach.clock.wall.id = WALL_CLOCK_ID;
689 name = internal_state.r.o.mach.clock.wall.name = WALL_CLOCK_ID_STR;
690 clck_srv_p = &internal_state.r.o.mach.clock.wall.srv;
691 kret = host_get_clock_service(host, id, clck_srv_p);
692 if (kret != KERN_SUCCESS) {
693 erts_exit(ERTS_ABORT_EXIT,
694 "host_get_clock_service(_, %s, _) failed\n",
695 name);
696 }
697 #endif
698
699 if (atexit(mach_clocks_fini) != 0) {
700 int err = errno;
701 char *errstr = err ? strerror(err) : "unknown";
702 erts_exit(ERTS_ABORT_EXIT,
703 "Failed to register mach_clocks_fini() "
704 "for call at exit: %s (%d)\n",
705 errstr, err);
706 }
707 }
708
709 #ifdef ERTS_HAVE_MACH_CLOCK_GETRES
710
711 static Sint64
mach_clock_getres(ErtsMachClock * clk)712 mach_clock_getres(ErtsMachClock *clk)
713 {
714 kern_return_t kret;
715 natural_t attr[1];
716 mach_msg_type_number_t cnt;
717
718 cnt = sizeof(attr);
719 kret = clock_get_attributes(clk->srv,
720 CLOCK_GET_TIME_RES,
721 (clock_attr_t) attr,
722 &cnt);
723 if (kret != KERN_SUCCESS || cnt != 1) {
724 erts_exit(ERTS_ABORT_EXIT,
725 "clock_get_attributes(%s, _) failed\n",
726 clk->name);
727 }
728
729 return (Sint64) attr[0];
730 }
731
732 #endif /* ERTS_HAVE_MACH_CLOCK_GETRES */
733
734 static ERTS_INLINE Sint64
mach_clock_get_time(ErtsMachClock * clk)735 mach_clock_get_time(ErtsMachClock *clk)
736 {
737 kern_return_t kret;
738 mach_timespec_t time_spec;
739
740 kret = clock_get_time(clk->srv, &time_spec);
741 if (kret != KERN_SUCCESS)
742 erts_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", clk->name);
743
744 return ERTS_TimeSpec2Sint64(&time_spec);
745 }
746
747 #endif /* defined(ERTS_MACH_CLOCKS) */
748
749 #if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
750
751 #define ERTS_HAVE_ERTS_OS_TIMES_IMPL__
752
753 ErtsSystemTime
erts_os_system_time(void)754 erts_os_system_time(void)
755 {
756 Sint64 stime = mach_clock_get_time(&internal_state.r.o.mach.clock.wall);
757 return adj_stime_time_unit((ErtsSystemTime) stime,
758 (Uint32) 1000*1000*1000);
759 }
760
761 #endif /* defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) */
762
763 #if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME)
764
765 ErtsMonotonicTime
erts_os_monotonic_time(void)766 erts_os_monotonic_time(void)
767 {
768 return (ErtsMonotonicTime)
769 mach_clock_get_time(&internal_state.r.o.mach.clock.monotonic);
770 }
771
772 #if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
773
774 #define ERTS_HAVE_ERTS_OS_TIMES_IMPL__
775
776 void
erts_os_times(ErtsMonotonicTime * mtimep,ErtsSystemTime * stimep)777 erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep)
778 {
779 kern_return_t mkret, skret;
780 mach_timespec_t mon_time_spec, sys_time_spec;
781
782 mkret = clock_get_time(internal_state.r.o.mach.clock.monotonic.srv,
783 &mon_time_spec);
784 skret = clock_get_time(internal_state.r.o.mach.clock.wall.srv,
785 &sys_time_spec);
786
787 if (mkret != KERN_SUCCESS)
788 erts_exit(ERTS_ABORT_EXIT,
789 "clock_get_time(%s, _) failed\n",
790 internal_state.r.o.mach.clock.monotonic.name);
791 if (skret != KERN_SUCCESS)
792 erts_exit(ERTS_ABORT_EXIT,
793 "clock_get_time(%s, _) failed\n",
794 internal_state.r.o.mach.clock.wall.name);
795
796 *mtimep = (ErtsMonotonicTime) ERTS_TimeSpec2Sint64(&mon_time_spec);
797 *stimep = (ErtsSystemTime) ERTS_TimeSpec2Sint64(&sys_time_spec);
798 }
799
800 #endif /* defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) */
801
802 #endif /* defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) */
803
804 #if defined(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME)
805
806 #define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
807
808 ErtsSysHrTime
erts_sys_hrtime(void)809 erts_sys_hrtime(void)
810 {
811 return (ErtsSysHrTime)
812 mach_clock_get_time(&internal_state.r.o.mach.clock.monotonic);
813 }
814
815 #endif /* defined(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME) */
816
817 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
818 * Solaris gethrtime() - OS monotonic time *
819 \* */
820
821 #if defined(OS_MONOTONIC_TIME_USING_GETHRTIME)
822
erts_os_monotonic_time(void)823 ErtsMonotonicTime erts_os_monotonic_time(void)
824 {
825 return (ErtsMonotonicTime) gethrtime();
826 }
827
828 #endif /* defined(OS_MONOTONIC_TIME_USING_GETHRTIME) */
829
830 #if defined(SYS_HRTIME_USING_GETHRTIME)
831
832 #define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
833
834 ErtsSysHrTime
erts_sys_hrtime(void)835 erts_sys_hrtime(void)
836 {
837 return (ErtsSysHrTime) gethrtime();
838 }
839
840 #endif /* defined(SYS_HRTIME_USING_GETHRTIME) */
841
842 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
843 * gettimeofday() - OS system time *
844 \* */
845
846 #if defined(OS_SYSTEM_TIME_GETTIMEOFDAY)
847
848 ErtsSystemTime
erts_os_system_time(void)849 erts_os_system_time(void)
850 {
851 ErtsSystemTime stime;
852 struct timeval tv;
853
854 if (gettimeofday(&tv, NULL) != 0) {
855 int err = errno;
856 char *errstr = err ? strerror(err) : "unknown";
857 erts_exit(ERTS_ABORT_EXIT,
858 "gettimeofday(_, NULL) failed: %s (%d)\n",
859 errstr, err);
860 }
861
862 stime = (ErtsSystemTime) tv.tv_sec;
863 stime *= (ErtsSystemTime) 1000*1000;
864 stime += (ErtsSystemTime) tv.tv_usec;
865
866 return adj_stime_time_unit(stime, (Uint32) 1000*1000);
867 }
868
869 #endif /* defined(OS_SYSTEM_TIME_GETTIMEOFDAY) */
870
871 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
872 * times() - OS monotonic time *
873 \* */
874
875 #if defined(OS_MONOTONIC_TIME_USING_TIMES)
876
877 ErtsMonotonicTime
erts_os_monotonic_time(void)878 erts_os_monotonic_time(void)
879 {
880 Uint32 ticks = get_tick_count();
881 return ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd,
882 ticks) << internal_state.r.o.times_shift;
883 }
884
885 #endif
886
887 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
888 * Fallbacks *
889 \* */
890
891 #ifndef ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
892
893 ErtsSysHrTime
erts_sys_hrtime(void)894 erts_sys_hrtime(void)
895 {
896 return (ErtsSysHrTime) ERTS_MONOTONIC_TO_NSEC(erts_os_system_time());
897 }
898
899 #endif
900
901 #if !defined(ERTS_HAVE_ERTS_OS_TIMES_IMPL__) \
902 && defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT)
903
904 void
erts_os_times(ErtsMonotonicTime * mtimep,ErtsSystemTime * stimep)905 erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep)
906 {
907 *mtimep = erts_os_monotonic_time();
908 *stimep = erts_os_system_time();
909 }
910
911 #endif
912
913 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
914 * Performance counter functions *
915 \* */
916
917
918 /* What resolution to spin to in micro seconds */
919 #define RESOLUTION 100
920 /* How many iterations to spin */
921 #define ITERATIONS 1
922 /* How many significant figures to round to */
923 #define SIGFIGS 3
924
calculate_perf_counter_unit(void)925 static ErtsSysPerfCounter calculate_perf_counter_unit(void) {
926 int i;
927 ErtsSysPerfCounter pre, post;
928 double value = 0;
929 double round_factor;
930 #if defined(HAVE_GETHRTIME) && defined(GETHRTIME_WITH_CLOCK_GETTIME)
931 struct timespec basetime,comparetime;
932 #define __GETTIME(arg) clock_gettime(CLOCK_MONOTONIC,arg)
933 #define __GETUSEC(arg) (arg.tv_nsec / 1000)
934 #else
935 SysTimeval basetime,comparetime;
936 #define __GETTIME(arg) sys_gettimeofday(arg)
937 #define __GETUSEC(arg) arg.tv_usec
938 #endif
939
940 for (i = 0; i < ITERATIONS; i++) {
941 /* Make sure usec just flipped over at current resolution */
942 __GETTIME(&basetime);
943 do {
944 __GETTIME(&comparetime);
945 } while ((__GETUSEC(basetime) / RESOLUTION) == (__GETUSEC(comparetime) / RESOLUTION));
946
947 pre = erts_sys_perf_counter();
948
949 __GETTIME(&basetime);
950 do {
951 __GETTIME(&comparetime);
952 } while ((__GETUSEC(basetime) / RESOLUTION) == (__GETUSEC(comparetime) / RESOLUTION));
953
954 post = erts_sys_perf_counter();
955
956 value += post - pre;
957 }
958 /* After this value is ticks per us */
959 value /= (RESOLUTION*ITERATIONS);
960
961 /* We round to 3 significant figures */
962 round_factor = pow(10.0, SIGFIGS - ceil(log10(value)));
963 value = ((ErtsSysPerfCounter)(value * round_factor + 0.5)) / round_factor;
964
965 /* convert to ticks per second */
966 return 1000000 * value;
967 }
968
have_rdtscp(void)969 static int have_rdtscp(void)
970 {
971 #if defined(ETHR_X86_RUNTIME_CONF__)
972 /* On early x86 cpu's the tsc varies with the current speed of the cpu,
973 which means that the time per tick vary depending on the current
974 load of the cpu. We do not want this as it would give very scewed
975 numbers when the cpu is mostly idle.
976 The linux kernel seems to think that checking for constant and
977 reliable is enough to trust the counter so we do the same.
978
979 If this test is not good enough, I don't know what we'll do.
980 Maybe fallback on erts_sys_hrtime always, but that would be a shame as
981 rdtsc is about 3 times faster than hrtime... */
982 return ETHR_X86_RUNTIME_CONF_HAVE_CONSTANT_TSC__ &&
983 ETHR_X86_RUNTIME_CONF_HAVE_TSC_RELIABLE__;
984 #else
985 return 0;
986 #endif
987 }
988
rdtsc(void)989 static ErtsSysPerfCounter rdtsc(void)
990 {
991 /* It may have been a good idea to put the cpuid instruction before
992 the rdtsc, but I decided against it because it is not really
993 needed for msacc, and it slows it down by quite a bit (5-7 times slower).
994 As a result though, this timestamp becomes much less
995 accurate as it might be re-ordered to be executed way before or after this
996 function is called.
997 */
998 ErtsSysPerfCounter ts;
999 #if defined(__x86_64__)
1000 __asm__ __volatile__ ("rdtsc\n\t"
1001 "shl $32, %%rdx\n\t"
1002 "or %%rdx, %0" : "=a" (ts) : : "rdx");
1003 #elif defined(__i386__)
1004 __asm__ __volatile__ ("rdtsc\n\t"
1005 : "=A" (ts) );
1006 #else
1007 ts = 0;
1008 #endif
1009 return ts;
1010 }
1011
init_perf_counter(void)1012 static void init_perf_counter(void)
1013 {
1014 if (have_rdtscp()) {
1015 erts_sys_time_data__.r.o.perf_counter = rdtsc;
1016 erts_sys_time_data__.r.o.perf_counter_unit = calculate_perf_counter_unit();
1017 } else {
1018 erts_sys_time_data__.r.o.perf_counter = erts_sys_hrtime;
1019 erts_sys_time_data__.r.o.perf_counter_unit = ERTS_HRTIME_UNIT;
1020 }
1021 }
1022
1023 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1024
1025 #ifdef HAVE_GETHRVTIME_PROCFS_IOCTL
1026
1027 /* The code below only has effect on solaris < 10,
1028 needed in order for gehhrvtime to work properly */
sys_start_hrvtime(void)1029 int sys_start_hrvtime(void)
1030 {
1031 long msacct = PR_MSACCT;
1032 int fd;
1033
1034 if ( (fd = open("/proc/self", O_WRONLY)) == -1) {
1035 return -1;
1036 }
1037 if (ioctl(fd, PIOCSET, &msacct) < 0) {
1038 close(fd);
1039 return -2;
1040 }
1041 close(fd);
1042 return 0;
1043 }
1044
sys_stop_hrvtime(void)1045 int sys_stop_hrvtime(void)
1046 {
1047 long msacct = PR_MSACCT;
1048 int fd;
1049
1050 if ( (fd = open("/proc/self", O_WRONLY)) == -1) {
1051 return -1;
1052 }
1053 if (ioctl(fd, PIOCRESET, &msacct) < 0) {
1054 close(fd);
1055 return -2;
1056 }
1057 close(fd);
1058 return 0;
1059 }
1060
1061 #endif /* HAVE_GETHRVTIME_PROCFS_IOCTL */
1062
1063
1064