Commit 5ab482b1 authored by Christopher Dykes's avatar Christopher Dykes Committed by Facebook Github Bot 8

Wrappers folly::chrono::clock_gettime and clock_gettime_ns

Summary:
On Linux hosts, the fast path to get the current time in
nanoseconds without doing a syscall to the kernel is available via the
VDSO kernel-runtime interface.

In this diff, I:

1. Expose portability wrappers `folly::chrono::clock_gettime()` and
`folly::chrono::clock_gettime_ns()`
2. Implement a VDSO wrapper on Linux hosts to implement those without
a round-trip to the kernel

Depends On D3418054

Reviewed By: bmaurer

Differential Revision: D3418087

fbshipit-source-id: 3fb99f0dd946f19ba29d0d52a1038dad3556bafd
parent 4786b768
/*
* Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/ClockGettimeWrappers.h>
#include <folly/Likely.h>
#include <folly/portability/Time.h>
#include <chrono>
#include <time.h>
#ifndef _WIN32
#define _GNU_SOURCE 1
#include <dlfcn.h>
#endif
namespace folly {
namespace chrono {
static int64_t clock_gettime_ns_fallback(clockid_t clock) {
struct timespec ts;
int r = clock_gettime(clock, &ts);
if (UNLIKELY(r != 0)) {
// Mimic what __clock_gettime_ns does (even though this can be a legit
// value).
return -1;
}
std::chrono::nanoseconds result =
std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec);
return result.count();
}
// Initialize with default behavior, which we might override on Linux hosts
// with VDSO support.
int (*clock_gettime)(clockid_t, timespec* ts) = &::clock_gettime;
int64_t (*clock_gettime_ns)(clockid_t) = &clock_gettime_ns_fallback;
#ifdef __linux__
namespace {
struct VdsoInitializer {
VdsoInitializer() {
m_handle = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
if (!m_handle) {
return;
}
void* p = dlsym(m_handle, "__vdso_clock_gettime");
if (p) {
folly::chrono::clock_gettime = (int (*)(clockid_t, timespec*))p;
}
p = dlsym(m_handle, "__vdso_clock_gettime_ns");
if (p) {
folly::chrono::clock_gettime_ns = (int64_t(*)(clockid_t))p;
}
}
~VdsoInitializer() {
if (m_handle) {
clock_gettime = &::clock_gettime;
clock_gettime_ns = &clock_gettime_ns_fallback;
dlclose(m_handle);
}
}
private:
void* m_handle;
};
static const VdsoInitializer vdso_initializer;
}
#endif
}
}
/*
* Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <folly/portability/Time.h>
#include <time.h>
namespace folly {
namespace chrono {
extern int (*clock_gettime)(clockid_t, timespec* ts);
extern int64_t (*clock_gettime_ns)(clockid_t);
}
}
......@@ -41,6 +41,7 @@ nobase_follyinclude_HEADERS = \
Bits.h \
CallOnce.h \
Checksum.h \
ClockGettimeWrappers.h \
ConcurrentSkipList.h \
ConcurrentSkipList-inl.h \
ConditionallyExistent.h \
......@@ -368,6 +369,7 @@ libfollybase_la_SOURCES = \
libfolly_la_SOURCES = \
Bits.cpp \
Checksum.cpp \
ClockGettimeWrappers.cpp \
detail/CacheLocality.cpp \
detail/IPAddress.cpp \
dynamic.cpp \
......
/*
* Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/ClockGettimeWrappers.h>
#include <folly/test/TestUtils.h>
#include <chrono>
#include <gtest/gtest.h>
static constexpr auto kAcceptableDeltaSecs = std::chrono::seconds(120);
using folly::test::AreWithinSecs;
#ifdef CLOCK_REALTIME
TEST(ClockGettimeWrappers, clockGettimeWrapperIsWithin120SecsOfSystemClock) {
struct timespec ts;
auto ret = folly::chrono::clock_gettime(CLOCK_REALTIME, &ts);
ASSERT_EQ(0, ret);
auto gettimeResult =
std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec);
auto stdChronoSystemClockNow =
std::chrono::system_clock::now().time_since_epoch();
ASSERT_TRUE(AreWithinSecs(
gettimeResult, stdChronoSystemClockNow, kAcceptableDeltaSecs));
}
TEST(ClockGettimeWrappers, clockGettimeNsWrapperIsWithin120SecsOfSystemClock) {
auto now_ns = folly::chrono::clock_gettime_ns(CLOCK_REALTIME);
auto stdChronoSystemClockNow =
std::chrono::system_clock::now().time_since_epoch();
ASSERT_TRUE(AreWithinSecs(
std::chrono::nanoseconds(now_ns),
stdChronoSystemClockNow,
kAcceptableDeltaSecs));
}
#endif /* CLOCK_REALTIME */
......@@ -229,6 +229,10 @@ indestructible_test_SOURCES = IndestructibleTest.cpp
indestructible_test_LDADD = libfollytestmain.la
TESTS += indestructible_test
portability_clock_gettime_wrappers_test_SOURCES = ClockGettimeWrappersTest.cpp
portability_clock_gettime_wrappers_test_LDADD = libfollytestmain.la
TESTS += portability_clock_gettime_wrappers_test
portability_time_test_SOURCES = ../portability/test/TimeTest.cpp
portability_time_test_LDADD = libfollytestmain.la
TESTS += portability_time_test
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment