Skip to content

Commit 3191861

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 <jsquyres@cisco.com> (cherry picked from commit c74f80a)
1 parent ddccdb8 commit 3191861

File tree

3 files changed

+129
-3
lines changed

3 files changed

+129
-3
lines changed

configure.ac

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# University of Stuttgart. All rights reserved.
1111
# Copyright (c) 2004-2005 The Regents of the University of California.
1212
# All rights reserved.
13-
# Copyright (c) 2006-2021 Cisco Systems, Inc. All rights reserved
13+
# Copyright (c) 2006-2022 Cisco Systems, Inc. All rights reserved
1414
# Copyright (c) 2006-2008 Sun Microsystems, Inc. All rights reserved.
1515
# Copyright (c) 2006-2017 Los Alamos National Security, LLC. All rights
1616
# reserved.
@@ -694,7 +694,7 @@ AC_CHECK_HEADERS([alloca.h aio.h arpa/inet.h dirent.h \
694694
sys/fcntl.h sys/ipc.h sys/shm.h \
695695
sys/ioctl.h sys/mman.h sys/param.h sys/queue.h \
696696
sys/resource.h sys/select.h sys/socket.h sys/sockio.h \
697-
sys/stat.h sys/statfs.h sys/statvfs.h sys/time.h sys/tree.h \
697+
sys/stat.h sys/statfs.h sys/statvfs.h time.h sys/time.h sys/tree.h \
698698
sys/types.h sys/uio.h sys/un.h net/uio.h sys/utsname.h sys/vfs.h sys/wait.h syslog.h \
699699
termios.h ulimit.h unistd.h util.h utmp.h malloc.h \
700700
ifaddrs.h crt_externs.h regex.h mntent.h paths.h \
@@ -883,6 +883,15 @@ AC_INCLUDES_DEFAULT
883883
#endif
884884
])
885885

886+
AC_CHECK_MEMBERS([struct timespec.tv_nsec],
887+
[], [], [AC_INCLUDES_DEFAULT
888+
#ifdef HAVE_TIME_H
889+
#include <time.h>
890+
#endif
891+
#ifdef HAVE_SYS_TIME_H
892+
#include <sys/time.h>
893+
#endif])
894+
886895
#
887896
# Find corresponding types for MPI_Aint, MPI_Count, and MPI_Offset.
888897
# And if relevant, find the corresponding MPI_ADDRESS_KIND,

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: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
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+
#if HAVE_TIME_H
46+
#include <time.h>
47+
#endif
48+
#if HAVE_SYS_TIME_H
49+
#include <sys/time.h>
50+
#endif
51+
52+
#if OPAL_HAVE_CLOCK_GETTIME
53+
#if defined(__darwin__)
54+
#define OPAL_CLOCK_TYPE CLOCK_MONOTONIC_RAW
55+
#else
56+
#define OPAL_CLOCK_TYPE CLOCK_MONOTONIC
57+
#endif
58+
#endif // OPAL_HAVE_CLOCK_GETTIME
59+
60+
#if !defined(HAVE_STRUCT_TIMESPEC_TV_NSEC)
61+
// Make sure that we have struct timespec; if not, define it.
62+
struct timespec {
63+
time_t tv_sec;
64+
long tv_nsec;
65+
};
66+
#endif
67+
68+
/**
69+
* Simple, portable wrapper around clock_gettime(3) for high-precision time.
70+
*
71+
* If the underlying system does not have clock_gettime(3), use
72+
* gettimeofday(3) instead.
73+
*
74+
* @param spec (OUT) Struct to return the time
75+
* @return Return value from underlying clock_gettime()
76+
*/
77+
static inline int opal_clock_gettime(struct timespec *spec)
78+
{
79+
#if OPAL_HAVE_CLOCK_GETTIME
80+
return clock_gettime(OPAL_CLOCK_TYPE, spec);
81+
#else
82+
// If we do not have clock_gettime(), fall back to gettimeofday()
83+
struct timeval tv;
84+
int ret = gettimeofday(&tv, NULL);
85+
86+
spec->tv_sec = tv.tv_sec;
87+
// Elevate the micrseconds to nanoseconds
88+
spec->tv_nsec = tv.tv_usec * 1000;
89+
90+
return ret;
91+
#endif
92+
}
93+
94+
/**
95+
* Simple, portable wrapper around clock_getres(3) for high-precision time.
96+
*
97+
* If the underlying system does not have clock_gettime(3), return usec
98+
* precison (because opal_clock_gettime() will be using gettimeofday(3)).
99+
*
100+
* @param spec (OUT) Struct to return the resolution
101+
* @return Return value from underlying clock_getres()
102+
*/
103+
static inline int opal_clock_getres(struct timespec *spec)
104+
{
105+
#if OPAL_HAVE_CLOCK_GETTIME
106+
return clock_getres(OPAL_CLOCK_TYPE, spec);
107+
#else
108+
// If we don't have clock_gettime(), just return usec precision.
109+
spec->tv_sec = 0;
110+
spec->tv_nsec = 1000;
111+
112+
return 0;
113+
#endif
114+
}
115+
116+
#endif // OPAL_UTIL_CLOCK_GETTIME_H_

0 commit comments

Comments
 (0)