Skip to content

Commit

Permalink
Import FXL timing utilities into FML. (flutter#5311)
Browse files Browse the repository at this point in the history
  • Loading branch information
chinmaygarde authored May 18, 2018
1 parent fbf07dc commit 99a1dde
Show file tree
Hide file tree
Showing 8 changed files with 364 additions and 0 deletions.
6 changes: 6 additions & 0 deletions fml/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ source_set("fml") {
"thread.cc",
"thread.h",
"thread_local.h",
"time/time_delta.h",
"time/time_point.cc",
"time/time_point.h",
"trace_event.cc",
"trace_event.h",
"unique_fd.cc",
Expand Down Expand Up @@ -148,6 +151,9 @@ executable("fml_unittests") {
"message_loop_unittests.cc",
"thread_local_unittests.cc",
"thread_unittests.cc",
"time/time_delta_unittest.cc",
"time/time_point_unittest.cc",
"time/time_unittest.cc",
]

deps = [
Expand Down
111 changes: 111 additions & 0 deletions fml/time/time_delta.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_FML_TIME_TIME_DELTA_H_
#define FLUTTER_FML_TIME_TIME_DELTA_H_

#include <stdint.h>
#include <time.h>

#include <iosfwd>
#include <limits>

namespace fml {

// A TimeDelta represents the difference between two time points.
class TimeDelta {
public:
constexpr TimeDelta() = default;

static constexpr TimeDelta Zero() { return TimeDelta(); }
static constexpr TimeDelta Min() {
return TimeDelta(std::numeric_limits<int64_t>::min());
}
static constexpr TimeDelta Max() {
return TimeDelta(std::numeric_limits<int64_t>::max());
}
static constexpr TimeDelta FromNanoseconds(int64_t nanos) {
return TimeDelta(nanos);
}
static constexpr TimeDelta FromMicroseconds(int64_t micros) {
return FromNanoseconds(micros * 1000);
}
static constexpr TimeDelta FromMilliseconds(int64_t millis) {
return FromMicroseconds(millis * 1000);
}
static constexpr TimeDelta FromSeconds(int64_t seconds) {
return FromMilliseconds(seconds * 1000);
}

static constexpr TimeDelta FromSecondsF(double seconds) {
return FromNanoseconds(seconds * (1000.0 * 1000.0 * 1000.0));
}

constexpr int64_t ToNanoseconds() const { return delta_; }
constexpr int64_t ToMicroseconds() const { return ToNanoseconds() / 1000; }
constexpr int64_t ToMilliseconds() const { return ToMicroseconds() / 1000; }
constexpr int64_t ToSeconds() const { return ToMilliseconds() / 1000; }

constexpr double ToNanosecondsF() const { return delta_; }
constexpr double ToMicrosecondsF() const { return delta_ / 1000.0; }
constexpr double ToMillisecondsF() const {
return delta_ / (1000.0 * 1000.0);
}
constexpr double ToSecondsF() const {
return delta_ / (1000.0 * 1000.0 * 1000.0);
}

constexpr TimeDelta operator-(TimeDelta other) const {
return TimeDelta::FromNanoseconds(delta_ - other.delta_);
}

constexpr TimeDelta operator+(TimeDelta other) const {
return TimeDelta::FromNanoseconds(delta_ + other.delta_);
}

constexpr TimeDelta operator/(int64_t divisor) const {
return TimeDelta::FromNanoseconds(delta_ / divisor);
}

constexpr int64_t operator/(TimeDelta other) const {
return delta_ / other.delta_;
}

constexpr TimeDelta operator*(int64_t multiplier) const {
return TimeDelta::FromNanoseconds(delta_ * multiplier);
}

constexpr TimeDelta operator%(TimeDelta other) const {
return TimeDelta::FromNanoseconds(delta_ % other.delta_);
}

bool operator==(TimeDelta other) const { return delta_ == other.delta_; }
bool operator!=(TimeDelta other) const { return delta_ != other.delta_; }
bool operator<(TimeDelta other) const { return delta_ < other.delta_; }
bool operator<=(TimeDelta other) const { return delta_ <= other.delta_; }
bool operator>(TimeDelta other) const { return delta_ > other.delta_; }
bool operator>=(TimeDelta other) const { return delta_ >= other.delta_; }

static constexpr TimeDelta FromTimespec(struct timespec ts) {
return TimeDelta::FromSeconds(ts.tv_sec) +
TimeDelta::FromNanoseconds(ts.tv_nsec);
}
struct timespec ToTimespec() {
struct timespec ts;
constexpr int64_t kNanosecondsPerSecond = 1000000000ll;
ts.tv_sec = static_cast<time_t>(ToSeconds());
ts.tv_nsec = delta_ % kNanosecondsPerSecond;
return ts;
}

private:
// Private, use one of the FromFoo() types
explicit constexpr TimeDelta(int64_t delta) : delta_(delta) {}

int64_t delta_ = 0;
};

} // namespace fml

#endif // FLUTTER_FML_TIME_TIME_DELTA_H_
23 changes: 23 additions & 0 deletions fml/time/time_delta_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/fml/time/time_delta.h"

#include "gtest/gtest.h"

namespace fml {
namespace {

TEST(TimeDelta, Control) {
EXPECT_LT(TimeDelta::Min(), TimeDelta::Zero());
EXPECT_GT(TimeDelta::Max(), TimeDelta::Zero());

EXPECT_GT(TimeDelta::Zero(), TimeDelta::FromMilliseconds(-100));
EXPECT_LT(TimeDelta::Zero(), TimeDelta::FromMilliseconds(100));

EXPECT_EQ(TimeDelta::FromMilliseconds(1000), TimeDelta::FromSeconds(1));
}

} // namespace
} // namespace fml
76 changes: 76 additions & 0 deletions fml/time/time_point.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/fml/time/time_point.h"

#include "flutter/fml/build_config.h"

#if defined(OS_MACOSX) || defined(OS_IOS)
#include <mach/kern_return.h>
#include <mach/mach_time.h>
#elif defined(OS_FUCHSIA)
#include <zircon/syscalls.h>
#elif defined(OS_WIN)
#include <windows.h>
#else
#include <time.h>
#endif // defined(OS_MACOSX) || defined(OS_IOS)

#include "flutter/fml/logging.h"

namespace fml {

// Mac OS X/iOS don't have a (useful) |clock_gettime()|.
// Note: Chromium's |base::TimeTicks::Now()| uses boot time (obtained via
// |sysctl()| with |CTL_KERN|/|KERN_BOOTTIME|). For our current purposes,
// monotonic time (which pauses during sleeps) is sufficient. TODO(vtl): If/when
// we use this for other purposes, maybe we should use boot time (maybe also on
// POSIX).
#if defined(OS_MACOSX) || defined(OS_IOS)

mach_timebase_info_data_t GetMachTimebaseInfo() {
mach_timebase_info_data_t timebase_info = {};
kern_return_t error = mach_timebase_info(&timebase_info);
FML_DCHECK(error == KERN_SUCCESS);
return timebase_info;
}

// static
TimePoint TimePoint::Now() {
static mach_timebase_info_data_t timebase_info = GetMachTimebaseInfo();
return TimePoint(mach_absolute_time() * timebase_info.numer /
timebase_info.denom);
}

#elif defined(OS_FUCHSIA)

// static
TimePoint TimePoint::Now() {
return TimePoint(zx_clock_get(ZX_CLOCK_MONOTONIC));
}

#elif defined(OS_WIN)

TimePoint TimePoint::Now() {
uint64_t freq = 0;
uint64_t count = 0;
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
QueryPerformanceCounter((LARGE_INTEGER*)&count);
return TimePoint((count * 1000000000) / freq);
}

#else

// static
TimePoint TimePoint::Now() {
struct timespec ts;
int res = clock_gettime(CLOCK_MONOTONIC, &ts);
FML_DCHECK(res == 0);
(void)res;
return TimePoint::FromEpochDelta(TimeDelta::FromTimespec(ts));
}

#endif // defined(OS_MACOSX) || defined(OS_IOS)

} // namespace fml
70 changes: 70 additions & 0 deletions fml/time/time_point.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_FML_TIME_TIME_POINT_H_
#define FLUTTER_FML_TIME_TIME_POINT_H_

#include <stdint.h>

#include <iosfwd>

#include "flutter/fml/time/time_delta.h"

namespace fml {

// A TimePoint represents a point in time represented as an integer number of
// nanoseconds elapsed since an arbitrary point in the past.
//
// WARNING: This class should not be serialized across reboots, or across
// devices: the reference point is only stable for a given device between
// reboots.
class TimePoint {
public:
// Default TimePoint with internal value 0 (epoch).
constexpr TimePoint() = default;

static TimePoint Now();

static constexpr TimePoint Min() {
return TimePoint(std::numeric_limits<int64_t>::min());
}

static constexpr TimePoint Max() {
return TimePoint(std::numeric_limits<int64_t>::max());
}

static constexpr TimePoint FromEpochDelta(TimeDelta ticks) {
return TimePoint(ticks.ToNanoseconds());
}

TimeDelta ToEpochDelta() const { return TimeDelta::FromNanoseconds(ticks_); }

// Compute the difference between two time points.
TimeDelta operator-(TimePoint other) const {
return TimeDelta::FromNanoseconds(ticks_ - other.ticks_);
}

TimePoint operator+(TimeDelta duration) const {
return TimePoint(ticks_ + duration.ToNanoseconds());
}
TimePoint operator-(TimeDelta duration) const {
return TimePoint(ticks_ - duration.ToNanoseconds());
}

bool operator==(TimePoint other) const { return ticks_ == other.ticks_; }
bool operator!=(TimePoint other) const { return ticks_ != other.ticks_; }
bool operator<(TimePoint other) const { return ticks_ < other.ticks_; }
bool operator<=(TimePoint other) const { return ticks_ <= other.ticks_; }
bool operator>(TimePoint other) const { return ticks_ > other.ticks_; }
bool operator>=(TimePoint other) const { return ticks_ >= other.ticks_; }

private:
explicit constexpr TimePoint(int64_t ticks) : ticks_(ticks) {}

int64_t ticks_ = 0;
};

} // namespace fml

#endif // FLUTTER_FML_TIME_TIME_POINT_H_
18 changes: 18 additions & 0 deletions fml/time/time_point_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/fml/time/time_point.h"

#include "gtest/gtest.h"

namespace fml {
namespace {

TEST(TimePoint, Control) {
EXPECT_LT(TimePoint::Min(), TimePoint::Now());
EXPECT_GT(TimePoint::Max(), TimePoint::Now());
}

} // namespace
} // namespace fml
54 changes: 54 additions & 0 deletions fml/time/time_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <thread>

#include "flutter/fml/time/time_delta.h"
#include "flutter/fml/time/time_point.h"
#include "gtest/gtest.h"

namespace fml {
namespace {

TEST(Time, Now) {
auto start = TimePoint::Now();
for (int i = 0; i < 3; ++i) {
auto now = TimePoint::Now();
EXPECT_GE(now, start);
std::this_thread::yield();
}
}

TEST(Time, IntConversions) {
// Integer conversions should all truncate, not round.
TimeDelta delta = TimeDelta::FromNanoseconds(102304506708ll);
EXPECT_EQ(102304506708ll, delta.ToNanoseconds());
EXPECT_EQ(102304506ll, delta.ToMicroseconds());
EXPECT_EQ(102304ll, delta.ToMilliseconds());
EXPECT_EQ(102ll, delta.ToSeconds());
}

TEST(Time, FloatConversions) {
// Float conversions should remain close to the original value.
TimeDelta delta = TimeDelta::FromNanoseconds(102304506708ll);
EXPECT_FLOAT_EQ(102304506708.0, delta.ToNanosecondsF());
EXPECT_FLOAT_EQ(102304506.708, delta.ToMicrosecondsF());
EXPECT_FLOAT_EQ(102304.506708, delta.ToMillisecondsF());
EXPECT_FLOAT_EQ(102.304506708, delta.ToSecondsF());
}

TEST(Time, TimespecConversions) {
struct timespec ts;
ts.tv_sec = 5;
ts.tv_nsec = 7;
TimeDelta from_timespec = TimeDelta::FromTimespec(ts);
EXPECT_EQ(5, from_timespec.ToSeconds());
EXPECT_EQ(5 * 1000000000ll + 7, from_timespec.ToNanoseconds());
struct timespec to_timespec = from_timespec.ToTimespec();
EXPECT_EQ(ts.tv_sec, to_timespec.tv_sec);
EXPECT_EQ(ts.tv_nsec, to_timespec.tv_nsec);
}

} // namespace
} // namespace fml
6 changes: 6 additions & 0 deletions travis/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,8 @@ LIBRARY: engine
ORIGIN: ../../../garnet/LICENSE
TYPE: LicenseType.bsd
FILE: ../../../flutter/fml/export.h
FILE: ../../../flutter/fml/time/time_delta_unittest.cc
FILE: ../../../flutter/fml/time/time_point_unittest.cc
----------------------------------------------------------------------------------------------------
Copyright 2017 The Fuchsia Authors. All rights reserved.

Expand Down Expand Up @@ -868,6 +870,10 @@ FILE: ../../../flutter/fml/memory/weak_ptr.h
FILE: ../../../flutter/fml/memory/weak_ptr_internal.cc
FILE: ../../../flutter/fml/memory/weak_ptr_internal.h
FILE: ../../../flutter/fml/memory/weak_ptr_unittest.cc
FILE: ../../../flutter/fml/time/time_delta.h
FILE: ../../../flutter/fml/time/time_point.cc
FILE: ../../../flutter/fml/time/time_point.h
FILE: ../../../flutter/fml/time/time_unittest.cc
----------------------------------------------------------------------------------------------------
Copyright 2016 The Fuchsia Authors. All rights reserved.

Expand Down

0 comments on commit 99a1dde

Please sign in to comment.