Skip to content

Commit 09ba185

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>
1 parent 14fc749 commit 09ba185

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-1
lines changed

opal/util/Makefile.am

Lines changed: 3 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 \
@@ -89,6 +90,7 @@ libopalutil_la_SOURCES = \
8990
argv.c \
9091
basename.c \
9192
bipartite_graph.c \
93+
clock_gettime.c \
9294
cmd_line.c \
9395
crc.c \
9496
daemon_init.c \

opal/util/clock_gettime.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
3+
* University Research and Technology
4+
* Corporation. All rights reserved.
5+
* Copyright (c) 2004-2018 The University of Tennessee and The University
6+
* of Tennessee Research Foundation. All rights
7+
* reserved.
8+
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9+
* University of Stuttgart. All rights reserved.
10+
* Copyright (c) 2004-2005 The Regents of the University of California.
11+
* All rights reserved.
12+
* Copyright (c) 2007-2022 Cisco Systems, Inc. All rights reserved.
13+
* Copyright (c) 2015-2016 Research Organization for Information Science
14+
* and Technology (RIST). All rights reserved.
15+
* Copyright (c) 2017 IBM Corporation. All rights reserved.
16+
* Copyright (c) 2017 Los Alamos National Security, LLC. All rights
17+
* reserved.
18+
* $COPYRIGHT$
19+
*
20+
* Additional copyrights may follow
21+
*
22+
* $HEADER$
23+
*/
24+
25+
#include "opal_config.h"
26+
27+
#ifdef HAVE_SYS_TIME_H
28+
#include <sys/time.h>
29+
#endif
30+
#ifdef HAVE_TIME_H
31+
#include <time.h>
32+
#endif
33+
34+
#include "opal/util/clock_gettime.h"
35+
36+
37+
#if OPAL_HAVE_CLOCK_GETTIME
38+
#if defined(__darwin__)
39+
#define OPAL_CLOCK_TYPE CLOCK_MONOTONIC_RAW
40+
#else
41+
#define OPAL_CLOCK_TYPE CLOCK_MONOTONIC
42+
#endif
43+
#endif // OPAL_HAVE_CLOCK_GETTIME
44+
45+
46+
int opal_clock_gettime(struct timespec *spec)
47+
{
48+
#if OPAL_HAVE_CLOCK_GETTIME
49+
return clock_gettime(OPAL_CLOCK_TYPE, spec);
50+
#else
51+
// If we do not have clock_gettime(), fall back to gettimeofday()
52+
struct timeval tv;
53+
int ret = gettimeofday(&tv, NULL);
54+
55+
spec->tv_sec = tv.tv_sec;
56+
// Elevate the micrseconds to nanoseconds
57+
spec->tv_nsec = tv.tv_usec * 1000;
58+
59+
return ret;
60+
#endif
61+
}
62+
63+
int opal_clock_getres(struct timespec *spec)
64+
{
65+
#if OPAL_HAVE_CLOCK_GETTIME
66+
return clock_getres(OPAL_CLOCK_TYPE, spec);
67+
#else
68+
// If we don't have clock_gettime(), just return usec precision.
69+
spec->tv_sec = 0;
70+
spec->tv_sec = 1.0e-6;
71+
72+
return 0;
73+
#endif
74+
}

opal/util/clock_gettime.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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+
/**
48+
* Simple, portable wrapper around clock_gettime(3) for high-precision time.
49+
*
50+
* If the underlying system does not have clock_gettime(3), use
51+
* gettimeofday(3) instead.
52+
*
53+
* @param spec (OUT) Struct to return the time
54+
* @return Return value from underlying clock_gettime()
55+
*/
56+
int opal_clock_gettime(struct timespec *spec);
57+
58+
/**
59+
* Simple, portable wrapper around clock_getres(3) for high-precision time.
60+
*
61+
* If the underlying system does not have clock_gettime(3), return usec
62+
* precison (because opal_clock_gettime() will be using gettimeofday(3)).
63+
*
64+
* @param spec (OUT) Struct to return the resolution
65+
* @return Return value from underlying clock_getres()
66+
*/
67+
int opal_clock_getres(struct timespec *spec);
68+
69+
#endif // OPAL_UTIL_CLOCK_GETTIME_H_

0 commit comments

Comments
 (0)