From 532bcc9376808196207c91da5bcd42901081ebc9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 1 May 2015 14:56:40 -0700 Subject: [PATCH] complete initial algorithm for AM throttle --- assignment-client/src/avatars/AvatarMixer.cpp | 59 ++++++++----------- .../src/avatars/AvatarMixerClientData.cpp | 2 +- .../src/avatars/AvatarMixerClientData.h | 10 ++-- 3 files changed, 32 insertions(+), 39 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 2795a73f25..b99ef128f5 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -166,7 +166,7 @@ void AvatarMixer::broadcastAvatarData() { distribution.reset(); // reset the max distance for this frame - float maxDistanceThisFrame = 0.0f; + float maxAvatarDistanceThisFrame = 0.0f; // reset the number of sent avatars nodeData->resetNumAvatarsSentLastFrame(); @@ -186,48 +186,44 @@ void AvatarMixer::broadcastAvatarData() { if (nodeData->getNumFramesSinceFRDAdjustment() > AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND) { const float FRD_ADJUSTMENT_ACCEPTABLE_RATIO = 0.8f; + const float HYSTERISIS_GAP = (1 - FRD_ADJUSTMENT_ACCEPTABLE_RATIO); + const float HYSTERISIS_MIDDLE_PERCENTAGE = (1 - (HYSTERISIS_GAP * 0.5f)); + const float FRD_RECOVERY_EPSILON = 0.0001; + + // get the current full rate distance so we can work with it + float currentFullRateDistance = nodeData->getFullRateDistance(); // qDebug() << "current node outbound bandwidth is" << avatarDataRateLastSecond; if (avatarDataRateLastSecond > _maxKbpsPerNode) { qDebug() << "Adjustment down required for avatar" << node->getUUID() << "whose current send rate is" - << avatarDataRateLastSecond; + << avatarDataRateLastSecond; - // is the FRD greater than the MAX FRD? if so, before we calculate anything, set it to the MAX FRD - float newFullRateDistance = nodeData->getFullRateDistance(); + // is the FRD greater than the farthest avatar? + // if so, before we calculate anything, set it to that distance + currentFullRateDistance = std::min(currentFullRateDistance, nodeData->getMaxAvatarDistance()); + + // we're adjusting the full rate distance to target a bandwidth in the middle + // of the hysterisis gap + + currentFullRateDistance *= (_maxKbpsPerNode * HYSTERISIS_MIDDLE_PERCENTAGE) / avatarDataRateLastSecond; - if (newFullRateDistance > nodeData->getMaxFullRateDistance()) { - newFullRateDistance = nodeData->getMaxFullRateDistance(); - } - - // we're adjusting, so we want to drop half the distance to FRD=0 - newFullRateDistance /= 2.0f; - - qDebug() << "max FRD is" << nodeData->getMaxFullRateDistance(); + qDebug() << "farthest possible FRD is" << nodeData->getMaxAvatarDistance(); qDebug() << "current FRD is" << nodeData->getFullRateDistance(); - nodeData->setFullRateDistance(newFullRateDistance); + nodeData->setFullRateDistance(currentFullRateDistance); qDebug() << "new FRD is" << nodeData->getFullRateDistance(); nodeData->resetNumFramesSinceFRDAdjustment(); - } else if (nodeData->getFullRateDistance() < nodeData->getMaxFullRateDistance() + } else if (currentFullRateDistance < nodeData->getMaxAvatarDistance() && avatarDataRateLastSecond < _maxKbpsPerNode * FRD_ADJUSTMENT_ACCEPTABLE_RATIO) { - // we are constrained AND we've recovered to below the acceptable ratio, adjust the FRD upwards - // by covering half the distance to the max FRD + // we are constrained AND we've recovered to below the acceptable ratio - qDebug() << "Adjustment up required for avatar" << node->getUUID() << "whose current send rate is" - << node->getOutboundBandwidth(); - - float newFullRateDistance = nodeData->getFullRateDistance(); - newFullRateDistance += (nodeData->getMaxFullRateDistance() - newFullRateDistance) / 2.0f; + // lets adjust the full rate distance to target a bandwidth in the middle of the hyterisis gap + currentFullRateDistance *= (_maxKbpsPerNode * HYSTERISIS_MIDDLE_PERCENTAGE) / avatarDataRateLastSecond; - qDebug() << "max FRD is" << nodeData->getMaxFullRateDistance(); - qDebug() << "current FRD is" << nodeData->getFullRateDistance(); - nodeData->setFullRateDistance(newFullRateDistance); - - qDebug() << "new FRD is" << nodeData->getFullRateDistance(); - + nodeData->setFullRateDistance(currentFullRateDistance); nodeData->resetNumFramesSinceFRDAdjustment(); } } else { @@ -265,7 +261,7 @@ void AvatarMixer::broadcastAvatarData() { float distanceToAvatar = glm::length(myPosition - otherPosition); // potentially update the max full rate distance for this frame - maxDistanceThisFrame = std::max(maxDistanceThisFrame, distanceToAvatar); + maxAvatarDistanceThisFrame = std::max(maxAvatarDistanceThisFrame, distanceToAvatar); if (distanceToAvatar != 0.0f && distribution(generator) > (nodeData->getFullRateDistance() / distanceToAvatar)) { @@ -305,7 +301,6 @@ void AvatarMixer::broadcastAvatarData() { billboardPacket.append(otherNode->getUUID().toRfc4122()); billboardPacket.append(otherNodeData->getAvatar().getBillboard()); - qDebug() << "Sending a billboard packet to" << node->getUUID(); nodeList->writeDatagram(billboardPacket, node); ++_sumBillboardPackets; @@ -322,8 +317,6 @@ void AvatarMixer::broadcastAvatarData() { individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122()); identityPacket.append(individualData); - qDebug() << "Sending an identity packet to" << node->getUUID(); - nodeList->writeDatagram(identityPacket, node); ++_sumIdentityPackets; @@ -338,9 +331,9 @@ void AvatarMixer::broadcastAvatarData() { if (numOtherAvatars == 0) { // update the full rate distance to FLOAT_MAX since we didn't have any other avatars to send - nodeData->setMaxFullRateDistance(FLT_MAX); + nodeData->setMaxAvatarDistance(FLT_MAX); } else { - nodeData->setMaxFullRateDistance(maxDistanceThisFrame); + nodeData->setMaxAvatarDistance(maxAvatarDistanceThisFrame); } } ); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index eeb1f70f99..17330ac891 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -28,7 +28,7 @@ bool AvatarMixerClientData::checkAndSetHasReceivedFirstPackets() { void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { jsonObject["display_name"] = _avatar.getDisplayName(); jsonObject["full_rate_distance"] = _fullRateDistance; - jsonObject["max_full_rate_distance"] = _maxFullRateDistance; + jsonObject["max_avatar_distance"] = _maxAvatarDistance; jsonObject["num_avatars_sent_last_frame"] = _numAvatarsSentLastFrame; jsonObject[OUTBOUND_AVATAR_DATA_STATS_KEY] = getOutboundAvatarDataKbps(); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 2f9ac7150d..cccc5ee60f 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -39,11 +39,11 @@ public: quint64 getIdentityChangeTimestamp() const { return _identityChangeTimestamp; } void setIdentityChangeTimestamp(quint64 identityChangeTimestamp) { _identityChangeTimestamp = identityChangeTimestamp; } - float getFullRateDistance() const { return _fullRateDistance; } void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; } - - void setMaxFullRateDistance(float maxFullRateDistance) { _maxFullRateDistance = maxFullRateDistance; } - float getMaxFullRateDistance() const { return _maxFullRateDistance; } + float getFullRateDistance() const { return _fullRateDistance; } + + void setMaxAvatarDistance(float maxAvatarDistance) { _maxAvatarDistance = maxAvatarDistance; } + float getMaxAvatarDistance() const { return _maxAvatarDistance; } void resetNumAvatarsSentLastFrame() { _numAvatarsSentLastFrame = 0; } void incrementNumAvatarsSentLastFrame() { ++_numAvatarsSentLastFrame; } @@ -65,7 +65,7 @@ private: quint64 _billboardChangeTimestamp = 0; quint64 _identityChangeTimestamp = 0; float _fullRateDistance = FLT_MAX; - float _maxFullRateDistance = FLT_MAX; + float _maxAvatarDistance = FLT_MAX; int _numAvatarsSentLastFrame = 0; int _numFramesSinceAdjustment = 0; SimpleMovingAverage _avgOtherAvatarDataRate;