From 8006719fda737e7f10ac35758ca04b2e9427755e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:42:23 -0700 Subject: [PATCH 01/41] add new stats to OctreeServer --- assignment-client/src/octree/OctreeServer.cpp | 29 +++++++++++++++---- assignment-client/src/octree/OctreeServer.h | 12 ++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c31beb7831..6c9e5cf70c 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -20,10 +20,13 @@ OctreeServer* OctreeServer::_instance = NULL; int OctreeServer::_clientCount = 0; -SimpleMovingAverage OctreeServer::_averageLoopTime(10000); -SimpleMovingAverage OctreeServer::_averageEncodeTime(10000); -SimpleMovingAverage OctreeServer::_averageTreeWaitTime(10000); -SimpleMovingAverage OctreeServer::_averageNodeWaitTime(10000); +SimpleMovingAverage OctreeServer::_averageLoopTime(100000); +SimpleMovingAverage OctreeServer::_averageEncodeTime(100000); +SimpleMovingAverage OctreeServer::_averageInsideTime(100000); +SimpleMovingAverage OctreeServer::_averageTreeWaitTime(100000); +SimpleMovingAverage OctreeServer::_averageNodeWaitTime(100000); +SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(100000); +SimpleMovingAverage OctreeServer::_averagePacketSendingTime(100000); void OctreeServer::attachQueryNodeToNode(Node* newNode) { if (!newNode->getLinkedData()) { @@ -276,9 +279,20 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& qDebug() << "averageLoopTime=" << averageLoopTime; float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %5.2f msecs\r\n", averageEncodeTime); + statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); qDebug() << "averageEncodeTime=" << averageEncodeTime; + float averageInsideTime = getAverageInsideTime(); + statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); + qDebug() << "averageInsideTime=" << averageInsideTime; + + float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); + statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); + qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; + + float averagePacketSendingTime = getAveragePacketSendingTime(); + statsString += QString().sprintf(" Average packet sending time: %7.2f usecs\r\n", averagePacketSendingTime); + qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; float averageTreeWaitTime = getAverageTreeWaitTime(); statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs\r\n", averageTreeWaitTime); @@ -288,6 +302,11 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; + float encodeToInsidePercent = (averageEncodeTime / averageInsideTime) * AS_PERCENT; + statsString += QString().sprintf(" Percent 'inside' time is encode: %5.2f%%\r\n", encodeToInsidePercent); + qDebug() << "averageInsideTime=" << averageInsideTime; + + statsString += QString("\r\n"); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 94dcf18dc8..022da9d658 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -80,11 +80,20 @@ public: static void trackEncodeTime(float time) { _averageEncodeTime.updateAverage(time); } static float getAverageEncodeTime() { return _averageEncodeTime.getAverage(); } + static void trackInsideTime(float time) { _averageInsideTime.updateAverage(time); } + static float getAverageInsideTime() { return _averageInsideTime.getAverage(); } + static void trackTreeWaitTime(float time) { _averageTreeWaitTime.updateAverage(time); } static float getAverageTreeWaitTime() { return _averageTreeWaitTime.getAverage(); } static void trackNodeWaitTime(float time) { _averageNodeWaitTime.updateAverage(time); } static float getAverageNodeWaitTime() { return _averageNodeWaitTime.getAverage(); } + static void trackCompressAndWriteTime(float time) { _averageCompressAndWriteTime.updateAverage(time); } + static float getAverageCompressAndWriteTime() { return _averageCompressAndWriteTime.getAverage(); } + + static void trackPacketSendingTime(float time) { _averagePacketSendingTime.updateAverage(time); } + static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } + bool handleHTTPRequest(HTTPConnection* connection, const QString& path); public slots: /// runs the voxel server assignment @@ -124,8 +133,11 @@ protected: static int _clientCount; static SimpleMovingAverage _averageLoopTime; static SimpleMovingAverage _averageEncodeTime; + static SimpleMovingAverage _averageInsideTime; static SimpleMovingAverage _averageTreeWaitTime; static SimpleMovingAverage _averageNodeWaitTime; + static SimpleMovingAverage _averageCompressAndWriteTime; + static SimpleMovingAverage _averagePacketSendingTime; }; #endif // __octree_server__OctreeServer__ From 8afbcae3657e714723e2423bc3f2c2c0e5bcc85f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:43:11 -0700 Subject: [PATCH 02/41] tweak to seeing load test --- examples/seeingVoxelsExample.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/seeingVoxelsExample.js b/examples/seeingVoxelsExample.js index 62ebd599ee..65907bde40 100644 --- a/examples/seeingVoxelsExample.js +++ b/examples/seeingVoxelsExample.js @@ -13,6 +13,7 @@ var yawDirection = -1; var yaw = 45; var yawMax = 70; var yawMin = 20; +var vantagePoint = {x: 5000, y: 500, z: 5000}; var isLocal = false; @@ -21,10 +22,10 @@ var orientation = Quat.fromPitchYawRoll(0, yaw, 0); function init() { if (isLocal) { - MyAvatar.position = {x: 5000, y: 500, z: 5000}; + MyAvatar.position = vantagePoint; MyAvatar.orientation = orientation; } else { - VoxelViewer.setPosition({x: 5000, y: 500, z: 5000}); + VoxelViewer.setPosition(vantagePoint); VoxelViewer.setOrientation(orientation); VoxelViewer.queryOctree(); Agent.isAvatar = true; From 1f88ede1aa287a0b4e70a60c5bc7b859f0edb144 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:47:50 -0700 Subject: [PATCH 03/41] switch OctreeElementBag to use QSet as it's underlying data store --- libraries/octree/src/OctreeElementBag.cpp | 138 +++++----------------- libraries/octree/src/OctreeElementBag.h | 10 +- 2 files changed, 32 insertions(+), 116 deletions(-) diff --git a/libraries/octree/src/OctreeElementBag.cpp b/libraries/octree/src/OctreeElementBag.cpp index c3ad44a604..3ecdfaf2e3 100644 --- a/libraries/octree/src/OctreeElementBag.cpp +++ b/libraries/octree/src/OctreeElementBag.cpp @@ -10,9 +10,8 @@ #include OctreeElementBag::OctreeElementBag() : - _bagElements(NULL), - _elementsInUse(0), - _sizeOfElementsArray(0) { + _bagElements() +{ OctreeElement::addDeleteHook(this); }; @@ -21,114 +20,35 @@ OctreeElementBag::~OctreeElementBag() { deleteAll(); } -void OctreeElementBag::deleteAll() { - if (_bagElements) { - delete[] _bagElements; - } - _bagElements = NULL; - _elementsInUse = 0; - _sizeOfElementsArray = 0; -} - - -const int GROW_BAG_BY = 100; - -// put a node into the bag -void OctreeElementBag::insert(OctreeElement* element) { - - // Search for where we should live in the bag (sorted) - // Note: change this to binary search... instead of linear! - int insertAt = _elementsInUse; - for (int i = 0; i < _elementsInUse; i++) { - // just compare the pointers... that's good enough - if (_bagElements[i] == element) { - return; // exit early!! - } - - if (_bagElements[i] > element) { - insertAt = i; - break; - } - } - // at this point, inserAt will be the location we want to insert at. - - // If we don't have room in our bag, then grow the bag - if (_sizeOfElementsArray < _elementsInUse + 1) { - OctreeElement** oldBag = _bagElements; - _bagElements = new OctreeElement*[_sizeOfElementsArray + GROW_BAG_BY]; - _sizeOfElementsArray += GROW_BAG_BY; - - // If we had an old bag... - if (oldBag) { - // copy old elements into the new bag, but leave a space where we need to - // insert the new node - memcpy(_bagElements, oldBag, insertAt * sizeof(OctreeElement*)); - memcpy(&_bagElements[insertAt + 1], &oldBag[insertAt], (_elementsInUse - insertAt) * sizeof(OctreeElement*)); - delete[] oldBag; - } - } else { - // move existing elements further back in the bag array, leave a space where we need to - // insert the new node - memmove(&_bagElements[insertAt + 1], &_bagElements[insertAt], (_elementsInUse - insertAt) * sizeof(OctreeElement*)); - } - _bagElements[insertAt] = element; - _elementsInUse++; -} - -// pull a node out of the bag (could come in any order) -OctreeElement* OctreeElementBag::extract() { - // pull the last node out, and shrink our list... - if (_elementsInUse) { - - // get the last element - OctreeElement* element = _bagElements[_elementsInUse - 1]; - - // reduce the count - _elementsInUse--; - - return element; - } - return NULL; -} - -bool OctreeElementBag::contains(OctreeElement* element) { - for (int i = 0; i < _elementsInUse; i++) { - // just compare the pointers... that's good enough - if (_bagElements[i] == element) { - return true; // exit early!! - } - // if we're past where it should be, then it's not here! - if (_bagElements[i] > element) { - return false; - } - } - // if we made it through the entire bag, it's not here! - return false; -} - -void OctreeElementBag::remove(OctreeElement* element) { - int foundAt = -1; - for (int i = 0; i < _elementsInUse; i++) { - // just compare the pointers... that's good enough - if (_bagElements[i] == element) { - foundAt = i; - break; - } - // if we're past where it should be, then it's not here! - if (_bagElements[i] > element) { - break; - } - } - // if we found it, then we need to remove it.... - if (foundAt != -1) { - memmove(&_bagElements[foundAt], &_bagElements[foundAt + 1], (_elementsInUse - foundAt) * sizeof(OctreeElement*)); - _elementsInUse--; - } -} - - void OctreeElementBag::elementDeleted(OctreeElement* element) { remove(element); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() } +void OctreeElementBag::deleteAll() { + _bagElements.clear(); +} + + +void OctreeElementBag::insert(OctreeElement* element) { + _bagElements.insert(element); +} + +OctreeElement* OctreeElementBag::extract() { + OctreeElement* result = NULL; + + if (_bagElements.size() > 0) { + QSet::iterator front = _bagElements.begin(); + result = *front; + _bagElements.erase(front); + } + return result; +} + +bool OctreeElementBag::contains(OctreeElement* element) { + return _bagElements.contains(element); +} + +void OctreeElementBag::remove(OctreeElement* element) { + _bagElements.remove(element); +} diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index a952b52095..ba74a05516 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -27,18 +27,14 @@ public: bool contains(OctreeElement* element); // is this element in the bag? void remove(OctreeElement* element); // remove a specific element from the bag - bool isEmpty() const { return (_elementsInUse == 0); } - int count() const { return _elementsInUse; } + bool isEmpty() const { return _bagElements.isEmpty(); } + int count() const { return _bagElements.size(); } void deleteAll(); virtual void elementDeleted(OctreeElement* element); private: - - OctreeElement** _bagElements; - int _elementsInUse; - int _sizeOfElementsArray; - //int _hookID; + QSet _bagElements; }; #endif /* defined(__hifi__OctreeElementBag__) */ From af71359c60077b6831deaf83ffa6b456325cf32e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:49:33 -0700 Subject: [PATCH 04/41] remove encode/deleting/start/done guards --- libraries/octree/src/Octree.cpp | 66 +-------------------------------- libraries/octree/src/Octree.h | 34 ----------------- 2 files changed, 1 insertion(+), 99 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 4c8ed8c9f6..15c1b62864 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -355,15 +355,7 @@ void Octree::deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool colla OctreeElement* node = _rootNode; - // We can't encode and delete nodes at the same time, so we guard against deleting any node that is actively - // being encoded. And we stick that code on our pendingDelete list. - if (isEncoding(codeBuffer)) { - queueForLaterDelete(codeBuffer); - } else { - startDeleting(codeBuffer); - deleteOctalCodeFromTreeRecursion(node, &args); - doneDeleting(codeBuffer); - } + deleteOctalCodeFromTreeRecursion(node, &args); } void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraData) { @@ -796,11 +788,8 @@ int Octree::encodeTreeBitstream(OctreeElement* node, return bytesWritten; } - startEncoding(node); - // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (params.viewFrustum && !node->isInView(*params.viewFrustum)) { - doneEncoding(node); params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; return bytesWritten; } @@ -824,7 +813,6 @@ int Octree::encodeTreeBitstream(OctreeElement* node, // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... if (!roomForOctalCode) { - doneEncoding(node); bag.insert(node); // add the node back to the bag so it will eventually get included params.stopReason = EncodeBitstreamParams::DIDNT_FIT; return bytesWritten; @@ -867,8 +855,6 @@ int Octree::encodeTreeBitstream(OctreeElement* node, packetData->endSubTree(); } - doneEncoding(node); - return bytesWritten; } @@ -1622,56 +1608,6 @@ void dumpSetContents(const char* name, std::set set) { */ } -void Octree::startEncoding(OctreeElement* node) { - _encodeSetLock.lock(); - _codesBeingEncoded.insert(node->getOctalCode()); - _encodeSetLock.unlock(); -} - -void Octree::doneEncoding(OctreeElement* node) { - _encodeSetLock.lock(); - _codesBeingEncoded.erase(node->getOctalCode()); - _encodeSetLock.unlock(); - - // if we have any pending delete codes, then delete them now. - emptyDeleteQueue(); -} - -void Octree::startDeleting(const unsigned char* code) { - _deleteSetLock.lock(); - _codesBeingDeleted.insert(code); - _deleteSetLock.unlock(); -} - -void Octree::doneDeleting(const unsigned char* code) { - _deleteSetLock.lock(); - _codesBeingDeleted.erase(code); - _deleteSetLock.unlock(); -} - -bool Octree::isEncoding(const unsigned char* codeBuffer) { - _encodeSetLock.lock(); - bool isEncoding = (_codesBeingEncoded.find(codeBuffer) != _codesBeingEncoded.end()); - _encodeSetLock.unlock(); - return isEncoding; -} - -void Octree::queueForLaterDelete(const unsigned char* codeBuffer) { - _deletePendingSetLock.lock(); - _codesPendingDelete.insert(codeBuffer); - _deletePendingSetLock.unlock(); -} - -void Octree::emptyDeleteQueue() { - _deletePendingSetLock.lock(); - for (std::set::iterator i = _codesPendingDelete.begin(); i != _codesPendingDelete.end(); ++i) { - const unsigned char* codeToDelete = *i; - _codesBeingDeleted.erase(codeToDelete); - deleteOctalCodeFromTree(codeToDelete, COLLAPSE_EMPTY_TREE); - } - _deletePendingSetLock.unlock(); -} - void Octree::cancelImport() { _stopImport = true; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 4c237b5f56..6e53e1f240 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -302,40 +302,6 @@ protected: bool _shouldReaverage; bool _stopImport; - /// Octal Codes of any subtrees currently being encoded. While any of these codes is being encoded, ancestors and - /// descendants of them can not be deleted. - std::set _codesBeingEncoded; - /// mutex lock to protect the encoding set - QMutex _encodeSetLock; - - /// Called to indicate that a OctreeElement is in the process of being encoded. - void startEncoding(OctreeElement* node); - /// Called to indicate that a OctreeElement is done being encoded. - void doneEncoding(OctreeElement* node); - /// Is the Octal Code currently being deleted? - bool isEncoding(const unsigned char* codeBuffer); - - /// Octal Codes of any subtrees currently being deleted. While any of these codes is being deleted, ancestors and - /// descendants of them can not be encoded. - std::set _codesBeingDeleted; - /// mutex lock to protect the deleting set - QMutex _deleteSetLock; - - /// Called to indicate that an octal code is in the process of being deleted. - void startDeleting(const unsigned char* code); - /// Called to indicate that an octal code is done being deleted. - void doneDeleting(const unsigned char* code); - /// Octal Codes that were attempted to be deleted but couldn't be because they were actively being encoded, and were - /// instead queued for later delete - std::set _codesPendingDelete; - /// mutex lock to protect the deleting set - QMutex _deletePendingSetLock; - - /// Adds an Octal Code to the set of codes that needs to be deleted - void queueForLaterDelete(const unsigned char* codeBuffer); - /// flushes out any Octal Codes that had to be queued - void emptyDeleteQueue(); - QReadWriteLock _lock; /// This tree is receiving inbound viewer datagrams. From 0d4066a347b66372884fc31b0288e4b2c35385d0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 10:07:26 -0700 Subject: [PATCH 05/41] added note --- libraries/octree/src/ViewFrustum.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index aeffcc4968..66f1445ddc 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -277,6 +277,10 @@ ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const { return keyholeResult; } + // TODO: These calculations are expensive, taking up 80% of our time in this function. + // This appears to be expensive because we have to test the distance to each plane. + // One suggested optimization is to first check against the approximated cone. We might + // also be able to test against the cone to the bounding sphere of the box. for(int i=0; i < 6; i++) { const glm::vec3& normal = _planes[i].getNormal(); const glm::vec3& boxVertexP = box.getVertexP(normal); From 4c39a891be141c305861c2a67f15ee75cb3e13af Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 10:23:07 -0700 Subject: [PATCH 06/41] add more packet sending statistics to server --- .../src/octree/OctreeSendThread.cpp | 44 +++++++++++++++++-- assignment-client/src/octree/OctreeServer.cpp | 2 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index ef69771607..7f75f17252 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -414,6 +414,13 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int extraPackingAttempts = 0; bool completedScene = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) { + float lockWaitElapsedUsec = 0.0f; + float encodeElapsedUsec = 0.0f; + float compressAndWriteElapsedUsec = 0.0f; + float packetSendingElapsedUsec = 0.0f; + + quint64 startInside = usecTimestampNow(); + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d", truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), @@ -442,7 +449,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->lockForRead(); quint64 lockWaitEnd = usecTimestampNow(); - float lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); + lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); nodeData->stats.encodeStarted(); @@ -450,8 +457,8 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); quint64 encodeEnd = usecTimestampNow(); - int encodeElapsedMsec = (encodeEnd - encodeStart)/USECS_PER_MSEC; - OctreeServer::trackEncodeTime(encodeElapsedMsec); + encodeElapsedUsec = (encodeEnd - encodeStart)/USECS_PER_MSEC; + OctreeServer::trackEncodeTime(encodeElapsedUsec); // If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've // sent the entire scene. We want to know this below so we'll actually write this content into @@ -491,6 +498,9 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // mean we should send the previous packet contents and reset it. if (completedScene || lastNodeDidntFit) { if (_packetData.hasContent()) { + + quint64 compressAndWriteStart = usecTimestampNow(); + // if for some reason the finalized size is greater than our available size, then probably the "compressed" // form actually inflated beyond our padding, and in this case we will send the current packet, then // write to out new packet... @@ -514,11 +524,15 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue } nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); extraPackingAttempts = 0; + quint64 compressAndWriteEnd = usecTimestampNow(); + compressAndWriteElapsedUsec = (float)(compressAndWriteEnd - compressAndWriteStart); } // If we're not running compressed, then we know we can just send now. Or if we're running compressed, but // the packet doesn't have enough space to bother attempting to pack more... bool sendNow = true; + + quint64 packetSendingStart = usecTimestampNow(); if (nodeData->getCurrentPacketIsCompressed() && nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING && @@ -549,7 +563,27 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue debug::valueOf(nodeData->getWantCompression()), targetSize); } _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset + + quint64 packetSendingEnd = usecTimestampNow(); + packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); } + OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); + OctreeServer::trackEncodeTime(encodeElapsedUsec); + OctreeServer::trackCompressAndWriteTime(compressAndWriteElapsedUsec); + OctreeServer::trackPacketSendingTime(packetSendingElapsedUsec); + + quint64 endInside = usecTimestampNow(); + quint64 elapsedInsideUsecs = endInside - startInside; + OctreeServer::trackInsideTime((float)elapsedInsideUsecs); + + float insideMsecs = (float)elapsedInsideUsecs / (float)USECS_PER_MSEC; + if (insideMsecs > 1.0f) { + qDebug()<< "inside msecs=" << insideMsecs + << "lockWait usec=" << lockWaitElapsedUsec + << "encode usec=" << encodeElapsedUsec + << "compress usec=" << compressAndWriteElapsedUsec + << "sending usec=" << packetSendingElapsedUsec; + } } @@ -614,6 +648,10 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue } // end if bag wasn't empty, and so we sent stuff... + if (truePacketsSent > 0 || packetsSentThisInterval > 0) { + qDebug() << "truePacketsSent=" << truePacketsSent << "packetsSentThisInterval=" << packetsSentThisInterval; + } + return truePacketsSent; } diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 6c9e5cf70c..04467c87e6 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -302,7 +302,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; - float encodeToInsidePercent = (averageEncodeTime / averageInsideTime) * AS_PERCENT; + float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; statsString += QString().sprintf(" Percent 'inside' time is encode: %5.2f%%\r\n", encodeToInsidePercent); qDebug() << "averageInsideTime=" << averageInsideTime; From 21458036cc7288a0ae9ddd6bba99787e7df51529 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 10:37:41 -0700 Subject: [PATCH 07/41] clean up formatting of sending stats --- .../src/octree/OctreeSendThread.cpp | 2 +- assignment-client/src/octree/OctreeServer.cpp | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 7f75f17252..ef47b4faef 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -457,7 +457,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); quint64 encodeEnd = usecTimestampNow(); - encodeElapsedUsec = (encodeEnd - encodeStart)/USECS_PER_MSEC; + encodeElapsedUsec = (float)(encodeEnd - encodeStart); OctreeServer::trackEncodeTime(encodeElapsedUsec); // If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 04467c87e6..7be8c34087 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -278,33 +278,43 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& statsString += QString().sprintf(" Average packetLoop() time: %5.2f msecs\r\n", averageLoopTime); qDebug() << "averageLoopTime=" << averageLoopTime; - float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); - qDebug() << "averageEncodeTime=" << averageEncodeTime; - float averageInsideTime = getAverageInsideTime(); statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); qDebug() << "averageInsideTime=" << averageInsideTime; + float averageTreeWaitTime = getAverageTreeWaitTime(); + statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs\r\n", averageTreeWaitTime); + qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; + + float averageEncodeTime = getAverageEncodeTime(); + statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); + qDebug() << "averageEncodeTime=" << averageEncodeTime; + float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; float averagePacketSendingTime = getAveragePacketSendingTime(); - statsString += QString().sprintf(" Average packet sending time: %7.2f usecs\r\n", averagePacketSendingTime); + statsString += QString().sprintf(" Average packet sending time: %7.2f usecs (includes node lock)\r\n", + averagePacketSendingTime); + qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; - float averageTreeWaitTime = getAverageTreeWaitTime(); - statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs\r\n", averageTreeWaitTime); - qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; - float averageNodeWaitTime = getAverageNodeWaitTime(); statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; + statsString += QString().sprintf("---------------------------------------------------\r\n"); + float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" Percent 'inside' time is encode: %5.2f%%\r\n", encodeToInsidePercent); - qDebug() << "averageInsideTime=" << averageInsideTime; + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", + encodeToInsidePercent); + qDebug() << "encodeToInsidePercent=" << encodeToInsidePercent; + + float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f + : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); + qDebug() << "waitToInsidePercent=" << waitToInsidePercent; From cbdd1592134b5b3c4f5b0b33cfcec447398a6e32 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 10:55:43 -0700 Subject: [PATCH 08/41] fix constness --- libraries/shared/src/SimpleMovingAverage.cpp | 4 ++-- libraries/shared/src/SimpleMovingAverage.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp index 5a55486216..f52a8b1c3d 100644 --- a/libraries/shared/src/SimpleMovingAverage.cpp +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -44,11 +44,11 @@ void SimpleMovingAverage::reset() { _numSamples = 0; } -float SimpleMovingAverage::getEventDeltaAverage() { +float SimpleMovingAverage::getEventDeltaAverage() const { return (ONE_MINUS_WEIGHTING * _eventDeltaAverage) + (WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000.0f)); } -float SimpleMovingAverage::getAverageSampleValuePerSecond() { +float SimpleMovingAverage::getAverageSampleValuePerSecond() const { return _average * (1 / getEventDeltaAverage()); } \ No newline at end of file diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h index 9788aafe58..f11cd16e58 100644 --- a/libraries/shared/src/SimpleMovingAverage.h +++ b/libraries/shared/src/SimpleMovingAverage.h @@ -20,10 +20,10 @@ public: int updateAverage(float sample); void reset(); - int getSampleCount() { return _numSamples; }; - float getAverage() { return _average; }; - float getEventDeltaAverage(); - float getAverageSampleValuePerSecond(); + int getSampleCount() const { return _numSamples; }; + float getAverage() const { return _average; }; + float getEventDeltaAverage() const; + float getAverageSampleValuePerSecond() const; private: int _numSamples; uint64_t _lastEventTimestamp; From a448b90726a43a8ecf076303a9a3f62145be2b0e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 10:57:39 -0700 Subject: [PATCH 09/41] fix some Q_OBJECT macros in class headers --- interface/src/VoxelHideShowThread.h | 1 + interface/src/VoxelPacketProcessor.h | 1 + 2 files changed, 2 insertions(+) diff --git a/interface/src/VoxelHideShowThread.h b/interface/src/VoxelHideShowThread.h index 2925888022..dc1f2062c1 100644 --- a/interface/src/VoxelHideShowThread.h +++ b/interface/src/VoxelHideShowThread.h @@ -16,6 +16,7 @@ /// Generalized threaded processor for handling received inbound packets. class VoxelHideShowThread : public GenericThread { + Q_OBJECT public: VoxelHideShowThread(VoxelSystem* theSystem); diff --git a/interface/src/VoxelPacketProcessor.h b/interface/src/VoxelPacketProcessor.h index 42040fe446..2acd347e99 100644 --- a/interface/src/VoxelPacketProcessor.h +++ b/interface/src/VoxelPacketProcessor.h @@ -16,6 +16,7 @@ /// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() class VoxelPacketProcessor : public ReceivedPacketProcessor { + Q_OBJECT protected: virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); }; From 96572d3752aca673f2bc11f87162ead57b6a9f44 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 10:57:53 -0700 Subject: [PATCH 10/41] fix some Q_OBJECT macros in class headers --- libraries/shared/src/ReceivedPacketProcessor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/ReceivedPacketProcessor.h b/libraries/shared/src/ReceivedPacketProcessor.h index 7c99218753..f88512639b 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.h +++ b/libraries/shared/src/ReceivedPacketProcessor.h @@ -18,6 +18,7 @@ /// Generalized threaded processor for handling received inbound packets. class ReceivedPacketProcessor : public GenericThread { + Q_OBJECT public: ReceivedPacketProcessor() { } From 981ab7374aa3509a0d8eaf6bd2e9427c00541574 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 11:01:09 -0700 Subject: [PATCH 11/41] fix crash in client shutdown, clean up some debugging, clean up Q_OBJECT --- .../src/octree/OctreeInboundPacketProcessor.h | 2 +- .../src/octree/OctreeQueryNode.cpp | 4 +- .../src/octree/OctreeQueryNode.h | 6 ++ .../src/octree/OctreeSendThread.cpp | 62 +++++++++++-------- .../src/octree/OctreeSendThread.h | 1 + assignment-client/src/octree/OctreeServer.cpp | 7 +-- 6 files changed, 49 insertions(+), 33 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 237a22d954..e2ec1b5c50 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -44,7 +44,7 @@ typedef std::map::iterator NodeToSenderStatsMapIterato /// Handles processing of incoming network packets for the voxel-server. As with other ReceivedPacketProcessor classes /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() class OctreeInboundPacketProcessor : public ReceivedPacketProcessor { - + Q_OBJECT public: OctreeInboundPacketProcessor(OctreeServer* myServer); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 8cb577d2f9..729b9150d0 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -35,11 +35,13 @@ OctreeQueryNode::OctreeQueryNode() : _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _lodChanged(false), _lodInitialized(false), - _sequenceNumber(0) + _sequenceNumber(0), + _scheduleForDelete(false) { } OctreeQueryNode::~OctreeQueryNode() { +qDebug() << "OctreeQueryNode::~OctreeQueryNode()"; if (_octreeSendThread) { _octreeSendThread->terminate(); delete _octreeSendThread; diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 6d4dee300a..b4df18fbb8 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -23,6 +23,7 @@ class OctreeSendThread; class OctreeServer; class OctreeQueryNode : public OctreeQuery { + Q_OBJECT public: OctreeQueryNode(); virtual ~OctreeQueryNode(); @@ -85,6 +86,9 @@ public: void dumpOutOfView(); + bool isScheduledForDelete() const { return _scheduleForDelete; } + void scheduleForDelete() { _scheduleForDelete = true; } + private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); @@ -119,6 +123,8 @@ private: bool _lodInitialized; OCTREE_PACKET_SEQUENCE _sequenceNumber; + + bool _scheduleForDelete; }; #endif /* defined(__hifi__OctreeQueryNode__) */ diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index ef47b4faef..98c7f2fbf5 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -34,7 +34,6 @@ OctreeSendThread::~OctreeSendThread() { bool OctreeSendThread::process() { - const int MAX_NODE_MISSING_CHECKS = 10; if (_nodeMissingCount > MAX_NODE_MISSING_CHECKS) { qDebug() << "our target node:" << _nodeUUID << "has been missing the last" << _nodeMissingCount @@ -64,6 +63,10 @@ bool OctreeSendThread::process() { } packetsSent = packetDistributor(node, nodeData, viewFrustumChanged); } + if (nodeData->isScheduledForDelete()) { + nodeData->deleteLater(); + node->setLinkedData(NULL); + } } else { _nodeMissingCount++; } @@ -83,7 +86,7 @@ bool OctreeSendThread::process() { PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { - if (true || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { + if ((_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { qDebug() << "Last send took too much time (" << (elapsed / USECS_PER_MSEC) <<" msecs), barely sleeping 1 usec!\n"; } @@ -576,13 +579,16 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 elapsedInsideUsecs = endInside - startInside; OctreeServer::trackInsideTime((float)elapsedInsideUsecs); - float insideMsecs = (float)elapsedInsideUsecs / (float)USECS_PER_MSEC; - if (insideMsecs > 1.0f) { - qDebug()<< "inside msecs=" << insideMsecs - << "lockWait usec=" << lockWaitElapsedUsec - << "encode usec=" << encodeElapsedUsec - << "compress usec=" << compressAndWriteElapsedUsec - << "sending usec=" << packetSendingElapsedUsec; + const bool wantExtraDebugging = false; + if (wantExtraDebugging) { + float insideMsecs = (float)elapsedInsideUsecs / (float)USECS_PER_MSEC; + if (insideMsecs > 1.0f) { + qDebug()<< "inside msecs=" << insideMsecs + << "lockWait usec=" << lockWaitElapsedUsec + << "encode usec=" << encodeElapsedUsec + << "compress usec=" << compressAndWriteElapsedUsec + << "sending usec=" << packetSendingElapsedUsec; + } } } @@ -607,24 +613,27 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; - if (elapsedmsec > 100) { - if (elapsedmsec > 1000) { - int elapsedsec = (end - start)/1000000; - qDebug("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets %d nodes still to send", - elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } else { - qDebug("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " + bool wantsExtraDebugging = false; + if (wantsExtraDebugging) { + if (elapsedmsec > 100) { + if (elapsedmsec > 1000) { + int elapsedsec = (end - start)/1000000; + qDebug("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] " + "to generate %d bytes in %d packets %d nodes still to send", + elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, + trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); + } else { + qDebug("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " + "to generate %d bytes in %d packets, %d nodes still to send", + elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, + trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); + } + } else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { + qDebug("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " "to generate %d bytes in %d packets, %d nodes still to send", elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } - } else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets, %d nodes still to send", - elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } // if after sending packets we've emptied our bag, then we want to remember that we've sent all @@ -648,8 +657,11 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue } // end if bag wasn't empty, and so we sent stuff... - if (truePacketsSent > 0 || packetsSentThisInterval > 0) { - qDebug() << "truePacketsSent=" << truePacketsSent << "packetsSentThisInterval=" << packetsSentThisInterval; + const bool wantExtraDebugging = false; + if (wantExtraDebugging) { + if (truePacketsSent > 0 || packetsSentThisInterval > 0) { + qDebug() << "truePacketsSent=" << truePacketsSent << "packetsSentThisInterval=" << packetsSentThisInterval; + } } return truePacketsSent; diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 081e7f411f..39c27911b0 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -19,6 +19,7 @@ /// Threaded processor for sending voxel packets to a single client class OctreeSendThread : public GenericThread { + Q_OBJECT public: OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer); virtual ~OctreeSendThread(); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 7be8c34087..4d55455f76 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -766,12 +766,7 @@ void OctreeServer::nodeAdded(SharedNodePointer node) { void OctreeServer::nodeKilled(SharedNodePointer node) { OctreeQueryNode* nodeData = static_cast(node->getLinkedData()); if (nodeData) { - // Note: It should be safe to do this without locking the node, because if any other threads - // are using the SharedNodePointer, then they have a reference to the SharedNodePointer and the deleteLater() - // won't actually delete it until all threads have released their references to the pointer. - // But we can and should clear the linked data so that no one else tries to access it. - nodeData->deleteLater(); - node->setLinkedData(NULL); + nodeData->scheduleForDelete(); } } From 07adfed6b4e8cc8796f1522a7f3c33dc10b5bf83 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 13:47:05 -0700 Subject: [PATCH 12/41] call setLastHeardFromMicrostamp() when we get packets from nodes so NodeList doesn't drop them --- assignment-client/src/Agent.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 46f4d233c2..16674efcbf 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -95,12 +95,19 @@ void Agent::readPendingDatagrams() { // also give our local particle tree a chance to remap any internal locally created particles _particleViewer.getTree()->handleAddParticleResponse(receivedPacket); + // Make sure our Node and NodeList knows we've heard from this node. + SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket); + sourceNode->setLastHeardMicrostamp(usecTimestampNow()); + } else if (datagramPacketType == PacketTypeParticleData || datagramPacketType == PacketTypeParticleErase || datagramPacketType == PacketTypeOctreeStats || datagramPacketType == PacketTypeVoxelData ) { + // Make sure our Node and NodeList knows we've heard from this node. SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket); + sourceNode->setLastHeardMicrostamp(usecTimestampNow()); + QByteArray mutablePacket = receivedPacket; ssize_t messageLength = mutablePacket.size(); From 59b272d8db467a005e9908cf64c7fbf97fc47e8c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 13:47:46 -0700 Subject: [PATCH 13/41] make seeing voxels less noisy and more random --- examples/seeingVoxelsExample.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/seeingVoxelsExample.js b/examples/seeingVoxelsExample.js index 330634f5af..0cfe54d89e 100644 --- a/examples/seeingVoxelsExample.js +++ b/examples/seeingVoxelsExample.js @@ -20,6 +20,10 @@ var isLocal = false; // set up our VoxelViewer with a position and orientation var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + function init() { if (isLocal) { MyAvatar.position = vantagePoint; @@ -39,21 +43,26 @@ function keepLooking(deltaTime) { init(); } count++; - if (count % 10 == 0) { + if (count % getRandomInt(5, 15) == 0) { yaw += yawDirection; orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); if (yaw > yawMax || yaw < yawMin) { yawDirection = yawDirection * -1; } - print("calling VoxelViewer.queryOctree()... count=" + count + " yaw=" + yaw); + if (count % 10000 == 0) { + print("calling VoxelViewer.queryOctree()... count=" + count + " yaw=" + yaw); + } if (isLocal) { MyAvatar.orientation = orientation; } else { VoxelViewer.setOrientation(orientation); VoxelViewer.queryOctree(); - print("VoxelViewer.getOctreeElementsCount()=" + VoxelViewer.getOctreeElementsCount()); + + if (count % 10000 == 0) { + print("VoxelViewer.getOctreeElementsCount()=" + VoxelViewer.getOctreeElementsCount()); + } } } From e9684c0ee537d86e889834f84cd4fba47bc2f01f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 16:11:00 -0700 Subject: [PATCH 14/41] added more stats to octree server stats page --- .../src/octree/OctreeSendThread.cpp | 6 +- assignment-client/src/octree/OctreeServer.cpp | 104 ++++++++++++++---- assignment-client/src/octree/OctreeServer.h | 11 +- 3 files changed, 97 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index fd4bbbd7a9..dc8cd64ebe 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -117,7 +117,7 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node, OctreeQuer quint64 lockWaitEnd = usecTimestampNow(); float lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); OctreeServer::trackNodeWaitTime(lockWaitElapsedUsec); - + const HifiSockAddr* nodeAddress = node->getActiveSocket(); if (!nodeAddress) { return packetsSent; // without sending... @@ -452,15 +452,13 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue _myServer->getOctree()->lockForRead(); quint64 lockWaitEnd = usecTimestampNow(); lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); - OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); - + nodeData->stats.encodeStarted(); quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); quint64 encodeEnd = usecTimestampNow(); encodeElapsedUsec = (float)(encodeEnd - encodeStart); - OctreeServer::trackEncodeTime(encodeElapsedUsec); // If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've // sent the entire scene. We want to know this below so we'll actually write this content into diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 4d55455f76..22bdae16d8 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -20,13 +20,54 @@ OctreeServer* OctreeServer::_instance = NULL; int OctreeServer::_clientCount = 0; -SimpleMovingAverage OctreeServer::_averageLoopTime(100000); -SimpleMovingAverage OctreeServer::_averageEncodeTime(100000); -SimpleMovingAverage OctreeServer::_averageInsideTime(100000); -SimpleMovingAverage OctreeServer::_averageTreeWaitTime(100000); -SimpleMovingAverage OctreeServer::_averageNodeWaitTime(100000); -SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(100000); -SimpleMovingAverage OctreeServer::_averagePacketSendingTime(100000); +const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000; +SimpleMovingAverage OctreeServer::_averageLoopTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageInsideTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageTreeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageTreeShortWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageTreeLongWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageTreeExtraLongWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageNodeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averagePacketSendingTime(MOVING_AVERAGE_SAMPLE_COUNTS); +int OctreeServer::_extraLongTreeWait = 0; +int OctreeServer::_longTreeWait = 0; +int OctreeServer::_shortTreeWait = 0; + + +void OctreeServer::resetSendingStats() { + _averageLoopTime.reset(); + _averageEncodeTime.reset(); + _averageInsideTime.reset(); + _averageTreeWaitTime.reset(); + _averageTreeShortWaitTime.reset(); + _averageTreeLongWaitTime.reset(); + _averageTreeExtraLongWaitTime.reset(); + _averageNodeWaitTime.reset(); + _averageCompressAndWriteTime.reset(); + _averagePacketSendingTime.reset(); + _extraLongTreeWait = 0; + _longTreeWait = 0; + _shortTreeWait = 0; +} + +void OctreeServer::trackTreeWaitTime(float time) { + _averageTreeWaitTime.updateAverage(time); + const float MAX_SHORT_TIME = 10.0f; + const float MAX_LONG_TIME = 100.0f; + if (time <= MAX_SHORT_TIME) { + _shortTreeWait++; + _averageTreeShortWaitTime.updateAverage(time); + } else if (time <= MAX_LONG_TIME) { + _longTreeWait++; + _averageTreeLongWaitTime.updateAverage(time); + } else { + _extraLongTreeWait++; + _averageTreeExtraLongWaitTime.updateAverage(time); + } +} + void OctreeServer::attachQueryNodeToNode(Node* newNode) { if (!newNode->getLinkedData()) { @@ -124,6 +165,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& showStats = true; } else if (path == "/resetStats") { _octreeInboundPacketProcessor->resetStats(); + resetSendingStats(); showStats = true; } } @@ -258,7 +300,9 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& statsString += "\r\n"; // display outbound packet stats - statsString += QString("%1 Outbound Packet Statistics...\r\n").arg(getMyServerName()); + statsString += QString("%1 Outbound Packet Statistics... " + "[RESET]\r\n").arg(getMyServerName()); + quint64 totalOutboundPackets = OctreeSendThread::_totalPackets; quint64 totalOutboundBytes = OctreeSendThread::_totalBytes; quint64 totalWastedBytes = OctreeSendThread::_totalWastedBytes; @@ -266,7 +310,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& quint64 totalBytesOfBitMasks = OctreePacketData::getTotalBytesOfBitMasks(); quint64 totalBytesOfColor = OctreePacketData::getTotalBytesOfColor(); - const int COLUMN_WIDTH = 10; + const int COLUMN_WIDTH = 19; statsString += QString(" Configured Max PPS/Client: %1 pps/client\r\n") .arg(locale.toString((uint)getPacketsPerClientPerSecond()).rightJustified(COLUMN_WIDTH, ' ')); statsString += QString(" Configured Max PPS/Server: %1 pps/server\r\n\r\n") @@ -275,45 +319,66 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); float averageLoopTime = getAverageLoopTime(); - statsString += QString().sprintf(" Average packetLoop() time: %5.2f msecs\r\n", averageLoopTime); + statsString += QString().sprintf(" Average packetLoop() time: %5.2f msecs\r\n", averageLoopTime); qDebug() << "averageLoopTime=" << averageLoopTime; float averageInsideTime = getAverageInsideTime(); - statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); + statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); qDebug() << "averageInsideTime=" << averageInsideTime; + int allWaitTimes = _extraLongTreeWait +_longTreeWait + _shortTreeWait; + float averageTreeWaitTime = getAverageTreeWaitTime(); - statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs\r\n", averageTreeWaitTime); + statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs samples: %12d \r\n", + averageTreeWaitTime, allWaitTimes); qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; + float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; + statsString += QString().sprintf(" Avg tree lock short wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeShortWaitTime.getAverage(), + shortVsTotal * AS_PERCENT, _shortTreeWait); + qDebug() << "averageTreeShortWaitTime=" << _averageTreeShortWaitTime.getAverage(); + + float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; + statsString += QString().sprintf(" Avg tree lock long wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeLongWaitTime.getAverage(), + longVsTotal * AS_PERCENT, _longTreeWait); + qDebug() << "averageTreeLongWaitTime=" << _averageTreeLongWaitTime.getAverage(); + + float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; + statsString += QString().sprintf("Avg tree lock extra long wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeExtraLongWaitTime.getAverage(), + extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); + qDebug() << "averageTreeExtraLongWaitTime=" << _averageTreeExtraLongWaitTime.getAverage(); + float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); + statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); qDebug() << "averageEncodeTime=" << averageEncodeTime; float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); - statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); + statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; float averagePacketSendingTime = getAveragePacketSendingTime(); - statsString += QString().sprintf(" Average packet sending time: %7.2f usecs (includes node lock)\r\n", + statsString += QString().sprintf(" Average packet sending time: %7.2f usecs (includes node lock)\r\n", averagePacketSendingTime); qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; float averageNodeWaitTime = getAverageNodeWaitTime(); - statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); + statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; - statsString += QString().sprintf("---------------------------------------------------\r\n"); + statsString += QString().sprintf("----------------------------------------------------\r\n"); float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", encodeToInsidePercent); qDebug() << "encodeToInsidePercent=" << encodeToInsidePercent; float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); qDebug() << "waitToInsidePercent=" << waitToInsidePercent; @@ -761,6 +826,7 @@ void OctreeServer::run() { void OctreeServer::nodeAdded(SharedNodePointer node) { // we might choose to use this notifier to track clients in a pending state + qDebug() << "OctreeServer::nodeAdded() node:" << *node; } void OctreeServer::nodeKilled(SharedNodePointer node) { diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 022da9d658..636ecb8365 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -83,8 +83,9 @@ public: static void trackInsideTime(float time) { _averageInsideTime.updateAverage(time); } static float getAverageInsideTime() { return _averageInsideTime.getAverage(); } - static void trackTreeWaitTime(float time) { _averageTreeWaitTime.updateAverage(time); } + static void trackTreeWaitTime(float time); static float getAverageTreeWaitTime() { return _averageTreeWaitTime.getAverage(); } + static void trackNodeWaitTime(float time) { _averageNodeWaitTime.updateAverage(time); } static float getAverageNodeWaitTime() { return _averageNodeWaitTime.getAverage(); } @@ -95,6 +96,7 @@ public: static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } bool handleHTTPRequest(HTTPConnection* connection, const QString& path); + public slots: /// runs the voxel server assignment void run(); @@ -105,6 +107,7 @@ public slots: protected: void parsePayload(); void initHTTPManager(int port); + void resetSendingStats(); int _argc; const char** _argv; @@ -135,9 +138,15 @@ protected: static SimpleMovingAverage _averageEncodeTime; static SimpleMovingAverage _averageInsideTime; static SimpleMovingAverage _averageTreeWaitTime; + static SimpleMovingAverage _averageTreeShortWaitTime; + static SimpleMovingAverage _averageTreeLongWaitTime; + static SimpleMovingAverage _averageTreeExtraLongWaitTime; static SimpleMovingAverage _averageNodeWaitTime; static SimpleMovingAverage _averageCompressAndWriteTime; static SimpleMovingAverage _averagePacketSendingTime; + static int _extraLongTreeWait; + static int _longTreeWait; + static int _shortTreeWait; }; #endif // __octree_server__OctreeServer__ From 9411519dc980802e7fc1baef7e7c1674b16eded7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 16:37:07 -0700 Subject: [PATCH 15/41] fix SimpleMovingAverage::reset() --- libraries/shared/src/SimpleMovingAverage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp index f52a8b1c3d..676c85598e 100644 --- a/libraries/shared/src/SimpleMovingAverage.cpp +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -42,6 +42,8 @@ int SimpleMovingAverage::updateAverage(float sample) { void SimpleMovingAverage::reset() { _numSamples = 0; + _average = 0; + _eventDeltaAverage = 0; } float SimpleMovingAverage::getEventDeltaAverage() const { From 14f8245dd8f416bc6b59a4654fc3e230f78426ce Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 17:07:42 -0700 Subject: [PATCH 16/41] adding threading and read write lock tests --- tests/threads/CMakeLists.txt | 36 ++++++++++++ tests/threads/src/SampleReadThread.cpp | 65 ++++++++++++++++++++++ tests/threads/src/SampleReadThread.h | 31 +++++++++++ tests/threads/src/SampleWriteThread.cpp | 47 ++++++++++++++++ tests/threads/src/SampleWriteThread.h | 30 ++++++++++ tests/threads/src/SharedResource.cpp | 38 +++++++++++++ tests/threads/src/SharedResource.h | 40 ++++++++++++++ tests/threads/src/ThreadsTests.cpp | 73 +++++++++++++++++++++++++ tests/threads/src/ThreadsTests.h | 16 ++++++ tests/threads/src/main.cpp | 11 ++++ 10 files changed, 387 insertions(+) create mode 100644 tests/threads/CMakeLists.txt create mode 100644 tests/threads/src/SampleReadThread.cpp create mode 100644 tests/threads/src/SampleReadThread.h create mode 100644 tests/threads/src/SampleWriteThread.cpp create mode 100644 tests/threads/src/SampleWriteThread.h create mode 100644 tests/threads/src/SharedResource.cpp create mode 100644 tests/threads/src/SharedResource.h create mode 100644 tests/threads/src/ThreadsTests.cpp create mode 100644 tests/threads/src/ThreadsTests.h create mode 100644 tests/threads/src/main.cpp diff --git a/tests/threads/CMakeLists.txt b/tests/threads/CMakeLists.txt new file mode 100644 index 0000000000..f12a124b0c --- /dev/null +++ b/tests/threads/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8) + +if (WIN32) + cmake_policy (SET CMP0020 NEW) +endif (WIN32) + +set(TARGET_NAME threads-tests) + +set(ROOT_DIR ../..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") + +find_package(Qt5Core REQUIRED) + +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME} TRUE) + +include(${MACRO_DIR}/AutoMTC.cmake) +auto_mtc(${TARGET_NAME} ${ROOT_DIR}) + +qt5_use_modules(${TARGET_NAME} Core) + +#include glm +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +# link in the shared libraries +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) + +IF (WIN32) + #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) +ENDIF(WIN32) + diff --git a/tests/threads/src/SampleReadThread.cpp b/tests/threads/src/SampleReadThread.cpp new file mode 100644 index 0000000000..129c3f098b --- /dev/null +++ b/tests/threads/src/SampleReadThread.cpp @@ -0,0 +1,65 @@ +// +// SampleReadThread.cpp +// interface +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. +// + +#include + +#include + +#include "SharedResource.h" +#include "SampleReadThread.h" + +SampleReadThread::SampleReadThread(SharedResource* theResource, int id) : + _theResource(theResource), + _myID(id) { +} + +bool SampleReadThread::process() { + const quint64 FRAME_RATE = 60; + const quint64 USECS_PER_FRAME = USECS_PER_SECOND / FRAME_RATE; // every 60fps + + quint64 start = usecTimestampNow(); + _theResource->lockForRead(); + quint64 end = usecTimestampNow(); + quint64 elapsed = end - start; + + int theValue = _theResource->getValue(); + + bool wantDebugging = true; + if (wantDebugging) { + qDebug() << "SampleReadThread::process()... _myID=" << _myID << "lockForRead() took" << elapsed << "usecs" << + " _theResource->getValue()=" << theValue; + } + + quint64 startWork = usecTimestampNow(); + { + const int LOTS_OF_OPERATIONS = 100000; + for(int i = 0; i < LOTS_OF_OPERATIONS; i++) { + float x = rand(); + float y = rand(); + float z = x * y; + } + } + quint64 endWork = usecTimestampNow(); + quint64 elapsedWork = endWork - startWork; + qDebug() << "SampleReadThread::process()... _myID=" << _myID << " work took" << elapsedWork << "usecs"; + + _theResource->unlock(); + + + if (isStillRunning()) { + if (elapsed < USECS_PER_FRAME) { + quint64 sleepFor = USECS_PER_FRAME - elapsed; + usleep(sleepFor); + } else { + usleep(5); // sleep at least a little + } + } + return isStillRunning(); // keep running till they terminate us +} diff --git a/tests/threads/src/SampleReadThread.h b/tests/threads/src/SampleReadThread.h new file mode 100644 index 0000000000..a9a25ac7a1 --- /dev/null +++ b/tests/threads/src/SampleReadThread.h @@ -0,0 +1,31 @@ +// +// SampleReadThread.h +// tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__SampleReadThread__ +#define __interface__SampleReadThread__ + +#include + +class SharedResource; + +/// Generalized threaded processor for handling received inbound packets. +class SampleReadThread : public GenericThread { + Q_OBJECT +public: + SampleReadThread(SharedResource* theResource, int id); + +protected: + /// Implements generic processing behavior for this thread. + virtual bool process(); + +private: + SharedResource* _theResource; + int _myID; +}; + +#endif // __interface__SampleReadThread__ diff --git a/tests/threads/src/SampleWriteThread.cpp b/tests/threads/src/SampleWriteThread.cpp new file mode 100644 index 0000000000..0fbe68904d --- /dev/null +++ b/tests/threads/src/SampleWriteThread.cpp @@ -0,0 +1,47 @@ +// +// SampleWriteThread.cpp +// interface +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. +// + +#include + +#include + +#include "SharedResource.h" +#include "SampleWriteThread.h" + +SampleWriteThread::SampleWriteThread(SharedResource* theResource) : + _theResource(theResource) { +} + +bool SampleWriteThread::process() { + const quint64 USECS_PER_OPERATION = USECS_PER_SECOND * 1; // once every second. + + quint64 start = usecTimestampNow(); + _theResource->lockForWrite(); + quint64 end = usecTimestampNow(); + quint64 elapsed = end - start; + + int theValue = _theResource->incrementValue(); + + bool wantDebugging = false; + if (wantDebugging) { + qDebug() << "SampleWriteThread::process()... lockForWrite() took" << elapsed << "usecs" << + " _theResource->incrementValue()=" << theValue; + } + _theResource->unlock(); + + + if (isStillRunning()) { + if (elapsed < USECS_PER_OPERATION) { + quint64 sleepFor = USECS_PER_OPERATION - elapsed; + usleep(sleepFor); + } + } + return isStillRunning(); // keep running till they terminate us +} diff --git a/tests/threads/src/SampleWriteThread.h b/tests/threads/src/SampleWriteThread.h new file mode 100644 index 0000000000..970b4435a9 --- /dev/null +++ b/tests/threads/src/SampleWriteThread.h @@ -0,0 +1,30 @@ +// +// SampleWriteThread.h +// tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__SampleWriteThread__ +#define __interface__SampleWriteThread__ + +#include + +class SharedResource; + +/// Generalized threaded processor for handling received inbound packets. +class SampleWriteThread : public GenericThread { + Q_OBJECT +public: + SampleWriteThread(SharedResource* theResource); + +protected: + /// Implements generic processing behavior for this thread. + virtual bool process(); + +private: + SharedResource* _theResource; +}; + +#endif // __interface__SampleWriteThread__ diff --git a/tests/threads/src/SharedResource.cpp b/tests/threads/src/SharedResource.cpp new file mode 100644 index 0000000000..c397e6a7db --- /dev/null +++ b/tests/threads/src/SharedResource.cpp @@ -0,0 +1,38 @@ +// +// SharedResource.cpp +// tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "SharedResource.h" + +const int MOVING_AVERAGE_SAMPLES = 10000; + +SharedResource::SharedResource() : + _value(0), + _lockAverage(MOVING_AVERAGE_SAMPLES), + _lockForReadAverage(MOVING_AVERAGE_SAMPLES), + _lockForWriteAverage(MOVING_AVERAGE_SAMPLES) +{ +}; + +void SharedResource::lockForRead() { + quint64 start = usecTimestampNow(); + _lock.lockForRead(); + quint64 end = usecTimestampNow(); + quint64 elapsed = end - start; + _lockForReadAverage.updateAverage(elapsed); + _lockAverage.updateAverage(elapsed); +} +void SharedResource::lockForWrite() { + quint64 start = usecTimestampNow(); + _lock.lockForWrite(); + quint64 end = usecTimestampNow(); + quint64 elapsed = end - start; + _lockForWriteAverage.updateAverage(elapsed); + _lockAverage.updateAverage(elapsed); +} diff --git a/tests/threads/src/SharedResource.h b/tests/threads/src/SharedResource.h new file mode 100644 index 0000000000..1426471f16 --- /dev/null +++ b/tests/threads/src/SharedResource.h @@ -0,0 +1,40 @@ +// +// SharedResource.h +// tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__SharedResource__ +#define __interface__SharedResource__ + +#include + +#include + +/// Generalized threaded processor for handling received inbound packets. +class SharedResource { +public: + SharedResource(); + + void lockForRead(); + void lockForWrite(); + void unlock() { _lock.unlock(); } + + int getValue() const { return _value; } + int incrementValue() { return ++_value; } + + float getAverageLockTime() const { return _lockAverage.getAverage(); } + float getAverageLockForReadTime() const { return _lockForReadAverage.getAverage(); } + float getAverageLockForWriteTime() const { return _lockForWriteAverage.getAverage(); } + +private: + QReadWriteLock _lock; + int _value; + SimpleMovingAverage _lockAverage; + SimpleMovingAverage _lockForReadAverage; + SimpleMovingAverage _lockForWriteAverage; +}; + +#endif // __interface__SharedResource__ diff --git a/tests/threads/src/ThreadsTests.cpp b/tests/threads/src/ThreadsTests.cpp new file mode 100644 index 0000000000..15b1c66e63 --- /dev/null +++ b/tests/threads/src/ThreadsTests.cpp @@ -0,0 +1,73 @@ +// +// ThreadsTests.cpp +// thread-tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#include +#include + +#include +#include + +#include "SampleReadThread.h" +#include "SampleWriteThread.h" +#include "SharedResource.h" +#include "ThreadsTests.h" + + +void ThreadsTests::runAllTests() { + qDebug() << "START ThreadsTests::runAllTests()"; + + const quint64 TOTAL_RUN_TIME = USECS_PER_SECOND * 10; // run for 2 minutes + const quint64 MAIN_THREAD_SLEEP = USECS_PER_SECOND * 0.25; // main thread checks in every 1/4 second + quint64 start = usecTimestampNow(); + quint64 now = usecTimestampNow(); + + SharedResource resource; + + const int NUMBER_OF_READERS = 125; // + 3 = 128, Max number of QThreads on the mac. + QVector readThreads; + for(int i = 0; i < NUMBER_OF_READERS; i++) { + SampleReadThread* newReader = new SampleReadThread(&resource, i); + newReader->initialize(); + readThreads.append(newReader); + } + + SampleWriteThread write(&resource); + write.initialize(); + + while(now - start < TOTAL_RUN_TIME) { + float elapsed = (float)(now - start) / (float)USECS_PER_SECOND; + qDebug() << "Main thread still running... elapsed:" << elapsed << "seconds"; + qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs"; + qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs"; + qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs"; + qDebug() << " resource.value:" << resource.getValue(); + + + usleep(MAIN_THREAD_SLEEP); + now = usecTimestampNow(); + } + write.terminate(); + + foreach(SampleReadThread* readThread, readThreads) { + readThread->terminate(); + delete readThread; + } + readThreads.clear(); + + qDebug() << "DONE running..."; + qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs"; + qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs"; + qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs"; + qDebug() << " resource.value:" << resource.getValue(); + + qDebug() << "END ThreadsTests::runAllTests()"; + + qDebug() << "_POSIX_THREAD_THREADS_MAX" << _POSIX_THREAD_THREADS_MAX; + qDebug() << "QThread::idealThreadCount()" << QThread::idealThreadCount(); + +} diff --git a/tests/threads/src/ThreadsTests.h b/tests/threads/src/ThreadsTests.h new file mode 100644 index 0000000000..29bd9aebd4 --- /dev/null +++ b/tests/threads/src/ThreadsTests.h @@ -0,0 +1,16 @@ +// +// ThreadsTests.h +// threads-tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#ifndef __tests__ThreadsTests__ +#define __tests__ThreadsTests__ + +namespace ThreadsTests { + void runAllTests(); +} + +#endif // __tests__ThreadsTests__ diff --git a/tests/threads/src/main.cpp b/tests/threads/src/main.cpp new file mode 100644 index 0000000000..16f3ea0900 --- /dev/null +++ b/tests/threads/src/main.cpp @@ -0,0 +1,11 @@ +// +// main.cpp +// threads-tests +// + +#include "ThreadsTests.h" + +int main(int argc, char** argv) { + ThreadsTests::runAllTests(); + return 0; +} From 62dabd9c1c7448ab66ad9d83f39a81b095f642a7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 17:49:50 -0700 Subject: [PATCH 17/41] formatting of stats --- assignment-client/src/octree/OctreeServer.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 22bdae16d8..2fd9caea50 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -319,66 +319,66 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); float averageLoopTime = getAverageLoopTime(); - statsString += QString().sprintf(" Average packetLoop() time: %5.2f msecs\r\n", averageLoopTime); + statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs\r\n", averageLoopTime); qDebug() << "averageLoopTime=" << averageLoopTime; float averageInsideTime = getAverageInsideTime(); - statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); + statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs\r\n", averageInsideTime); qDebug() << "averageInsideTime=" << averageInsideTime; int allWaitTimes = _extraLongTreeWait +_longTreeWait + _shortTreeWait; float averageTreeWaitTime = getAverageTreeWaitTime(); - statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs samples: %12d \r\n", + statsString += QString().sprintf(" Average tree lock wait time: %9.2f usecs samples: %12d \r\n", averageTreeWaitTime, allWaitTimes); qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock short wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + statsString += QString().sprintf(" Avg tree lock short wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageTreeShortWaitTime.getAverage(), shortVsTotal * AS_PERCENT, _shortTreeWait); qDebug() << "averageTreeShortWaitTime=" << _averageTreeShortWaitTime.getAverage(); float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock long wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + statsString += QString().sprintf(" Avg tree lock long wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageTreeLongWaitTime.getAverage(), longVsTotal * AS_PERCENT, _longTreeWait); qDebug() << "averageTreeLongWaitTime=" << _averageTreeLongWaitTime.getAverage(); float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf("Avg tree lock extra long wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + statsString += QString().sprintf("Avg tree lock extra long wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageTreeExtraLongWaitTime.getAverage(), extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); qDebug() << "averageTreeExtraLongWaitTime=" << _averageTreeExtraLongWaitTime.getAverage(); float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); + statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime); qDebug() << "averageEncodeTime=" << averageEncodeTime; float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); - statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); + statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", averageCompressAndWriteTime); qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; float averagePacketSendingTime = getAveragePacketSendingTime(); - statsString += QString().sprintf(" Average packet sending time: %7.2f usecs (includes node lock)\r\n", + statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", averagePacketSendingTime); qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; float averageNodeWaitTime = getAverageNodeWaitTime(); - statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); + statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; - statsString += QString().sprintf("----------------------------------------------------\r\n"); + statsString += QString().sprintf("------------------------------------------------------\r\n"); float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", encodeToInsidePercent); qDebug() << "encodeToInsidePercent=" << encodeToInsidePercent; float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); qDebug() << "waitToInsidePercent=" << waitToInsidePercent; From c09974bcda41415f23e6c073f76528e7eb0ce855 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 17:51:09 -0700 Subject: [PATCH 18/41] use parents inFrustum status to optimize children --- libraries/octree/src/Octree.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 63a7fb8e88..2776af6dab 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -892,6 +892,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, return bytesAtThisLevel; } } + + ViewFrustum::location nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside // caller can pass NULL as viewFrustum if they want everything if (params.viewFrustum) { @@ -907,11 +909,13 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, params.stopReason = EncodeBitstreamParams::LOD_SKIP; return bytesAtThisLevel; } + + nodeLocationThisView = node->inFrustum(*params.viewFrustum); // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view - if (!node->isInView(*params.viewFrustum)) { + if (nodeLocationThisView == ViewFrustum::OUTSIDE) { if (params.stats) { params.stats->skippedOutOfView(node); } @@ -1065,7 +1069,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, OctreeElement* childNode = sortedChildren[i]; int originalIndex = indexOfChildren[i]; - bool childIsInView = (childNode && (!params.viewFrustum || childNode->isInView(*params.viewFrustum))); + bool childIsInView = (childNode && + ( !params.viewFrustum || // no view frustum was given, everything is assumed in view + (nodeLocationThisView == ViewFrustum::INSIDE) || // the parent was fully in view, we can assume ALL children are + (nodeLocationThisView == ViewFrustum::INTERSECT && childNode->isInView(*params.viewFrustum)) // the parent intersects and the child is in view + )); if (!childIsInView) { // must check childNode here, because it could be we got here because there was no childNode From 28766bebc81e14d210215b9c0f15878cba22cac8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 18:30:08 -0700 Subject: [PATCH 19/41] pass down parents inFrustum() state to recursion to allow further optimization --- libraries/octree/src/Octree.cpp | 20 +++++++++++++++----- libraries/octree/src/Octree.h | 3 ++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 2776af6dab..58cfd9b15d 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -829,7 +829,10 @@ int Octree::encodeTreeBitstream(OctreeElement* node, params.stats->traversed(node); } - int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, currentEncodeLevel); + ViewFrustum::location parentLocationThisView = ViewFrustum::INTERSECT; // assume parent is in view, but not fully + + int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, + currentEncodeLevel, parentLocationThisView); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -861,7 +864,8 @@ int Octree::encodeTreeBitstream(OctreeElement* node, int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params, int& currentEncodeLevel) const { + EncodeBitstreamParams& params, int& currentEncodeLevel, + const ViewFrustum::location& parentLocationThisView) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -909,8 +913,13 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, params.stopReason = EncodeBitstreamParams::LOD_SKIP; return bytesAtThisLevel; } - - nodeLocationThisView = node->inFrustum(*params.viewFrustum); + + // if the parent isn't known to be INSIDE, then it must be INTERSECT, and we should double check to see + // if we are INSIDE, INTERSECT, or OUTSIDE + if (parentLocationThisView != ViewFrustum::INSIDE) { + assert(parentLocationThisView != ViewFrustum::OUTSIDE); // we shouldn't be here if our parent was OUTSIDE! + nodeLocationThisView = node->inFrustum(*params.viewFrustum); + } // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if @@ -1300,7 +1309,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, // This only applies in the view frustum case, in other cases, like file save and copy/past where // no viewFrustum was requested, we still want to recurse the child tree. if (!params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) { - childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packetData, bag, params, thisLevel); + childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packetData, bag, params, + thisLevel, nodeLocationThisView); } // remember this for reshuffling diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 6e53e1f240..f029431d87 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -287,7 +287,8 @@ protected: int encodeTreeBitstreamRecursion(OctreeElement* node, OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params, int& currentEncodeLevel) const; + EncodeBitstreamParams& params, int& currentEncodeLevel, + const ViewFrustum::location& parentLocationThisView) const; static bool countOctreeElementsOperation(OctreeElement* node, void* extraData); From fc50cc0604a4d53a83985b22ee8e10540ef738ea Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 23:40:07 -0700 Subject: [PATCH 20/41] improving server stats --- .../src/octree/OctreeSendThread.cpp | 6 +- assignment-client/src/octree/OctreeServer.cpp | 227 ++++++++++++++---- assignment-client/src/octree/OctreeServer.h | 33 ++- 3 files changed, 215 insertions(+), 51 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index dc8cd64ebe..e91b999c20 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -416,9 +416,9 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int extraPackingAttempts = 0; bool completedScene = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) { - float lockWaitElapsedUsec = 0.0f; - float encodeElapsedUsec = 0.0f; - float compressAndWriteElapsedUsec = 0.0f; + float lockWaitElapsedUsec = OctreeServer::SKIP_TIME; + float encodeElapsedUsec = OctreeServer::SKIP_TIME; + float compressAndWriteElapsedUsec = OctreeServer::SKIP_TIME; float packetSendingElapsedUsec = 0.0f; quint64 startInside = usecTimestampNow(); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 2fd9caea50..377ff0ea7a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -21,42 +21,107 @@ OctreeServer* OctreeServer::_instance = NULL; int OctreeServer::_clientCount = 0; const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000; + +float OctreeServer::SKIP_TIME = -1.0f; // use this for trackXXXTime() calls for non-times + SimpleMovingAverage OctreeServer::_averageLoopTime(MOVING_AVERAGE_SAMPLE_COUNTS); -SimpleMovingAverage OctreeServer::_averageEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); SimpleMovingAverage OctreeServer::_averageInsideTime(MOVING_AVERAGE_SAMPLE_COUNTS); + +SimpleMovingAverage OctreeServer::_averageEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageShortEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageLongEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageExtraLongEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +int OctreeServer::_extraLongEncode = 0; +int OctreeServer::_longEncode = 0; +int OctreeServer::_shortEncode = 0; +int OctreeServer::_noEncode = 0; + SimpleMovingAverage OctreeServer::_averageTreeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); SimpleMovingAverage OctreeServer::_averageTreeShortWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); SimpleMovingAverage OctreeServer::_averageTreeLongWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); SimpleMovingAverage OctreeServer::_averageTreeExtraLongWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); -SimpleMovingAverage OctreeServer::_averageNodeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); -SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(MOVING_AVERAGE_SAMPLE_COUNTS); -SimpleMovingAverage OctreeServer::_averagePacketSendingTime(MOVING_AVERAGE_SAMPLE_COUNTS); int OctreeServer::_extraLongTreeWait = 0; int OctreeServer::_longTreeWait = 0; int OctreeServer::_shortTreeWait = 0; +int OctreeServer::_noTreeWait = 0; + +SimpleMovingAverage OctreeServer::_averageNodeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); + +SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageShortCompressTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageLongCompressTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageExtraLongCompressTime(MOVING_AVERAGE_SAMPLE_COUNTS); +int OctreeServer::_extraLongCompress = 0; +int OctreeServer::_longCompress = 0; +int OctreeServer::_shortCompress = 0; +int OctreeServer::_noCompress = 0; + +SimpleMovingAverage OctreeServer::_averagePacketSendingTime(MOVING_AVERAGE_SAMPLE_COUNTS); void OctreeServer::resetSendingStats() { _averageLoopTime.reset(); + _averageEncodeTime.reset(); + _averageShortEncodeTime.reset(); + _averageLongEncodeTime.reset(); + _averageExtraLongEncodeTime.reset(); + _extraLongEncode = 0; + _longEncode = 0; + _shortEncode = 0; + _noEncode = 0; + _averageInsideTime.reset(); _averageTreeWaitTime.reset(); _averageTreeShortWaitTime.reset(); _averageTreeLongWaitTime.reset(); _averageTreeExtraLongWaitTime.reset(); - _averageNodeWaitTime.reset(); - _averageCompressAndWriteTime.reset(); - _averagePacketSendingTime.reset(); _extraLongTreeWait = 0; _longTreeWait = 0; _shortTreeWait = 0; + _noTreeWait = 0; + + _averageNodeWaitTime.reset(); + + _averageCompressAndWriteTime.reset(); + _averageShortCompressTime.reset(); + _averageLongCompressTime.reset(); + _averageExtraLongCompressTime.reset(); + _extraLongCompress = 0; + _longCompress = 0; + _shortCompress = 0; + _noCompress = 0; + + _averagePacketSendingTime.reset(); +} + +void OctreeServer::trackEncodeTime(float time) { + const float MAX_SHORT_TIME = 10.0f; + const float MAX_LONG_TIME = 100.0f; + + if (time == SKIP_TIME) { + _noEncode++; + time = 0.0f; + } else if (time <= MAX_SHORT_TIME) { + _shortEncode++; + _averageShortEncodeTime.updateAverage(time); + } else if (time <= MAX_LONG_TIME) { + _longEncode++; + _averageLongEncodeTime.updateAverage(time); + } else { + _extraLongEncode++; + _averageExtraLongEncodeTime.updateAverage(time); + } + _averageEncodeTime.updateAverage(time); } void OctreeServer::trackTreeWaitTime(float time) { - _averageTreeWaitTime.updateAverage(time); const float MAX_SHORT_TIME = 10.0f; const float MAX_LONG_TIME = 100.0f; - if (time <= MAX_SHORT_TIME) { + if (time == SKIP_TIME) { + _noTreeWait++; + time = 0.0f; + } else if (time <= MAX_SHORT_TIME) { _shortTreeWait++; _averageTreeShortWaitTime.updateAverage(time); } else if (time <= MAX_LONG_TIME) { @@ -66,6 +131,26 @@ void OctreeServer::trackTreeWaitTime(float time) { _extraLongTreeWait++; _averageTreeExtraLongWaitTime.updateAverage(time); } + _averageTreeWaitTime.updateAverage(time); +} + +void OctreeServer::trackCompressAndWriteTime(float time) { + const float MAX_SHORT_TIME = 10.0f; + const float MAX_LONG_TIME = 100.0f; + if (time == SKIP_TIME) { + _noCompress++; + time = 0.0f; + } else if (time <= MAX_SHORT_TIME) { + _shortCompress++; + _averageShortCompressTime.updateAverage(time); + } else if (time <= MAX_LONG_TIME) { + _longCompress++; + _averageLongCompressTime.updateAverage(time); + } else { + _extraLongCompress++; + _averageExtraLongCompressTime.updateAverage(time); + } + _averageCompressAndWriteTime.updateAverage(time); } @@ -319,67 +404,123 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); float averageLoopTime = getAverageLoopTime(); - statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs\r\n", averageLoopTime); - qDebug() << "averageLoopTime=" << averageLoopTime; + statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs\r\n", averageLoopTime); float averageInsideTime = getAverageInsideTime(); - statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs\r\n", averageInsideTime); - qDebug() << "averageInsideTime=" << averageInsideTime; + statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs\r\n\r\n", averageInsideTime); - int allWaitTimes = _extraLongTreeWait +_longTreeWait + _shortTreeWait; + int allWaitTimes = _extraLongTreeWait +_longTreeWait + _shortTreeWait + _noTreeWait; float averageTreeWaitTime = getAverageTreeWaitTime(); - statsString += QString().sprintf(" Average tree lock wait time: %9.2f usecs samples: %12d \r\n", - averageTreeWaitTime, allWaitTimes); - qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; + statsString += QString().sprintf(" Average tree lock wait time:" + " %9.2f usecs samples: %12d \r\n", + averageTreeWaitTime, allWaitTimes); + + float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noTreeWait / (float)allWaitTimes) : 0.0f; + statsString += QString().sprintf(" No Lock Wait:" + " (%6.2f%%) samples: %12d \r\n", + zeroVsTotal * AS_PERCENT, _noTreeWait); float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock short wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", - _averageTreeShortWaitTime.getAverage(), - shortVsTotal * AS_PERCENT, _shortTreeWait); - qDebug() << "averageTreeShortWaitTime=" << _averageTreeShortWaitTime.getAverage(); + statsString += QString().sprintf(" Avg tree lock short wait time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeShortWaitTime.getAverage(), + shortVsTotal * AS_PERCENT, _shortTreeWait); float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock long wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", - _averageTreeLongWaitTime.getAverage(), - longVsTotal * AS_PERCENT, _longTreeWait); - qDebug() << "averageTreeLongWaitTime=" << _averageTreeLongWaitTime.getAverage(); + statsString += QString().sprintf(" Avg tree lock long wait time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeLongWaitTime.getAverage(), + longVsTotal * AS_PERCENT, _longTreeWait); float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf("Avg tree lock extra long wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", - _averageTreeExtraLongWaitTime.getAverage(), - extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); - qDebug() << "averageTreeExtraLongWaitTime=" << _averageTreeExtraLongWaitTime.getAverage(); + statsString += QString().sprintf(" Avg tree lock extra long wait time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", + _averageTreeExtraLongWaitTime.getAverage(), + extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime); - qDebug() << "averageEncodeTime=" << averageEncodeTime; + statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime); + + int allEncodeTimes = _noEncode + _shortEncode + _longEncode + _extraLongEncode; + + float zeroVsTotalEncode = (allEncodeTimes > 0) ? ((float)_noEncode / (float)allEncodeTimes) : 0.0f; + statsString += QString().sprintf(" No Encode:" + " (%6.2f%%) samples: %12d \r\n", + zeroVsTotalEncode * AS_PERCENT, _noEncode); + + float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f; + statsString += QString().sprintf(" Avg tree lock short encode time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageShortEncodeTime.getAverage(), + shortVsTotalEncode * AS_PERCENT, _shortEncode); + + float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f; + statsString += QString().sprintf(" Avg tree lock long encode time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageLongEncodeTime.getAverage(), + longVsTotalEncode * AS_PERCENT, _longEncode); + + float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f; + statsString += QString().sprintf("Avg tree lock extra long encode time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", + _averageExtraLongEncodeTime.getAverage(), + extraLongVsTotalEncode * AS_PERCENT, _extraLongEncode); + float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); - statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", averageCompressAndWriteTime); - qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; + statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", averageCompressAndWriteTime); + + int allCompressTimes = _noCompress + _shortCompress + _longCompress + _extraLongCompress; + + float zeroVsTotalCompress = (allCompressTimes > 0) ? ((float)_noCompress / (float)allCompressTimes) : 0.0f; + statsString += QString().sprintf(" No compression:" + " (%6.2f%%) samples: %12d \r\n", + zeroVsTotalCompress * AS_PERCENT, _noCompress); + + float shortVsTotalCompress = (allCompressTimes > 0) ? ((float)_shortCompress / (float)allCompressTimes) : 0.0f; + statsString += QString().sprintf(" Avg short compress time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageShortCompressTime.getAverage(), + shortVsTotalCompress * AS_PERCENT, _shortCompress); + + float longVsTotalCompress = (allCompressTimes > 0) ? ((float)_longCompress / (float)allCompressTimes) : 0.0f; + statsString += QString().sprintf(" Avg long compress time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageLongCompressTime.getAverage(), + longVsTotalCompress * AS_PERCENT, _longCompress); + + float extraLongVsTotalCompress = (allCompressTimes > 0) ? ((float)_extraLongCompress / (float)allCompressTimes) : 0.0f; + statsString += QString().sprintf(" Avg extra long compress time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", + _averageExtraLongCompressTime.getAverage(), + extraLongVsTotalCompress * AS_PERCENT, _extraLongCompress); float averagePacketSendingTime = getAveragePacketSendingTime(); - statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", + statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", averagePacketSendingTime); - qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; - float averageNodeWaitTime = getAverageNodeWaitTime(); - statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); - qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; + statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); - statsString += QString().sprintf("------------------------------------------------------\r\n"); + statsString += QString().sprintf("--------------------------------------------------------------\r\n"); float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", encodeToInsidePercent); - qDebug() << "encodeToInsidePercent=" << encodeToInsidePercent; float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); - qDebug() << "waitToInsidePercent=" << waitToInsidePercent; + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); + + float compressAndWriteToInsidePercent = averageInsideTime == 0.0f ? 0.0f + : (averageCompressAndWriteTime / averageInsideTime) * AS_PERCENT; + statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n", + compressAndWriteToInsidePercent); + + float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f + : (averagePacketSendingTime / averageInsideTime) * AS_PERCENT; + statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n", sendingToInsidePercent); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 636ecb8365..182fef81dd 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -73,11 +73,13 @@ public: virtual int sendSpecialPacket(const SharedNodePointer& node) { return 0; } static void attachQueryNodeToNode(Node* newNode); + + static float SKIP_TIME; // use this for trackXXXTime() calls for non-times static void trackLoopTime(float time) { _averageLoopTime.updateAverage(time); } static float getAverageLoopTime() { return _averageLoopTime.getAverage(); } - static void trackEncodeTime(float time) { _averageEncodeTime.updateAverage(time); } + static void trackEncodeTime(float time); static float getAverageEncodeTime() { return _averageEncodeTime.getAverage(); } static void trackInsideTime(float time) { _averageInsideTime.updateAverage(time); } @@ -89,7 +91,7 @@ public: static void trackNodeWaitTime(float time) { _averageNodeWaitTime.updateAverage(time); } static float getAverageNodeWaitTime() { return _averageNodeWaitTime.getAverage(); } - static void trackCompressAndWriteTime(float time) { _averageCompressAndWriteTime.updateAverage(time); } + static void trackCompressAndWriteTime(float time); static float getAverageCompressAndWriteTime() { return _averageCompressAndWriteTime.getAverage(); } static void trackPacketSendingTime(float time) { _averagePacketSendingTime.updateAverage(time); } @@ -135,18 +137,39 @@ protected: static int _clientCount; static SimpleMovingAverage _averageLoopTime; + static SimpleMovingAverage _averageEncodeTime; + static SimpleMovingAverage _averageShortEncodeTime; + static SimpleMovingAverage _averageLongEncodeTime; + static SimpleMovingAverage _averageExtraLongEncodeTime; + static int _extraLongEncode; + static int _longEncode; + static int _shortEncode; + static int _noEncode; + static SimpleMovingAverage _averageInsideTime; static SimpleMovingAverage _averageTreeWaitTime; static SimpleMovingAverage _averageTreeShortWaitTime; static SimpleMovingAverage _averageTreeLongWaitTime; static SimpleMovingAverage _averageTreeExtraLongWaitTime; - static SimpleMovingAverage _averageNodeWaitTime; - static SimpleMovingAverage _averageCompressAndWriteTime; - static SimpleMovingAverage _averagePacketSendingTime; static int _extraLongTreeWait; static int _longTreeWait; static int _shortTreeWait; + static int _noTreeWait; + + static SimpleMovingAverage _averageNodeWaitTime; + + static SimpleMovingAverage _averageCompressAndWriteTime; + static SimpleMovingAverage _averageShortCompressTime; + static SimpleMovingAverage _averageLongCompressTime; + static SimpleMovingAverage _averageExtraLongCompressTime; + static int _extraLongCompress; + static int _longCompress; + static int _shortCompress; + static int _noCompress; + + static SimpleMovingAverage _averagePacketSendingTime; + }; #endif // __octree_server__OctreeServer__ From 34b2ccb9d71ea867fa26833915a4fa7798f2262f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 00:02:47 -0700 Subject: [PATCH 21/41] adding not sent to stats --- .../src/octree/OctreeSendThread.cpp | 17 +++++------------ assignment-client/src/octree/OctreeServer.cpp | 17 +++++++++++++++++ assignment-client/src/octree/OctreeServer.h | 3 ++- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index e91b999c20..df7a1a91ee 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -419,7 +419,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue float lockWaitElapsedUsec = OctreeServer::SKIP_TIME; float encodeElapsedUsec = OctreeServer::SKIP_TIME; float compressAndWriteElapsedUsec = OctreeServer::SKIP_TIME; - float packetSendingElapsedUsec = 0.0f; + float packetSendingElapsedUsec = OctreeServer::SKIP_TIME; quint64 startInside = usecTimestampNow(); @@ -532,8 +532,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // the packet doesn't have enough space to bother attempting to pack more... bool sendNow = true; - quint64 packetSendingStart = usecTimestampNow(); - if (nodeData->getCurrentPacketIsCompressed() && nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING && extraPackingAttempts <= REASONABLE_NUMBER_OF_PACKING_ATTEMPTS) { @@ -542,10 +540,11 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; if (sendNow) { - if (forceDebugging) { - qDebug("about to call handlePacketSend() .... line: %d -- sendNow = TRUE", __LINE__); - } + quint64 packetSendingStart = usecTimestampNow(); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + quint64 packetSendingEnd = usecTimestampNow(); + packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); + if (wantCompression) { targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } @@ -558,14 +557,8 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // a larger compressed size then uncompressed size targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; } - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d",__LINE__, - debug::valueOf(nodeData->getWantCompression()), targetSize); - } _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset - quint64 packetSendingEnd = usecTimestampNow(); - packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); } OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); OctreeServer::trackEncodeTime(encodeElapsedUsec); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 377ff0ea7a..c3df8fc6ac 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -57,6 +57,7 @@ int OctreeServer::_shortCompress = 0; int OctreeServer::_noCompress = 0; SimpleMovingAverage OctreeServer::_averagePacketSendingTime(MOVING_AVERAGE_SAMPLE_COUNTS); +int OctreeServer::_noSend = 0; void OctreeServer::resetSendingStats() { @@ -93,6 +94,7 @@ void OctreeServer::resetSendingStats() { _noCompress = 0; _averagePacketSendingTime.reset(); + _noSend = 0; } void OctreeServer::trackEncodeTime(float time) { @@ -153,6 +155,15 @@ void OctreeServer::trackCompressAndWriteTime(float time) { _averageCompressAndWriteTime.updateAverage(time); } +void OctreeServer::trackPacketSendingTime(float time) { + if (time == SKIP_TIME) { + _noSend++; + time = 0.0f; + } + _averagePacketSendingTime.updateAverage(time); +} + + void OctreeServer::attachQueryNodeToNode(Node* newNode) { if (!newNode->getLinkedData()) { @@ -499,6 +510,12 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& float averagePacketSendingTime = getAveragePacketSendingTime(); statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", averagePacketSendingTime); + + float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ? + ((float)_noSend / (float)_averagePacketSendingTime.getSampleCount()) : 0.0f; + statsString += QString().sprintf(" Not sending:" + " (%6.2f%%) samples: %12d \r\n", + noVsTotalSend * AS_PERCENT, _noSend); float averageNodeWaitTime = getAverageNodeWaitTime(); statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 182fef81dd..44fca6f124 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -94,7 +94,7 @@ public: static void trackCompressAndWriteTime(float time); static float getAverageCompressAndWriteTime() { return _averageCompressAndWriteTime.getAverage(); } - static void trackPacketSendingTime(float time) { _averagePacketSendingTime.updateAverage(time); } + static void trackPacketSendingTime(float time); static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } bool handleHTTPRequest(HTTPConnection* connection, const QString& path); @@ -169,6 +169,7 @@ protected: static int _noCompress; static SimpleMovingAverage _averagePacketSendingTime; + static int _noSend; }; From beffb6deaef6e18bad1d4e9a3357c8fe023a2d13 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 01:04:52 -0700 Subject: [PATCH 22/41] clean up stats --- assignment-client/src/octree/OctreeServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c3df8fc6ac..34b457a8f7 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -461,19 +461,19 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& zeroVsTotalEncode * AS_PERCENT, _noEncode); float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock short encode time:" + statsString += QString().sprintf(" Avg short encode time:" " %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageShortEncodeTime.getAverage(), shortVsTotalEncode * AS_PERCENT, _shortEncode); float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock long encode time:" + statsString += QString().sprintf(" Avg long encode time:" " %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageLongEncodeTime.getAverage(), longVsTotalEncode * AS_PERCENT, _longEncode); float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f; - statsString += QString().sprintf("Avg tree lock extra long encode time:" + statsString += QString().sprintf(" Avg extra long encode time:" " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", _averageExtraLongEncodeTime.getAverage(), extraLongVsTotalEncode * AS_PERCENT, _extraLongEncode); From 329d3b37e0c75bd944058dd41fce440652a604ed Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 01:07:45 -0700 Subject: [PATCH 23/41] add last know root timestamp property to query node --- assignment-client/src/octree/OctreeQueryNode.cpp | 4 ++-- assignment-client/src/octree/OctreeQueryNode.h | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 18f2943a3c..cf57c4f1b5 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -36,12 +36,12 @@ OctreeQueryNode::OctreeQueryNode() : _lodChanged(false), _lodInitialized(false), _sequenceNumber(0), - _scheduleForDelete(false) + _scheduleForDelete(false), + _lastRootTimestamp(0) { } OctreeQueryNode::~OctreeQueryNode() { -qDebug() << "OctreeQueryNode::~OctreeQueryNode()"; if (_octreeSendThread) { _octreeSendThread->terminate(); delete _octreeSendThread; diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 18b00877ec..c103d87138 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -89,6 +89,10 @@ public: bool isScheduledForDelete() const { return _scheduleForDelete; } void scheduleForDelete() { _scheduleForDelete = true; } + quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } + void setLastRootTimestamp(quint64 timestamp) { _lastRootTimestamp = timestamp; } + + private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); @@ -125,6 +129,8 @@ private: OCTREE_PACKET_SEQUENCE _sequenceNumber; bool _scheduleForDelete; + + quint64 _lastRootTimestamp; }; #endif /* defined(__hifi__OctreeQueryNode__) */ From 86c2b5baa7c88c47eb2bb84d8cb24eb250f4c863 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 01:51:30 -0700 Subject: [PATCH 24/41] removed some debugging, added some comments, more work on optimizaiton --- .../src/octree/OctreeQueryNode.h | 2 + .../src/octree/OctreeSendThread.cpp | 171 +++++------------- 2 files changed, 52 insertions(+), 121 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index c103d87138..6f17117ca2 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -91,6 +91,8 @@ public: quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } void setLastRootTimestamp(quint64 timestamp) { _lastRootTimestamp = timestamp; } + unsigned int getlastOctreePacketLength() const { return _lastOctreePacketLength; } + int getDuplicatePacketCount() const { return _duplicatePacketCount; } private: diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index df7a1a91ee..132090f15d 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -262,23 +262,8 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // then let's just send that waiting packet. if (!nodeData->getCurrentPacketFormatMatches()) { if (nodeData->isPacketWaiting()) { - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("about to call handlePacketSend() .... line: %d -- format change " - "wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s " - "currentPacketIsCompressed=%s", - __LINE__, - debug::valueOf(wantColor), debug::valueOf(wantCompression), - debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); - } packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } else { - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s", - debug::valueOf(wantColor), debug::valueOf(wantCompression), - debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); - } nodeData->resetOctreePacket(); } int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; @@ -345,44 +330,25 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // track completed scenes and send out the stats packet accordingly nodeData->stats.sceneCompleted(); - ::endSceneSleepTime = _usleepTime; - unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime; + nodeData->setLastRootTimestamp(_myServer->getOctree()->getRoot()->getLastChanged()); - unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); - unsigned long elapsedTime = nodeData->stats.getElapsedTime(); + // TODO: add these to stats page + //::endSceneSleepTime = _usleepTime; + //unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime; + //unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); + //unsigned long elapsedTime = nodeData->stats.getElapsedTime(); - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("about to call handlePacketSend() .... line: %d -- completed scene", __LINE__ ); - } int packetsJustSent = handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval += packetsJustSent; - if (forceDebugging) { - qDebug("packetsJustSent=%d packetsSentThisInterval=%d", packetsJustSent, packetsSentThisInterval); - } - - if (forceDebugging || _myServer->wantsDebugSending()) { - qDebug() << "Scene completed at " << usecTimestampNow() - << "encodeTime:" << encodeTime - << " sleepTime:" << sleepTime - << " elapsed:" << elapsedTime - << " Packets:" << _totalPackets - << " Bytes:" << _totalBytes - << " Wasted:" << _totalWastedBytes; - } // If we're starting a full scene, then definitely we want to empty the nodeBag if (isFullScene) { nodeData->nodeBag.deleteAll(); } - if (forceDebugging || _myServer->wantsDebugSending()) { - qDebug() << "Scene started at " << usecTimestampNow() - << " Packets:" << _totalPackets - << " Bytes:" << _totalBytes - << " Wasted:" << _totalWastedBytes; - } - - ::startSceneSleepTime = _usleepTime; + // TODO: add these to stats page + //::startSceneSleepTime = _usleepTime; + // start tracking our stats nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot(), _myServer->getJurisdiction()); @@ -401,8 +367,10 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue if (!nodeData->nodeBag.isEmpty()) { int bytesWritten = 0; quint64 start = usecTimestampNow(); - quint64 startCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; - quint64 startCompressCalls = OctreePacketData::getCompressContentCalls(); + + // TODO: add these to stats page + //quint64 startCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; + //quint64 startCompressCalls = OctreePacketData::getCompressContentCalls(); int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND)); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); @@ -432,34 +400,58 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue bool lastNodeDidntFit = false; // assume each node fits if (!nodeData->nodeBag.isEmpty()) { OctreeElement* subTree = nodeData->nodeBag.extract(); + + /* TODO: Looking for a way to prevent locking and encoding a tree that is not + // going to result in any packets being sent... + // + // If our node is root, and the root hasn't changed, and our view hasn't changed, + // and we've already seen at least one duplicate packet, then we probably don't need + // to lock the tree and encode, because the result should be that no bytes will be + // encoded, and this will be a duplicate packet from the last one we sent... + OctreeElement* root = _myServer->getOctree()->getRoot(); + bool skipEncode = false; + if ( + (subTree == root) + && (nodeData->getLastRootTimestamp() == root->getLastChanged()) + && !viewFrustumChanged + && (nodeData->getDuplicatePacketCount() > 0) + ) { + qDebug() << "is root, root not changed, view not changed, already seen a duplicate!" + << "Can we skip it?"; + skipEncode = true; + } + */ + bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; - + float voxelSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); - + int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() - ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - + ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); + EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction()); - + // TODO: should this include the lock time or not? This stat is sent down to the client, + // it seems like it may be a good idea to include the lock time as part of the encode time + // are reported to client. Since you can encode without the lock + nodeData->stats.encodeStarted(); + quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->lockForRead(); quint64 lockWaitEnd = usecTimestampNow(); lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); - nodeData->stats.encodeStarted(); - quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); quint64 encodeEnd = usecTimestampNow(); encodeElapsedUsec = (float)(encodeEnd - encodeStart); - + // If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've // sent the entire scene. We want to know this below so we'll actually write this content into // the packet and send it @@ -509,19 +501,9 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue if (writtenSize > nodeData->getAvailable()) { - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("about to call handlePacketSend() .... line: %d -- " - "writtenSize[%d] > available[%d] too big, sending packet as is.", - __LINE__, writtenSize, nodeData->getAvailable()); - } packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug(">>>>>> calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%u", - nodeData->getAvailable(), _packetData.getFinalizedSize(), - _packetData.getUncompressedSize(), _packetData.getTargetSize()); - } nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); extraPackingAttempts = 0; quint64 compressAndWriteEnd = usecTimestampNow(); @@ -568,18 +550,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 endInside = usecTimestampNow(); quint64 elapsedInsideUsecs = endInside - startInside; OctreeServer::trackInsideTime((float)elapsedInsideUsecs); - - const bool wantExtraDebugging = false; - if (wantExtraDebugging) { - float insideMsecs = (float)elapsedInsideUsecs / (float)USECS_PER_MSEC; - if (insideMsecs > 1.0f) { - qDebug()<< "inside msecs=" << insideMsecs - << "lockWait usec=" << lockWaitElapsedUsec - << "encode usec=" << encodeElapsedUsec - << "compress usec=" << compressAndWriteElapsedUsec - << "sending usec=" << packetSendingElapsedUsec; - } - } } @@ -597,63 +567,22 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int elapsedmsec = (end - start)/USECS_PER_MSEC; OctreeServer::trackLoopTime(elapsedmsec); - quint64 endCompressCalls = OctreePacketData::getCompressContentCalls(); - int elapsedCompressCalls = endCompressCalls - startCompressCalls; - - quint64 endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; - int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; - - bool wantsExtraDebugging = false; - if (wantsExtraDebugging) { - if (elapsedmsec > 100) { - if (elapsedmsec > 1000) { - int elapsedsec = (end - start)/1000000; - qDebug("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets %d nodes still to send", - elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } else { - qDebug("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets, %d nodes still to send", - elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } - } else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets, %d nodes still to send", - elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } - } + // TODO: add these to stats page + //quint64 endCompressCalls = OctreePacketData::getCompressContentCalls(); + //int elapsedCompressCalls = endCompressCalls - startCompressCalls; + //quint64 endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; + //int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; // if after sending packets we've emptied our bag, then we want to remember that we've sent all // the voxels from the current view frustum if (nodeData->nodeBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - nodeData->map.printStats(); - } nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d " - "server PPI=%d nodePPS=%d nodePPI=%d", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, - _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxOctreePacketsPerSecond(), - clientMaxPacketsPerInterval); - } - } // end if bag wasn't empty, and so we sent stuff... - const bool wantExtraDebugging = false; - if (wantExtraDebugging) { - if (truePacketsSent > 0 || packetsSentThisInterval > 0) { - qDebug() << "truePacketsSent=" << truePacketsSent << "packetsSentThisInterval=" << packetsSentThisInterval; - } - } - return truePacketsSent; } From dfb07e717db9686cad7177e478788a9a17ed0004 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 09:34:24 -0700 Subject: [PATCH 25/41] removed old debugging code --- .../src/octree/OctreeSendThread.cpp | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 132090f15d..6cd5d65340 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -56,9 +56,6 @@ bool OctreeSendThread::process() { // Sometimes the node data has not yet been linked, in which case we can't really do anything if (nodeData) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); - } packetDistributor(node, nodeData, viewFrustumChanged); } if (nodeData->isScheduledForDelete()) { @@ -68,10 +65,6 @@ bool OctreeSendThread::process() { } else { _nodeMissingCount++; } - } else { - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("OctreeSendThread::process() waiting for isInitialLoadComplete()"); - } } // Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap @@ -84,10 +77,6 @@ bool OctreeSendThread::process() { PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { - if ((_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug() << "Last send took too much time (" << (elapsed / USECS_PER_MSEC) - <<" msecs), barely sleeping 1 usec!\n"; - } const int MIN_USEC_TO_SLEEP = 1; usleep(MIN_USEC_TO_SLEEP); } @@ -270,49 +259,15 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue if (wantCompression) { targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d", __LINE__, - debug::valueOf(wantCompression), targetSize); - } - _packetData.changeSettings(wantCompression, targetSize); } - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s", - debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()), - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving())); - } - const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("packetDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s", - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()), - debug::valueOf(nodeData->getViewSent()) - ); - } - // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { quint64 now = usecTimestampNow(); - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...", - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty())); - if (nodeData->getLastTimeBagEmpty() > 0) { - float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f; - if (viewFrustumChanged) { - qDebug("viewFrustumChanged resetting after elapsed time to send scene = %f seconds", elapsedSceneSend); - } else { - qDebug("elapsed time to send scene = %f seconds", elapsedSceneSend); - } - qDebug("[ occlusionCulling:%s, wantDelta:%s, wantColor:%s ]", - debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta), - debug::valueOf(wantColor)); - } - } // if our view has changed, we need to reset these things... if (viewFrustumChanged) { @@ -375,12 +330,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND)); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), - nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval); - } - int extraPackingAttempts = 0; bool completedScene = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) { @@ -391,12 +340,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 startInside = usecTimestampNow(); - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), - nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval); - } - bool lastNodeDidntFit = false; // assume each node fits if (!nodeData->nodeBag.isEmpty()) { OctreeElement* subTree = nodeData->nodeBag.extract(); @@ -585,4 +528,3 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue return truePacketsSent; } - From 88fd686126eccb2afc62c97aeebf7b1fcd104d53 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 15:59:02 -0700 Subject: [PATCH 26/41] tweak thread tests --- tests/threads/src/SampleReadThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/threads/src/SampleReadThread.cpp b/tests/threads/src/SampleReadThread.cpp index 129c3f098b..79693dc791 100644 --- a/tests/threads/src/SampleReadThread.cpp +++ b/tests/threads/src/SampleReadThread.cpp @@ -43,7 +43,7 @@ bool SampleReadThread::process() { for(int i = 0; i < LOTS_OF_OPERATIONS; i++) { float x = rand(); float y = rand(); - float z = x * y; + y = x * y; } } quint64 endWork = usecTimestampNow(); From 220232312dc8cb7a45b6dc65732068b1d4f05fec Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 16:06:20 -0700 Subject: [PATCH 27/41] remove unused variables --- assignment-client/src/octree/OctreeSendThread.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 6cd5d65340..2490640952 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -227,8 +227,6 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node, OctreeQuer /// Version of voxel distributor that sends the deepest LOD level at once int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged) { - bool forceDebugging = false; - int truePacketsSent = 0; int trueBytesSent = 0; int packetsSentThisInterval = 0; @@ -267,7 +265,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { - quint64 now = usecTimestampNow(); // if our view has changed, we need to reset these things... if (viewFrustumChanged) { From 499c4bd500b40a9ae041ab9516d1ae7030774db4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 17:44:53 -0700 Subject: [PATCH 28/41] fix octree server crashes on various shutdown corner cases --- assignment-client/src/AssignmentClient.cpp | 13 +++++++---- .../src/octree/OctreeSendThread.cpp | 15 ++++++++++-- assignment-client/src/octree/OctreeServer.cpp | 23 ++++++++++++++++--- assignment-client/src/octree/OctreeServer.h | 3 +++ libraries/shared/src/ThreadedAssignment.cpp | 1 + libraries/shared/src/ThreadedAssignment.h | 9 +++++--- 6 files changed, 51 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 978f090ec2..e4db44eea4 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -194,21 +194,24 @@ void AssignmentClient::handleAuthenticationRequest() { } void AssignmentClient::assignmentCompleted() { +qDebug() << "START AssignmentClient::assignmentCompleted()... this=" << this << "_currentAssignment=" << _currentAssignment; + // reset the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); qDebug("Assignment finished or never started - waiting for new assignment."); NodeList* nodeList = NodeList::getInstance(); + + // reset our NodeList by switching back to unassigned and clearing the list + nodeList->reset(); + nodeList->setOwnerType(NodeType::Unassigned); + nodeList->resetNodeInterestSet(); // have us handle incoming NodeList datagrams again disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment, 0); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); +qDebug() << "DONE AssignmentClient::assignmentCompleted()... this=" << this << "_currentAssignment was=" << _currentAssignment; _currentAssignment = NULL; - - // reset our NodeList by switching back to unassigned and clearing the list - nodeList->setOwnerType(NodeType::Unassigned); - nodeList->reset(); - nodeList->resetNodeInterestSet(); } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 2490640952..83d4a6c082 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -23,12 +23,23 @@ OctreeSendThread::OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer _packetData(), _nodeMissingCount(0) { - qDebug() << "client connected - starting sending thread"; + QString safeServerName("Octree"); + if (_myServer) { + safeServerName = _myServer->getMyServerName(); + } + qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client connected " + "- starting sending thread [" << this << "]"; + OctreeServer::clientConnected(); } OctreeSendThread::~OctreeSendThread() { - qDebug() << "client disconnected - ending sending thread"; + QString safeServerName("Octree"); + if (_myServer) { + safeServerName = _myServer->getMyServerName(); + } + qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client disconnected " + "- ending sending thread [" << this << "]"; OctreeServer::clientDisconnected(); } diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 34b457a8f7..82839e06b3 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -195,9 +195,11 @@ OctreeServer::OctreeServer(const QByteArray& packet) : { _instance = this; _averageLoopTime.updateAverage(0); + qDebug() << "Octree server starting... [" << this << "]"; } OctreeServer::~OctreeServer() { + qDebug() << qPrintable(_safeServerName) << "server shutting down... [" << this << "]"; if (_parsedArgV) { for (int i = 0; i < _argc; i++) { delete[] _parsedArgV[i]; @@ -222,7 +224,7 @@ OctreeServer::~OctreeServer() { delete _jurisdiction; _jurisdiction = NULL; - qDebug() << "OctreeServer::~OctreeServer()... DONE"; + qDebug() << qPrintable(_safeServerName) << "server DONE shutting down... [" << this << "]"; } void OctreeServer::initHTTPManager(int port) { @@ -808,6 +810,7 @@ void OctreeServer::readPendingDatagrams() { } void OctreeServer::run() { + _safeServerName = getMyServerName(); // Before we do anything else, create our tree... _tree = createTree(); @@ -863,6 +866,7 @@ void OctreeServer::run() { connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer))); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer))); + // we need to ask the DS about agents so we can ping/reply with them nodeList->addNodeTypeToInterestSet(NodeType::Agent); @@ -984,13 +988,26 @@ void OctreeServer::run() { void OctreeServer::nodeAdded(SharedNodePointer node) { // we might choose to use this notifier to track clients in a pending state - qDebug() << "OctreeServer::nodeAdded() node:" << *node; + qDebug() << qPrintable(_safeServerName) << "server added node:" << *node; } void OctreeServer::nodeKilled(SharedNodePointer node) { + qDebug() << qPrintable(_safeServerName) << "server killed node:" << *node; OctreeQueryNode* nodeData = static_cast(node->getLinkedData()); if (nodeData) { - nodeData->scheduleForDelete(); + qDebug() << qPrintable(_safeServerName) << "server resetting Linked Data for node:" << *node; + node->setLinkedData(NULL); // set this first in case another thread comes through and tryes to acces this + qDebug() << qPrintable(_safeServerName) << "server deleting Linked Data for node:" << *node; + delete nodeData; } } +void OctreeServer::aboutToFinish() { + qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish..."; + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; + nodeKilled(node); + } + qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; +} + diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 44fca6f124..12091170d9 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -98,6 +98,8 @@ public: static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } bool handleHTTPRequest(HTTPConnection* connection, const QString& path); + + virtual void aboutToFinish(); public slots: /// runs the voxel server assignment @@ -134,6 +136,7 @@ protected: time_t _started; quint64 _startedUSecs; + QString _safeServerName; static int _clientCount; static SimpleMovingAverage _averageLoopTime; diff --git a/libraries/shared/src/ThreadedAssignment.cpp b/libraries/shared/src/ThreadedAssignment.cpp index e2d42883f6..c4282028ae 100644 --- a/libraries/shared/src/ThreadedAssignment.cpp +++ b/libraries/shared/src/ThreadedAssignment.cpp @@ -29,6 +29,7 @@ void ThreadedAssignment::setFinished(bool isFinished) { _isFinished = isFinished; if (_isFinished) { + aboutToFinish(); emit finished(); } } diff --git a/libraries/shared/src/ThreadedAssignment.h b/libraries/shared/src/ThreadedAssignment.h index 25489a8e25..a3cf2a1e31 100644 --- a/libraries/shared/src/ThreadedAssignment.h +++ b/libraries/shared/src/ThreadedAssignment.h @@ -9,21 +9,24 @@ #ifndef __hifi__ThreadedAssignment__ #define __hifi__ThreadedAssignment__ +#include + #include "Assignment.h" class ThreadedAssignment : public Assignment { Q_OBJECT public: ThreadedAssignment(const QByteArray& packet); - void setFinished(bool isFinished); + + virtual void aboutToFinish() { }; + public slots: /// threaded run of assignment virtual void run() = 0; - virtual void deleteLater(); - virtual void readPendingDatagrams() = 0; + protected: bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr); From 450a9c03a7e167659ad70fd67df674d29b655cfa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 23:54:23 -0700 Subject: [PATCH 29/41] revert changes --- assignment-client/src/AssignmentClient.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index e4db44eea4..970b6518ec 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -194,8 +194,6 @@ void AssignmentClient::handleAuthenticationRequest() { } void AssignmentClient::assignmentCompleted() { -qDebug() << "START AssignmentClient::assignmentCompleted()... this=" << this << "_currentAssignment=" << _currentAssignment; - // reset the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); @@ -203,15 +201,14 @@ qDebug() << "START AssignmentClient::assignmentCompleted()... this=" << this << NodeList* nodeList = NodeList::getInstance(); - // reset our NodeList by switching back to unassigned and clearing the list - nodeList->reset(); - nodeList->setOwnerType(NodeType::Unassigned); - nodeList->resetNodeInterestSet(); - // have us handle incoming NodeList datagrams again disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment, 0); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); -qDebug() << "DONE AssignmentClient::assignmentCompleted()... this=" << this << "_currentAssignment was=" << _currentAssignment; _currentAssignment = NULL; + + // reset our NodeList by switching back to unassigned and clearing the list + nodeList->setOwnerType(NodeType::Unassigned); + nodeList->reset(); + nodeList->resetNodeInterestSet(); } From b3f60a068d90a9b95a48471f3ab4b8bb2e63eb55 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 00:17:14 -0700 Subject: [PATCH 30/41] remove isScheduledForDelete from OctreeQueryNode --- assignment-client/src/octree/OctreeQueryNode.cpp | 1 - assignment-client/src/octree/OctreeQueryNode.h | 6 ------ assignment-client/src/octree/OctreeSendThread.cpp | 4 ---- 3 files changed, 11 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cf57c4f1b5..a1922f980d 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -36,7 +36,6 @@ OctreeQueryNode::OctreeQueryNode() : _lodChanged(false), _lodInitialized(false), _sequenceNumber(0), - _scheduleForDelete(false), _lastRootTimestamp(0) { } diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 6f17117ca2..20fa2c5858 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -86,9 +86,6 @@ public: void dumpOutOfView(); - bool isScheduledForDelete() const { return _scheduleForDelete; } - void scheduleForDelete() { _scheduleForDelete = true; } - quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } void setLastRootTimestamp(quint64 timestamp) { _lastRootTimestamp = timestamp; } unsigned int getlastOctreePacketLength() const { return _lastOctreePacketLength; } @@ -129,9 +126,6 @@ private: bool _lodInitialized; OCTREE_PACKET_SEQUENCE _sequenceNumber; - - bool _scheduleForDelete; - quint64 _lastRootTimestamp; }; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 83d4a6c082..caa729e340 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -69,10 +69,6 @@ bool OctreeSendThread::process() { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); packetDistributor(node, nodeData, viewFrustumChanged); } - if (nodeData->isScheduledForDelete()) { - nodeData->deleteLater(); - node->setLinkedData(NULL); - } } else { _nodeMissingCount++; } From 584adfda0851eb40ee2e96d04f03bc2b8faf70f2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 00:32:38 -0700 Subject: [PATCH 31/41] cleanup headers --- libraries/shared/src/ThreadedAssignment.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/shared/src/ThreadedAssignment.h b/libraries/shared/src/ThreadedAssignment.h index a3cf2a1e31..d3502e9c4d 100644 --- a/libraries/shared/src/ThreadedAssignment.h +++ b/libraries/shared/src/ThreadedAssignment.h @@ -9,8 +9,6 @@ #ifndef __hifi__ThreadedAssignment__ #define __hifi__ThreadedAssignment__ -#include - #include "Assignment.h" class ThreadedAssignment : public Assignment { @@ -18,7 +16,6 @@ class ThreadedAssignment : public Assignment { public: ThreadedAssignment(const QByteArray& packet); void setFinished(bool isFinished); - virtual void aboutToFinish() { }; public slots: @@ -29,7 +26,6 @@ public slots: protected: bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr); - void commonInit(const QString& targetName, NodeType_t nodeType); bool _isFinished; private slots: From 80ea33bf020a65ba1f5fa9cc298d57a8c2965100 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 00:37:43 -0700 Subject: [PATCH 32/41] removed test code --- tests/threads/CMakeLists.txt | 36 ------------ tests/threads/src/SampleReadThread.cpp | 65 ---------------------- tests/threads/src/SampleReadThread.h | 31 ----------- tests/threads/src/SampleWriteThread.cpp | 47 ---------------- tests/threads/src/SampleWriteThread.h | 30 ---------- tests/threads/src/SharedResource.cpp | 38 ------------- tests/threads/src/SharedResource.h | 40 -------------- tests/threads/src/ThreadsTests.cpp | 73 ------------------------- tests/threads/src/ThreadsTests.h | 16 ------ tests/threads/src/main.cpp | 11 ---- 10 files changed, 387 deletions(-) delete mode 100644 tests/threads/CMakeLists.txt delete mode 100644 tests/threads/src/SampleReadThread.cpp delete mode 100644 tests/threads/src/SampleReadThread.h delete mode 100644 tests/threads/src/SampleWriteThread.cpp delete mode 100644 tests/threads/src/SampleWriteThread.h delete mode 100644 tests/threads/src/SharedResource.cpp delete mode 100644 tests/threads/src/SharedResource.h delete mode 100644 tests/threads/src/ThreadsTests.cpp delete mode 100644 tests/threads/src/ThreadsTests.h delete mode 100644 tests/threads/src/main.cpp diff --git a/tests/threads/CMakeLists.txt b/tests/threads/CMakeLists.txt deleted file mode 100644 index f12a124b0c..0000000000 --- a/tests/threads/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -if (WIN32) - cmake_policy (SET CMP0020 NEW) -endif (WIN32) - -set(TARGET_NAME threads-tests) - -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -find_package(Qt5Core REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME} TRUE) - -include(${MACRO_DIR}/AutoMTC.cmake) -auto_mtc(${TARGET_NAME} ${ROOT_DIR}) - -qt5_use_modules(${TARGET_NAME} Core) - -#include glm -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - -# link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -IF (WIN32) - #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - diff --git a/tests/threads/src/SampleReadThread.cpp b/tests/threads/src/SampleReadThread.cpp deleted file mode 100644 index 79693dc791..0000000000 --- a/tests/threads/src/SampleReadThread.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// -// SampleReadThread.cpp -// interface -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. -// - -#include - -#include - -#include "SharedResource.h" -#include "SampleReadThread.h" - -SampleReadThread::SampleReadThread(SharedResource* theResource, int id) : - _theResource(theResource), - _myID(id) { -} - -bool SampleReadThread::process() { - const quint64 FRAME_RATE = 60; - const quint64 USECS_PER_FRAME = USECS_PER_SECOND / FRAME_RATE; // every 60fps - - quint64 start = usecTimestampNow(); - _theResource->lockForRead(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - - int theValue = _theResource->getValue(); - - bool wantDebugging = true; - if (wantDebugging) { - qDebug() << "SampleReadThread::process()... _myID=" << _myID << "lockForRead() took" << elapsed << "usecs" << - " _theResource->getValue()=" << theValue; - } - - quint64 startWork = usecTimestampNow(); - { - const int LOTS_OF_OPERATIONS = 100000; - for(int i = 0; i < LOTS_OF_OPERATIONS; i++) { - float x = rand(); - float y = rand(); - y = x * y; - } - } - quint64 endWork = usecTimestampNow(); - quint64 elapsedWork = endWork - startWork; - qDebug() << "SampleReadThread::process()... _myID=" << _myID << " work took" << elapsedWork << "usecs"; - - _theResource->unlock(); - - - if (isStillRunning()) { - if (elapsed < USECS_PER_FRAME) { - quint64 sleepFor = USECS_PER_FRAME - elapsed; - usleep(sleepFor); - } else { - usleep(5); // sleep at least a little - } - } - return isStillRunning(); // keep running till they terminate us -} diff --git a/tests/threads/src/SampleReadThread.h b/tests/threads/src/SampleReadThread.h deleted file mode 100644 index a9a25ac7a1..0000000000 --- a/tests/threads/src/SampleReadThread.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// SampleReadThread.h -// tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__SampleReadThread__ -#define __interface__SampleReadThread__ - -#include - -class SharedResource; - -/// Generalized threaded processor for handling received inbound packets. -class SampleReadThread : public GenericThread { - Q_OBJECT -public: - SampleReadThread(SharedResource* theResource, int id); - -protected: - /// Implements generic processing behavior for this thread. - virtual bool process(); - -private: - SharedResource* _theResource; - int _myID; -}; - -#endif // __interface__SampleReadThread__ diff --git a/tests/threads/src/SampleWriteThread.cpp b/tests/threads/src/SampleWriteThread.cpp deleted file mode 100644 index 0fbe68904d..0000000000 --- a/tests/threads/src/SampleWriteThread.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// -// SampleWriteThread.cpp -// interface -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. -// - -#include - -#include - -#include "SharedResource.h" -#include "SampleWriteThread.h" - -SampleWriteThread::SampleWriteThread(SharedResource* theResource) : - _theResource(theResource) { -} - -bool SampleWriteThread::process() { - const quint64 USECS_PER_OPERATION = USECS_PER_SECOND * 1; // once every second. - - quint64 start = usecTimestampNow(); - _theResource->lockForWrite(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - - int theValue = _theResource->incrementValue(); - - bool wantDebugging = false; - if (wantDebugging) { - qDebug() << "SampleWriteThread::process()... lockForWrite() took" << elapsed << "usecs" << - " _theResource->incrementValue()=" << theValue; - } - _theResource->unlock(); - - - if (isStillRunning()) { - if (elapsed < USECS_PER_OPERATION) { - quint64 sleepFor = USECS_PER_OPERATION - elapsed; - usleep(sleepFor); - } - } - return isStillRunning(); // keep running till they terminate us -} diff --git a/tests/threads/src/SampleWriteThread.h b/tests/threads/src/SampleWriteThread.h deleted file mode 100644 index 970b4435a9..0000000000 --- a/tests/threads/src/SampleWriteThread.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// SampleWriteThread.h -// tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__SampleWriteThread__ -#define __interface__SampleWriteThread__ - -#include - -class SharedResource; - -/// Generalized threaded processor for handling received inbound packets. -class SampleWriteThread : public GenericThread { - Q_OBJECT -public: - SampleWriteThread(SharedResource* theResource); - -protected: - /// Implements generic processing behavior for this thread. - virtual bool process(); - -private: - SharedResource* _theResource; -}; - -#endif // __interface__SampleWriteThread__ diff --git a/tests/threads/src/SharedResource.cpp b/tests/threads/src/SharedResource.cpp deleted file mode 100644 index c397e6a7db..0000000000 --- a/tests/threads/src/SharedResource.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// SharedResource.cpp -// tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include - -#include "SharedResource.h" - -const int MOVING_AVERAGE_SAMPLES = 10000; - -SharedResource::SharedResource() : - _value(0), - _lockAverage(MOVING_AVERAGE_SAMPLES), - _lockForReadAverage(MOVING_AVERAGE_SAMPLES), - _lockForWriteAverage(MOVING_AVERAGE_SAMPLES) -{ -}; - -void SharedResource::lockForRead() { - quint64 start = usecTimestampNow(); - _lock.lockForRead(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - _lockForReadAverage.updateAverage(elapsed); - _lockAverage.updateAverage(elapsed); -} -void SharedResource::lockForWrite() { - quint64 start = usecTimestampNow(); - _lock.lockForWrite(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - _lockForWriteAverage.updateAverage(elapsed); - _lockAverage.updateAverage(elapsed); -} diff --git a/tests/threads/src/SharedResource.h b/tests/threads/src/SharedResource.h deleted file mode 100644 index 1426471f16..0000000000 --- a/tests/threads/src/SharedResource.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// SharedResource.h -// tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__SharedResource__ -#define __interface__SharedResource__ - -#include - -#include - -/// Generalized threaded processor for handling received inbound packets. -class SharedResource { -public: - SharedResource(); - - void lockForRead(); - void lockForWrite(); - void unlock() { _lock.unlock(); } - - int getValue() const { return _value; } - int incrementValue() { return ++_value; } - - float getAverageLockTime() const { return _lockAverage.getAverage(); } - float getAverageLockForReadTime() const { return _lockForReadAverage.getAverage(); } - float getAverageLockForWriteTime() const { return _lockForWriteAverage.getAverage(); } - -private: - QReadWriteLock _lock; - int _value; - SimpleMovingAverage _lockAverage; - SimpleMovingAverage _lockForReadAverage; - SimpleMovingAverage _lockForWriteAverage; -}; - -#endif // __interface__SharedResource__ diff --git a/tests/threads/src/ThreadsTests.cpp b/tests/threads/src/ThreadsTests.cpp deleted file mode 100644 index 15b1c66e63..0000000000 --- a/tests/threads/src/ThreadsTests.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// ThreadsTests.cpp -// thread-tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. -// - -#include -#include - -#include -#include - -#include "SampleReadThread.h" -#include "SampleWriteThread.h" -#include "SharedResource.h" -#include "ThreadsTests.h" - - -void ThreadsTests::runAllTests() { - qDebug() << "START ThreadsTests::runAllTests()"; - - const quint64 TOTAL_RUN_TIME = USECS_PER_SECOND * 10; // run for 2 minutes - const quint64 MAIN_THREAD_SLEEP = USECS_PER_SECOND * 0.25; // main thread checks in every 1/4 second - quint64 start = usecTimestampNow(); - quint64 now = usecTimestampNow(); - - SharedResource resource; - - const int NUMBER_OF_READERS = 125; // + 3 = 128, Max number of QThreads on the mac. - QVector readThreads; - for(int i = 0; i < NUMBER_OF_READERS; i++) { - SampleReadThread* newReader = new SampleReadThread(&resource, i); - newReader->initialize(); - readThreads.append(newReader); - } - - SampleWriteThread write(&resource); - write.initialize(); - - while(now - start < TOTAL_RUN_TIME) { - float elapsed = (float)(now - start) / (float)USECS_PER_SECOND; - qDebug() << "Main thread still running... elapsed:" << elapsed << "seconds"; - qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs"; - qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs"; - qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs"; - qDebug() << " resource.value:" << resource.getValue(); - - - usleep(MAIN_THREAD_SLEEP); - now = usecTimestampNow(); - } - write.terminate(); - - foreach(SampleReadThread* readThread, readThreads) { - readThread->terminate(); - delete readThread; - } - readThreads.clear(); - - qDebug() << "DONE running..."; - qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs"; - qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs"; - qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs"; - qDebug() << " resource.value:" << resource.getValue(); - - qDebug() << "END ThreadsTests::runAllTests()"; - - qDebug() << "_POSIX_THREAD_THREADS_MAX" << _POSIX_THREAD_THREADS_MAX; - qDebug() << "QThread::idealThreadCount()" << QThread::idealThreadCount(); - -} diff --git a/tests/threads/src/ThreadsTests.h b/tests/threads/src/ThreadsTests.h deleted file mode 100644 index 29bd9aebd4..0000000000 --- a/tests/threads/src/ThreadsTests.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// ThreadsTests.h -// threads-tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. -// - -#ifndef __tests__ThreadsTests__ -#define __tests__ThreadsTests__ - -namespace ThreadsTests { - void runAllTests(); -} - -#endif // __tests__ThreadsTests__ diff --git a/tests/threads/src/main.cpp b/tests/threads/src/main.cpp deleted file mode 100644 index 16f3ea0900..0000000000 --- a/tests/threads/src/main.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// -// main.cpp -// threads-tests -// - -#include "ThreadsTests.h" - -int main(int argc, char** argv) { - ThreadsTests::runAllTests(); - return 0; -} From cd6e0f16982b65d9b9532956a0d3ad73d8a58431 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 01:02:49 -0700 Subject: [PATCH 33/41] switch to deleteLater to prevent deadlock --- assignment-client/src/octree/OctreeServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 82839e06b3..7e6ffe52da 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -998,7 +998,7 @@ void OctreeServer::nodeKilled(SharedNodePointer node) { qDebug() << qPrintable(_safeServerName) << "server resetting Linked Data for node:" << *node; node->setLinkedData(NULL); // set this first in case another thread comes through and tryes to acces this qDebug() << qPrintable(_safeServerName) << "server deleting Linked Data for node:" << *node; - delete nodeData; + nodeData->deleteLater(); } } From 7c45df002a11f78d93683c2c9b34a2d39b198c6b Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 19 Mar 2014 07:41:36 -0700 Subject: [PATCH 34/41] increased head smoothing for visage --- interface/resources/visage/tracker.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/visage/tracker.cfg b/interface/resources/visage/tracker.cfg index b5ed3302fa..10744da6e5 100644 --- a/interface/resources/visage/tracker.cfg +++ b/interface/resources/visage/tracker.cfg @@ -40,7 +40,7 @@ detect_strip_roi_width 2 detect_strip_roi_height 4 smoothing_factors - 150 15 -2 100 -1 50 50 0 + 150 5 -2 100 -1 50 50 0 #translation rotation action_units eyebrows mouth gaze eye_closure other process_eyes 1 From 252bc3b3eee61ee52b099694234b1cae1b096b76 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 11:51:47 -0700 Subject: [PATCH 35/41] optimized ViewFrustum::getFurthestPointFromCamera() --- libraries/octree/src/OctreeElement.cpp | 7 ++++--- libraries/octree/src/ViewFrustum.cpp | 25 +++++++++---------------- libraries/octree/src/ViewFrustum.h | 5 +++-- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 72ac5b14d6..3f31ad928a 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1222,10 +1222,11 @@ bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float float OctreeElement::furthestDistanceToCamera(const ViewFrustum& viewFrustum) const { AABox box = getAABox(); box.scale(TREE_SCALE); - glm::vec3 furthestPoint = viewFrustum.getFurthestPointFromCamera(box); + glm::vec3 furthestPoint; + viewFrustum.getFurthestPointFromCamera(box, furthestPoint); glm::vec3 temp = viewFrustum.getPosition() - furthestPoint; - float distanceToVoxelCenter = sqrtf(glm::dot(temp, temp)); - return distanceToVoxelCenter; + float distanceToFurthestPoint = sqrtf(glm::dot(temp, temp)); + return distanceToFurthestPoint; } float OctreeElement::distanceToCamera(const ViewFrustum& viewFrustum) const { diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 66f1445ddc..00caafa095 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -695,39 +695,32 @@ OctreeProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const return projectedPolygon; } - // Similar strategy to getProjectedPolygon() we use the knowledge of camera position relative to the // axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for // squares and square-roots. Just compares. -glm::vec3 ViewFrustum::getFurthestPointFromCamera(const AABox& box) const { +void ViewFrustum::getFurthestPointFromCamera(const AABox& box, glm::vec3& furthestPoint) const { const glm::vec3& bottomNearRight = box.getCorner(); - glm::vec3 center = box.calcCenter(); - glm::vec3 topFarLeft = box.calcTopFarLeft(); + float scale = box.getScale(); + float halfScale = scale * 0.5f; - glm::vec3 furthestPoint; - if (_position.x < center.x) { + if (_position.x < bottomNearRight.x + halfScale) { // we are to the right of the center, so the left edge is furthest - furthestPoint.x = topFarLeft.x; + furthestPoint.x = bottomNearRight.x + scale; } else { - // we are to the left of the center, so the right edge is furthest (at center ok too) furthestPoint.x = bottomNearRight.x; } - if (_position.y < center.y) { + if (_position.y < bottomNearRight.y + halfScale) { // we are below of the center, so the top edge is furthest - furthestPoint.y = topFarLeft.y; + furthestPoint.y = bottomNearRight.y + scale; } else { - // we are above the center, so the lower edge is furthest (at center ok too) furthestPoint.y = bottomNearRight.y; } - if (_position.z < center.z) { + if (_position.z < bottomNearRight.z + halfScale) { // we are to the near side of the center, so the far side edge is furthest - furthestPoint.z = topFarLeft.z; + furthestPoint.z = bottomNearRight.z + scale; } else { - // we are to the far side of the center, so the near side edge is furthest (at center ok too) furthestPoint.z = bottomNearRight.z; } - - return furthestPoint; } diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index da4a6997f1..f841566652 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -102,8 +102,9 @@ public: glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const; OctreeProjectedPolygon getProjectedPolygon(const AABox& box) const; - glm::vec3 getFurthestPointFromCamera(const AABox& box) const; - + //glm::vec3 getFurthestPointFromCamera(const AABox& box) const; + void getFurthestPointFromCamera(const AABox& box, glm::vec3& furthestPoint) const; + private: // Used for keyhole calculations ViewFrustum::location pointInKeyhole(const glm::vec3& point) const; From f3bd8925d91f46d63d4af17ed32f4545febed259 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 12:48:11 -0700 Subject: [PATCH 36/41] optimized OctreeElement::furthestDistanceToCamera() --- libraries/octree/src/OctreeElement.cpp | 9 ++++---- libraries/octree/src/ViewFrustum.cpp | 29 ++++++++++++++++++++++++++ libraries/octree/src/ViewFrustum.h | 10 ++++++--- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 3f31ad928a..4d1630135c 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1219,14 +1219,13 @@ bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float } // Calculates the distance to the furthest point of the voxel to the camera +// does as much math as possible in voxel scale and then scales up to TREE_SCALE at end float OctreeElement::furthestDistanceToCamera(const ViewFrustum& viewFrustum) const { - AABox box = getAABox(); - box.scale(TREE_SCALE); glm::vec3 furthestPoint; - viewFrustum.getFurthestPointFromCamera(box, furthestPoint); - glm::vec3 temp = viewFrustum.getPosition() - furthestPoint; + viewFrustum.getFurthestPointFromCameraVoxelScale(getAABox(), furthestPoint); + glm::vec3 temp = viewFrustum.getPositionVoxelScale() - furthestPoint; float distanceToFurthestPoint = sqrtf(glm::dot(temp, temp)); - return distanceToFurthestPoint; + return distanceToFurthestPoint * (float)TREE_SCALE; } float OctreeElement::distanceToCamera(const ViewFrustum& viewFrustum) const { diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 00caafa095..da03aad697 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -25,6 +25,7 @@ using namespace std; ViewFrustum::ViewFrustum() : _position(0,0,0), + _positionVoxelScale(0,0,0), _orientation(), _direction(IDENTITY_FRONT), _up(IDENTITY_UP), @@ -724,3 +725,31 @@ void ViewFrustum::getFurthestPointFromCamera(const AABox& box, glm::vec3& furthe furthestPoint.z = bottomNearRight.z; } } + +void ViewFrustum::getFurthestPointFromCameraVoxelScale(const AABox& box, glm::vec3& furthestPoint) const { + const glm::vec3& bottomNearRight = box.getCorner(); + float scale = box.getScale(); + float halfScale = scale * 0.5f; + + if (_positionVoxelScale.x < bottomNearRight.x + halfScale) { + // we are to the right of the center, so the left edge is furthest + furthestPoint.x = bottomNearRight.x + scale; + } else { + furthestPoint.x = bottomNearRight.x; + } + + if (_positionVoxelScale.y < bottomNearRight.y + halfScale) { + // we are below of the center, so the top edge is furthest + furthestPoint.y = bottomNearRight.y + scale; + } else { + furthestPoint.y = bottomNearRight.y; + } + + if (_positionVoxelScale.z < bottomNearRight.z + halfScale) { + // we are to the near side of the center, so the far side edge is furthest + furthestPoint.z = bottomNearRight.z + scale; + } else { + furthestPoint.z = bottomNearRight.z; + } +} + diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index f841566652..a0b3a851aa 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -29,11 +29,12 @@ const float DEFAULT_FAR_CLIP = 50.0f * TREE_SCALE; class ViewFrustum { public: // setters for camera attributes - void setPosition(const glm::vec3& p) { _position = p; } + void setPosition(const glm::vec3& p) { _position = p; _positionVoxelScale = (p / (float)TREE_SCALE); } void setOrientation(const glm::quat& orientationAsQuaternion); // getters for camera attributes const glm::vec3& getPosition() const { return _position; } + const glm::vec3& getPositionVoxelScale() const { return _positionVoxelScale; } const glm::quat& getOrientation() const { return _orientation; } const glm::vec3& getDirection() const { return _direction; } const glm::vec3& getUp() const { return _up; } @@ -102,9 +103,11 @@ public: glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const; OctreeProjectedPolygon getProjectedPolygon(const AABox& box) const; - //glm::vec3 getFurthestPointFromCamera(const AABox& box) const; void getFurthestPointFromCamera(const AABox& box, glm::vec3& furthestPoint) const; + // assumes box is in voxel scale, not TREE_SCALE, will scale view frustum's position accordingly + void getFurthestPointFromCameraVoxelScale(const AABox& box, glm::vec3& furthestPoint) const; + private: // Used for keyhole calculations ViewFrustum::location pointInKeyhole(const glm::vec3& point) const; @@ -112,7 +115,8 @@ private: ViewFrustum::location boxInKeyhole(const AABox& box) const; // camera location/orientation attributes - glm::vec3 _position; + glm::vec3 _position; // the position in TREE_SCALE + glm::vec3 _positionVoxelScale; // the position in voxel scale glm::quat _orientation; // calculated for orientation From adaa01c13e362ec2b21d287b042c82cc9299067d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 13:15:28 -0700 Subject: [PATCH 37/41] optimize isLeaf() to just check the child mask instead of counting children --- libraries/octree/src/OctreeElement.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 1785307696..cbdad959be 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -126,7 +126,7 @@ public: float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this. float distanceToPoint(const glm::vec3& point) const; - bool isLeaf() const { return getChildCount() == 0; } + bool isLeaf() const { return _childBitmask == 0; } int getChildCount() const { return numberOfOnes(_childBitmask); } void printDebugDetails(const char* label) const; bool isDirty() const { return _isDirty; } From 3d0207b926751cb280a56ef2e159e54b2e58d54e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 13:54:06 -0700 Subject: [PATCH 38/41] optimize OctreeElement::calculateShouldRender() --- libraries/octree/src/OctreeElement.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 4d1630135c..bdf396a656 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1209,11 +1209,15 @@ bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float bool shouldRender = false; if (hasContent()) { float furthestDistance = furthestDistanceToCamera(*viewFrustum); - float boundary = boundaryDistanceForRenderLevel(getLevel() + boundaryLevelAdjust, voxelScaleSize); - float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); - bool inBoundary = (furthestDistance <= boundary); - bool inChildBoundary = (furthestDistance <= childBoundary); - shouldRender = (isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary); + float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); + bool inChildBoundary = (furthestDistance <= childBoundary); + if (isLeaf() && inChildBoundary) { + shouldRender = true; + } else { + float boundary = childBoundary * 2.0f; // the boundary is always twice the distance of the child boundary + bool inBoundary = (furthestDistance <= boundary); + shouldRender = inBoundary && !inChildBoundary; + } } return shouldRender; } From 5f94e44cde18e3c48bc301438e1fadd73a2db520 Mon Sep 17 00:00:00 2001 From: Tony Hagale Date: Wed, 19 Mar 2014 16:26:45 -0500 Subject: [PATCH 39/41] #2386 trying a new static lookup table for numberOfOnes() --- libraries/shared/src/SharedUtil.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index e5aded2798..00810653c1 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -130,14 +130,22 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) { } int numberOfOnes(unsigned char byte) { - return (byte >> 7) - + ((byte >> 6) & 1) - + ((byte >> 5) & 1) - + ((byte >> 4) & 1) - + ((byte >> 3) & 1) - + ((byte >> 2) & 1) - + ((byte >> 1) & 1) - + (byte & 1); + + static const unsigned char nbits[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3, + 4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4, + 4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2, + 3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5, + 4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3, + 4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3, + 3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5, + 6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6, + 4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5, + 6,5,6,6,7,5,6,6,7,6,7,7,8 + }; + + return nbits[(unsigned char) byte]; + } bool oneAtBit(unsigned char byte, int bitIndex) { From 7f2a92d759786e1bf1b8ad5eb43f14a45722596a Mon Sep 17 00:00:00 2001 From: Tony Hagale Date: Wed, 19 Mar 2014 16:28:12 -0500 Subject: [PATCH 40/41] #2386 trying a new static lookup table for numberOfOnes() --- libraries/shared/src/SharedUtil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 00810653c1..882d4719c8 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -131,7 +131,7 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) { int numberOfOnes(unsigned char byte) { - static const unsigned char nbits[256] = { + static const int nbits[256] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3, 4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4, 4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2, From f3968679d3474275c6914cb618062fbf045391d2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 15:44:18 -0700 Subject: [PATCH 41/41] cleanup isInView() to use inFrustum() directly --- libraries/octree/src/OctreeElement.cpp | 7 ------- libraries/octree/src/OctreeElement.h | 4 +--- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index bdf396a656..cdc4f419c0 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1183,13 +1183,6 @@ float OctreeElement::getEnclosingRadius() const { return getScale() * sqrtf(3.0f) / 2.0f; } -bool OctreeElement::isInView(const ViewFrustum& viewFrustum) const { - AABox box = _box; // use temporary box so we can scale it - box.scale(TREE_SCALE); - bool inView = (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(box)); - return inView; -} - ViewFrustum::location OctreeElement::inFrustum(const ViewFrustum& viewFrustum) const { AABox box = _box; // use temporary box so we can scale it box.scale(TREE_SCALE); diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index cbdad959be..ca2fa0b540 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -112,9 +112,7 @@ public: int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; } float getEnclosingRadius() const; - - - bool isInView(const ViewFrustum& viewFrustum) const; + bool isInView(const ViewFrustum& viewFrustum) const { return inFrustum(viewFrustum) != ViewFrustum::OUTSIDE; } ViewFrustum::location inFrustum(const ViewFrustum& viewFrustum) const; float distanceToCamera(const ViewFrustum& viewFrustum) const; float furthestDistanceToCamera(const ViewFrustum& viewFrustum) const;