mirror of
https://github.com/lubosz/overte.git
synced 2025-04-17 07:32:10 +02:00
Merge pull request #5795 from birarda/phrc
fix high resolution timing for VS2012 in networking
This commit is contained in:
commit
15b809bd16
10 changed files with 125 additions and 41 deletions
|
@ -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<microseconds>(now - _lastRCTime).count() < synInterval()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,11 +12,12 @@
|
|||
#ifndef hifi_CongestionControl_h
|
||||
#define hifi_CongestionControl_h
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -28,7 +28,7 @@ using namespace udt;
|
|||
using namespace std::chrono;
|
||||
|
||||
Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr<CongestionControl> 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<microseconds>(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<seconds>(high_resolution_clock::now() - _connectionStart).count();
|
||||
auto secondsSinceStart = duration_cast<seconds>(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> 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<microseconds>(currentTime - lastACK2SendTime);
|
||||
|
||||
|
@ -542,7 +542,7 @@ void Connection::processACK(std::unique_ptr<ControlPacket> 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> 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<microseconds>(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;
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
#ifndef hifi_Connection_h
|
||||
#define hifi_Connection_h
|
||||
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#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<SequenceNumber, std::chrono::high_resolution_clock::time_point>;
|
||||
using SequenceNumberTimePair = std::pair<SequenceNumber, p_high_resolution_clock::time_point>;
|
||||
using ACKListPair = std::pair<SequenceNumber, SequenceNumberTimePair>;
|
||||
using SentACKList = std::list<ACKListPair>;
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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<microseconds>(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<microseconds>(now - _firstProbeTime).count();
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
#ifndef hifi_PacketTimeWindow_h
|
||||
#define hifi_PacketTimeWindow_h
|
||||
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
namespace udt {
|
||||
|
||||
class PacketTimeWindow {
|
||||
|
@ -41,8 +42,8 @@ private:
|
|||
std::vector<int> _packetIntervals; // vector of microsecond intervals between packet arrivals
|
||||
std::vector<int> _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
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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<std::mutex> 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<std::chrono::milliseconds>(high_resolution_clock::now()
|
||||
auto sinceLastHandshake = std::chrono::duration_cast<std::chrono::milliseconds>(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;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#define hifi_SendQueue_h
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
|
@ -24,6 +23,8 @@
|
|||
#include <QtCore/QObject>
|
||||
#include <QtCore/QReadWriteLock>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#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<SendQueue> create(Socket* socket, HifiSockAddr destination);
|
||||
|
||||
|
|
30
libraries/shared/src/PortableHighResolutionClock.cpp
Normal file
30
libraries/shared/src/PortableHighResolutionClock.cpp
Normal file
|
@ -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<rep>(period::den) / g_Frequency));
|
||||
}
|
||||
|
||||
#endif
|
51
libraries/shared/src/PortableHighResolutionClock.h
Normal file
51
libraries/shared/src/PortableHighResolutionClock.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef hifi_PortableHighResolutionClock_h
|
||||
#define hifi_PortableHighResolutionClock_h
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// 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<rep, period> duration;
|
||||
typedef std::chrono::time_point<win_high_resolution_clock> 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
|
Loading…
Reference in a new issue