Skip to content

Commit d509488

Browse files
committed
opal/util: add portable wrappers for clock_gettime()/getres()
As of Dec 2021, it turns out that CLOCK_MONOTONIC can actually go backwards on macOS (!). Add two simple portable wrappers that use CLOCK_MONOTONIC_RAW on Darwin (which doesn't go backwards) and CLOCK_MONOTONIC everywhere else. Additionally, if the underlying OS does not have clock_gettime(), use gettimeofday() instead. Signed-off-by: Jeff Squyres <[email protected]>
1 parent 14fc749 commit d509488

File tree

2 files changed

+106
-1
lines changed

2 files changed

+106
-1
lines changed

opal/util/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# University of Stuttgart. All rights reserved.
1010
# Copyright (c) 2004-2005 The Regents of the University of California.
1111
# All rights reserved.
12-
# Copyright (c) 2007-2015 Cisco Systems, Inc. All rights reserved.
12+
# Copyright (c) 2007-2022 Cisco Systems, Inc. All rights reserved
1313
# Copyright (c) 2013 NVIDIA Corporation. All rights reserved.
1414
# Copyright (c) 2013 Intel, Inc. All rights reserved
1515
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
@@ -48,6 +48,7 @@ headers = \
4848
bipartite_graph.h \
4949
bipartite_graph_internal.h \
5050
bit_ops.h \
51+
clock_gettime.h \
5152
cmd_line.h \
5253
crc.h \
5354
daemon_init.h \

opal/util/clock_gettime.h

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright (c) 2022 Cisco Systems, Inc. All rights reserved.
3+
* $COPYRIGHT$
4+
*
5+
* Additional copyrights may follow
6+
*
7+
* $HEADER$
8+
*/
9+
10+
/** @file clock_gettime.h
11+
*
12+
* Simple, portable wrappers around clock_gettime(3) and
13+
* clock_getres(3) to always get monotonically-increasing time.
14+
*
15+
* If the underlying OS does not have clock_gettime(3), use
16+
* gettimeofday(3) instead.
17+
*
18+
* We intentionally do not use the OPAL timer framework for
19+
* high-prevision time here; see
20+
* https://github.com/open-mpi/ompi/issues/3003 for more details.
21+
*
22+
* As of Dec 2021, it turns out that CLOCK_MONOTONIC can actually go
23+
* backwards on macOS (!). CLOCK_MONOTONIC does *not* go backwards on
24+
* Linux (or anywhere else we can find), though, even in the presence
25+
* of small NTP time adjustments -- e.g., adjtime(3) simply slightly
26+
* speeds up or slows down the system clock to make it eventually get
27+
* to the desired time. On macOS, we can use CLOCK_MONOTONIC_RAW,
28+
* which never goes backwards.
29+
*
30+
* Hence, for these wrappers, use CLOCK_MONOTONIC_RAW on Darwin, and
31+
* use CLOCK_MONOTONIC everywhere else.
32+
*
33+
* See
34+
* https://github.com/open-mpi/ompi/pull/8057#discussion_r762612710
35+
* and
36+
* https://github.com/open-mpi/ompi/pull/8057#discussion_r762618783
37+
* for more details.
38+
*/
39+
40+
#ifndef OPAL_UTIL_CLOCK_GETTIME_H_
41+
#define OPAL_UTIL_CLOCK_GETTIME_H_
42+
43+
#include "opal_config.h"
44+
45+
#include <time.h>
46+
47+
#if OPAL_HAVE_CLOCK_GETTIME
48+
#if defined(__darwin__)
49+
#define OPAL_CLOCK_TYPE CLOCK_MONOTONIC_RAW
50+
#else
51+
#define OPAL_CLOCK_TYPE CLOCK_MONOTONIC
52+
#endif
53+
#endif // OPAL_HAVE_CLOCK_GETTIME
54+
55+
56+
/**
57+
* Simple, portable wrapper around clock_gettime(3) for high-precision time.
58+
*
59+
* If the underlying system does not have clock_gettime(3), use
60+
* gettimeofday(3) instead.
61+
*
62+
* @param spec (OUT) Struct to return the time
63+
* @return Return value from underlying clock_gettime()
64+
*/
65+
static inline int opal_clock_gettime(struct timespec *spec)
66+
{
67+
#if OPAL_HAVE_CLOCK_GETTIME
68+
return clock_gettime(OPAL_CLOCK_TYPE, spec);
69+
#else
70+
// If we do not have clock_gettime(), fall back to gettimeofday()
71+
struct timeval tv;
72+
int ret = gettimeofday(&tv, NULL);
73+
74+
spec->tv_sec = tv.tv_sec;
75+
// Elevate the micrseconds to nanoseconds
76+
spec->tv_nsec = tv.tv_usec * 1000;
77+
78+
return ret;
79+
#endif
80+
}
81+
82+
/**
83+
* Simple, portable wrapper around clock_getres(3) for high-precision time.
84+
*
85+
* If the underlying system does not have clock_gettime(3), return usec
86+
* precison (because opal_clock_gettime() will be using gettimeofday(3)).
87+
*
88+
* @param spec (OUT) Struct to return the resolution
89+
* @return Return value from underlying clock_getres()
90+
*/
91+
static inline int opal_clock_getres(struct timespec *spec)
92+
{
93+
#if OPAL_HAVE_CLOCK_GETTIME
94+
return clock_getres(OPAL_CLOCK_TYPE, spec);
95+
#else
96+
// If we don't have clock_gettime(), just return usec precision.
97+
spec->tv_sec = 0;
98+
spec->tv_sec = 1.0e-6;
99+
100+
return 0;
101+
#endif
102+
}
103+
104+
#endif // OPAL_UTIL_CLOCK_GETTIME_H_

0 commit comments

Comments
 (0)