diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 9dc1880df6..2240f2c193 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -34,7 +34,7 @@ void CongestionControl::setPacketSendPeriod(double newSendPeriod) { } DefaultCC::DefaultCC() : - _lastRCTime(high_resolution_clock::now()), + _lastRCTime(p_high_resolution_clock::now()), _slowStartLastAck(_sendCurrSeqNum), _lastDecreaseMaxSeq(SequenceNumber {SequenceNumber::MAX }) { @@ -54,7 +54,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) { const double minimumIncrease = 0.01; // we will only adjust once per sync interval so check that it has been at least that long now - auto now = high_resolution_clock::now(); + auto now = p_high_resolution_clock::now(); if (duration_cast(now - _lastRCTime).count() < synInterval()) { return; } diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 8fd1f22bc8..adbf1f0e85 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -12,11 +12,12 @@ #ifndef hifi_CongestionControl_h #define hifi_CongestionControl_h -#include #include #include #include +#include + #include "LossList.h" #include "SequenceNumber.h" @@ -107,7 +108,7 @@ public: private: void stopSlowStart(); // stops the slow start on loss or timeout - std::chrono::high_resolution_clock::time_point _lastRCTime; // last rate increase time + p_high_resolution_clock::time_point _lastRCTime; // last rate increase time bool _slowStart { true }; // if in slow start phase SequenceNumber _slowStartLastAck; // last ACKed seq num bool _loss { false }; // if loss happened since last rate increase diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index f159ff517c..21dce2831c 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -28,7 +28,7 @@ using namespace udt; using namespace std::chrono; Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr congestionControl) : - _connectionStart(high_resolution_clock::now()), + _connectionStart(p_high_resolution_clock::now()), _parentSocket(parentSocket), _destination(destination), _congestionControl(move(congestionControl)) @@ -154,7 +154,7 @@ void Connection::sync() { static const int NUM_TIMEOUTS_BEFORE_EXPIRY = 16; static const int MIN_SECONDS_BEFORE_EXPIRY = 5; - auto now = high_resolution_clock::now(); + auto now = p_high_resolution_clock::now(); auto sincePacketReceive = now - _lastReceiveTime; @@ -185,7 +185,7 @@ void Connection::sync() { if (_lossList.getLength() > 0) { // check if we need to re-transmit a loss list // we do this if it has been longer than the current nakInterval since we last sent - auto now = high_resolution_clock::now(); + auto now = p_high_resolution_clock::now(); if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { // Send a timeout NAK packet @@ -197,7 +197,7 @@ void Connection::sync() { // this most likely means we were started erroneously // check the start time for this connection and auto expire it after 5 seconds of not receiving or sending any data static const int CONNECTION_NOT_USED_EXPIRY_SECONDS = 5; - auto secondsSinceStart = duration_cast(high_resolution_clock::now() - _connectionStart).count(); + auto secondsSinceStart = duration_cast(p_high_resolution_clock::now() - _connectionStart).count(); if (secondsSinceStart >= CONNECTION_NOT_USED_EXPIRY_SECONDS) { // it's been CONNECTION_NOT_USED_EXPIRY_SECONDS and nothing has actually happened with this connection @@ -222,8 +222,8 @@ void Connection::recordRetransmission() { } void Connection::sendACK(bool wasCausedBySyncTimeout) { - static high_resolution_clock::time_point lastACKSendTime; - auto currentTime = high_resolution_clock::now(); + static p_high_resolution_clock::time_point lastACKSendTime; + auto currentTime = p_high_resolution_clock::now(); SequenceNumber nextACKNumber = nextACK(); Q_ASSERT_X(nextACKNumber >= _lastSentACK, "Connection::sendACK", "Sending lower ACK, something is wrong"); @@ -280,7 +280,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { ackPacket->writePrimitive(estimatedBandwidth); // record this as the last ACK send time - lastACKSendTime = high_resolution_clock::now(); + lastACKSendTime = p_high_resolution_clock::now(); } // have the socket send off our packet @@ -290,7 +290,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { "Connection::sendACK", "Adding an invalid ACK to _sentACKs"); // write this ACK to the map of sent ACKs - _sentACKs.push_back({ _currentACKSubSequenceNumber, { nextACKNumber, high_resolution_clock::now() }}); + _sentACKs.push_back({ _currentACKSubSequenceNumber, { nextACKNumber, p_high_resolution_clock::now() }}); // reset the number of data packets received since last ACK _packetsSinceACK = 0; @@ -358,7 +358,7 @@ void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { _parentSocket->writeBasePacket(*lossReport, _destination); // record our last NAK time - _lastNAKTime = high_resolution_clock::now(); + _lastNAKTime = p_high_resolution_clock::now(); _stats.record(ConnectionStats::Stats::SentNAK); } @@ -379,7 +379,7 @@ void Connection::sendTimeoutNAK() { _parentSocket->writeBasePacket(*lossListPacket, _destination); // record this as the last NAK time - _lastNAKTime = high_resolution_clock::now(); + _lastNAKTime = p_high_resolution_clock::now(); _stats.record(ConnectionStats::Stats::SentTimeoutNAK); } @@ -403,7 +403,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in _isReceivingData = true; // mark our last receive time as now (to push the potential expiry farther) - _lastReceiveTime = high_resolution_clock::now(); + _lastReceiveTime = p_high_resolution_clock::now(); // check if this is a packet pair we should estimate bandwidth from, or just a regular packet if (((uint32_t) sequenceNumber & 0xF) == 0) { @@ -533,8 +533,8 @@ void Connection::processACK(std::unique_ptr controlPacket) { // Check if we need send an ACK2 for this ACK // This will be the case if it has been longer than the sync interval OR // it looks like they haven't received our ACK2 for this ACK - auto currentTime = high_resolution_clock::now(); - static high_resolution_clock::time_point lastACK2SendTime; + auto currentTime = p_high_resolution_clock::now(); + static p_high_resolution_clock::time_point lastACK2SendTime; microseconds sinceLastACK2 = duration_cast(currentTime - lastACK2SendTime); @@ -542,7 +542,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // Send ACK2 packet sendACK2(currentACKSubSequenceNumber); - lastACK2SendTime = high_resolution_clock::now(); + lastACK2SendTime = p_high_resolution_clock::now(); } // read the ACKed sequence number @@ -664,7 +664,7 @@ void Connection::processACK2(std::unique_ptr controlPacket) { // update the RTT using the ACK window // calculate the RTT (time now - time ACK sent) - auto now = high_resolution_clock::now(); + auto now = p_high_resolution_clock::now(); int rtt = duration_cast(now - it->second.second).count(); updateRTT(rtt); @@ -779,13 +779,13 @@ void Connection::resetReceiveState() { // clear the loss list and _lastNAKTime _lossList.clear(); - _lastNAKTime = high_resolution_clock::time_point(); + _lastNAKTime = p_high_resolution_clock::time_point(); // the _nakInterval need not be reset, that will happen on loss // clear sync variables _isReceivingData = false; - _connectionStart = high_resolution_clock::now(); + _connectionStart = p_high_resolution_clock::now(); _acksDuringSYN = 1; _lightACKsDuringSYN = 1; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index f10c9dd720..31ef664ce5 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -12,12 +12,13 @@ #ifndef hifi_Connection_h #define hifi_Connection_h -#include #include #include #include +#include + #include "ConnectionStats.h" #include "Constants.h" #include "LossList.h" @@ -51,7 +52,7 @@ private: class Connection : public QObject { Q_OBJECT public: - using SequenceNumberTimePair = std::pair; + using SequenceNumberTimePair = std::pair; using ACKListPair = std::pair; using SentACKList = std::list; @@ -113,13 +114,13 @@ private: int _nakInterval { -1 }; // NAK timeout interval, in microseconds, set on loss int _minNAKInterval { 100000 }; // NAK timeout interval lower bound, default of 100ms - std::chrono::high_resolution_clock::time_point _lastNAKTime; + p_high_resolution_clock::time_point _lastNAKTime; bool _hasReceivedHandshake { false }; // flag for receipt of handshake from server bool _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client - std::chrono::high_resolution_clock::time_point _connectionStart; // holds the time_point for creation of this connection - std::chrono::high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender + p_high_resolution_clock::time_point _connectionStart; // holds the time_point for creation of this connection + p_high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection LossList _lossList; // List of all missing packets diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 00eb43c7e6..51bba2c52c 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -94,7 +94,7 @@ int32_t PacketTimeWindow::getEstimatedBandwidth() const { void PacketTimeWindow::onPacketArrival() { // take the current time - auto now = high_resolution_clock::now(); + auto now = p_high_resolution_clock::now(); // record the interval between this packet and the last one _packetIntervals[_currentPacketInterval++] = duration_cast(now - _lastPacketTime).count(); @@ -110,12 +110,12 @@ void PacketTimeWindow::onPacketArrival() { void PacketTimeWindow::onProbePair1Arrival() { // take the current time as the first probe time - _firstProbeTime = high_resolution_clock::now(); + _firstProbeTime = p_high_resolution_clock::now(); } void PacketTimeWindow::onProbePair2Arrival() { // store the interval between the two probes - auto now = high_resolution_clock::now(); + auto now = p_high_resolution_clock::now(); _probeIntervals[_currentProbeInterval++] = duration_cast(now - _firstProbeTime).count(); diff --git a/libraries/networking/src/udt/PacketTimeWindow.h b/libraries/networking/src/udt/PacketTimeWindow.h index a8a4e0c8b5..c2a90d0f6c 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.h +++ b/libraries/networking/src/udt/PacketTimeWindow.h @@ -14,9 +14,10 @@ #ifndef hifi_PacketTimeWindow_h #define hifi_PacketTimeWindow_h -#include #include +#include + namespace udt { class PacketTimeWindow { @@ -41,8 +42,8 @@ private: std::vector _packetIntervals; // vector of microsecond intervals between packet arrivals std::vector _probeIntervals; // vector of microsecond intervals between probe pair arrivals - std::chrono::high_resolution_clock::time_point _lastPacketTime; // the time_point when last packet arrived - std::chrono::high_resolution_clock::time_point _firstProbeTime; // the time_point when first probe in pair arrived + p_high_resolution_clock::time_point _lastPacketTime; // the time_point when last packet arrived + p_high_resolution_clock::time_point _firstProbeTime; // the time_point when first probe in pair arrived }; } diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 04b3921aac..2890d52c2b 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -272,7 +272,7 @@ void SendQueue::run() { while (_isRunning) { // Record how long the loop takes to execute - auto loopStartTimestamp = high_resolution_clock::now(); + auto loopStartTimestamp = p_high_resolution_clock::now(); std::unique_lock handshakeLock { _handshakeMutex }; @@ -281,12 +281,12 @@ void SendQueue::run() { // if it has been at least 100ms since we last sent a handshake, send another now // hold the time of last send in a static - static auto lastSendHandshake = high_resolution_clock::time_point(); + static auto lastSendHandshake = p_high_resolution_clock::time_point(); static const auto HANDSHAKE_RESEND_INTERVAL_MS = std::chrono::milliseconds(100); // calculation the duration since the last handshake send - auto sinceLastHandshake = std::chrono::duration_cast(high_resolution_clock::now() + auto sinceLastHandshake = std::chrono::duration_cast(p_high_resolution_clock::now() - lastSendHandshake); if (sinceLastHandshake >= HANDSHAKE_RESEND_INTERVAL_MS) { @@ -295,12 +295,12 @@ void SendQueue::run() { static auto handshakePacket = ControlPacket::create(ControlPacket::Handshake, 0); _socket->writeBasePacket(*handshakePacket, _destination); - lastSendHandshake = high_resolution_clock::now(); + lastSendHandshake = p_high_resolution_clock::now(); } // we wait for the ACK or the re-send interval to expire _handshakeACKCondition.wait_until(handshakeLock, - high_resolution_clock::now() + p_high_resolution_clock::now() + HANDSHAKE_RESEND_INTERVAL_MS); // Once we're here we've either received the handshake ACK or it's going to be time to re-send a handshake. @@ -420,7 +420,7 @@ void SendQueue::run() { } } - auto loopEndTimestamp = high_resolution_clock::now(); + auto loopEndTimestamp = p_high_resolution_clock::now(); // sleep as long as we need until next packet send, if we can auto timeToSleep = (loopStartTimestamp + std::chrono::microseconds(_packetSendPeriod)) - loopEndTimestamp; diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 564e74a3fb..401ebd384d 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -13,7 +13,6 @@ #define hifi_SendQueue_h #include -#include #include #include #include @@ -24,6 +23,8 @@ #include #include +#include + #include "../HifiSockAddr.h" #include "Constants.h" @@ -44,8 +45,7 @@ class SendQueue : public QObject { Q_OBJECT public: - using high_resolution_clock = std::chrono::high_resolution_clock; - using time_point = high_resolution_clock::time_point; + using time_point = p_high_resolution_clock::time_point; static std::unique_ptr create(Socket* socket, HifiSockAddr destination); diff --git a/libraries/shared/src/PortableHighResolutionClock.cpp b/libraries/shared/src/PortableHighResolutionClock.cpp new file mode 100644 index 0000000000..7cfb4c61b2 --- /dev/null +++ b/libraries/shared/src/PortableHighResolutionClock.cpp @@ -0,0 +1,30 @@ +// +// PortableHighResolutionClock.cpp +// libraries/shared/src +// +// Created by Stephen Birarda on 2015-09-14. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#include "PortableHighResolutionClock.h" + +namespace { + const long long g_Frequency = []() -> long long { + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + return frequency.QuadPart; + } +} + +win_high_resolution_clock::time_point win_high_resolution_clock::now() { + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + return time_point(duration(count.QuadPart * static_cast(period::den) / g_Frequency)); +} + +#endif diff --git a/libraries/shared/src/PortableHighResolutionClock.h b/libraries/shared/src/PortableHighResolutionClock.h new file mode 100644 index 0000000000..4631adefdb --- /dev/null +++ b/libraries/shared/src/PortableHighResolutionClock.h @@ -0,0 +1,48 @@ +// +// PortableHighResolutionClock.h +// libraries/shared/src +// +// Created by Stephen Birarda on 2015-09-14. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// I discovered the low-resolution nature of the VC2012 implementation of std::chrono::high_resolution_clock +// while debugging a UDT issue with packet receive speeds. That lead to +// http://stackoverflow.com/questions/16299029/resolution-of-stdchronohigh-resolution-clock-doesnt-correspond-to-measureme +// which is where the implementation of this class is from. + +#include + +#pragma once + +#ifndef hifi_PortableHighResolutionClock_h +#define hifi_PortableHighResolutionClock_h + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +// The following struct is not compliant with the HF coding standard, but uses underscores to match the classes +// in std::chrono + +struct win_high_resolution_clock { + typedef long long rep; + typedef std::nano period; + typedef std::chrono::duration duration; + typedef std::chrono::time_point time_point; + static const bool is_steady = true; + + static time_point now(); +}; + +using p_high_resolution_clock = win_high_resolution_clock; + +#else + +using p_high_resolution_clock = std::chrono::high_resolution_clock; + +#endif + + +#endif // hifi_PortableHighResolutionClock_h