QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
vasilvv | 89713d0 | 2020-02-11 14:33:26 -0800 | [diff] [blame] | 5 | #include "net/third_party/quiche/src/quic/core/quic_clock.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 6 | |
| 7 | #include <limits> |
| 8 | |
dmcardle | c97eba6 | 2020-01-06 10:39:01 -0800 | [diff] [blame] | 9 | #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 10 | |
| 11 | namespace quic { |
| 12 | |
| 13 | QuicClock::QuicClock() |
| 14 | : is_calibrated_(false), calibration_offset_(QuicTime::Delta::Zero()) {} |
| 15 | |
| 16 | QuicClock::~QuicClock() {} |
| 17 | |
| 18 | QuicTime::Delta QuicClock::ComputeCalibrationOffset() const { |
| 19 | // In the ideal world, all we need to do is to return the difference of |
| 20 | // WallNow() and Now(). In the real world, things like context switch may |
| 21 | // happen between the calls to WallNow() and Now(), causing their difference |
| 22 | // to be arbitrarily large, so we repeat the calculation many times and use |
| 23 | // the one with the minimum difference as the true offset. |
| 24 | int64_t min_offset_us = std::numeric_limits<int64_t>::max(); |
| 25 | |
| 26 | for (int i = 0; i < 128; ++i) { |
| 27 | int64_t now_in_us = (Now() - QuicTime::Zero()).ToMicroseconds(); |
| 28 | int64_t wallnow_in_us = |
| 29 | static_cast<int64_t>(WallNow().ToUNIXMicroseconds()); |
| 30 | |
| 31 | int64_t offset_us = wallnow_in_us - now_in_us; |
| 32 | if (offset_us < min_offset_us) { |
| 33 | min_offset_us = offset_us; |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | return QuicTime::Delta::FromMicroseconds(min_offset_us); |
| 38 | } |
| 39 | |
| 40 | void QuicClock::SetCalibrationOffset(QuicTime::Delta offset) { |
| 41 | DCHECK(!is_calibrated_) << "A clock should only be calibrated once"; |
| 42 | calibration_offset_ = offset; |
| 43 | is_calibrated_ = true; |
| 44 | } |
| 45 | |
| 46 | QuicTime QuicClock::ConvertWallTimeToQuicTime( |
| 47 | const QuicWallTime& walltime) const { |
| 48 | if (is_calibrated_) { |
| 49 | int64_t time_in_us = static_cast<int64_t>(walltime.ToUNIXMicroseconds()) - |
| 50 | calibration_offset_.ToMicroseconds(); |
| 51 | return QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(time_in_us); |
| 52 | } |
| 53 | |
| 54 | // .......................... |
| 55 | // | | | |
| 56 | // unix epoch |walltime| WallNow() |
| 57 | // .......................... |
| 58 | // | | | |
| 59 | // clock epoch | Now() |
| 60 | // result |
| 61 | // |
| 62 | // result = Now() - (WallNow() - walltime) |
| 63 | return Now() - QuicTime::Delta::FromMicroseconds( |
| 64 | WallNow() |
| 65 | .Subtract(QuicTime::Delta::FromMicroseconds( |
| 66 | walltime.ToUNIXMicroseconds())) |
| 67 | .ToUNIXMicroseconds()); |
| 68 | } |
| 69 | |
| 70 | } // namespace quic |