diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 1167ef8b46..d5667d6249 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -108,35 +108,75 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { const struct mg_request_info* ri = mg_get_request_info(connection); if (strcmp(ri->uri, "/") == 0 && strcmp(ri->request_method, "GET") == 0) { + uint64_t checkSum; // return a 200 mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n"); mg_printf(connection, "%s", "Your Voxel Server is running.\r\n"); mg_printf(connection, "%s", "Current Statistics\r\n"); mg_printf(connection, "%s", "\r\n"); - mg_printf(connection, "Voxel Node Memory Usage: %8.2f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f); - mg_printf(connection, "Octcode Memory Usage: %8.2f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f); - mg_printf(connection, "External Children Memory Usage: %8.2f MB\r\n", - VoxelNode::getExternalChildrenMemoryUsage() / 1000000.f); + + const char* memoryScaleLabel; + const float MEGABYTES = 1000000.f; + const float GIGABYTES = 1000000000.f; + float memoryScale; + if (VoxelNode::getTotalMemoryUsage() / MEGABYTES < 1000.0f) { + memoryScaleLabel = "MB"; + memoryScale = MEGABYTES; + } else { + memoryScaleLabel = "GB"; + memoryScale = GIGABYTES; + } + + mg_printf(connection, "Voxel Node Memory Usage: %8.2f %s\r\n", + VoxelNode::getVoxelMemoryUsage() / memoryScale, memoryScaleLabel); + mg_printf(connection, "Octcode Memory Usage: %8.2f %s\r\n", + VoxelNode::getOctcodeMemoryUsage() / memoryScale, memoryScaleLabel); + mg_printf(connection, "External Children Memory Usage: %8.2f %s\r\n", + VoxelNode::getExternalChildrenMemoryUsage() / memoryScale, memoryScaleLabel); mg_printf(connection, "%s", " -----------\r\n"); - mg_printf(connection, " Total: %8.2f MB\r\n", VoxelNode::getTotalMemoryUsage() / 1000000.f); + mg_printf(connection, " Total: %8.2f %s\r\n", + VoxelNode::getTotalMemoryUsage() / memoryScale, memoryScaleLabel); + + mg_printf(connection, "\r\nVoxelNode size... %ld bytes\r\n", sizeof(VoxelNode)); unsigned long nodeCount = VoxelNode::getNodeCount(); unsigned long internalNodeCount = VoxelNode::getInternalNodeCount(); unsigned long leafNodeCount = VoxelNode::getLeafNodeCount(); + + + QLocale locale(QLocale::English); const float AS_PERCENT = 100.0; mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "Current Nodes in scene\r\n"); - mg_printf(connection, " Total Nodes: %10.lu nodes\r\n", nodeCount); - mg_printf(connection, " Internal Nodes: %10.lu nodes (%5.2f%%)\r\n", - internalNodeCount, ((float)internalNodeCount/(float)nodeCount) * AS_PERCENT); - mg_printf(connection, " Leaf Nodes: %10.lu nodes (%5.2f%%)\r\n", - leafNodeCount, ((float)leafNodeCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, " Total Nodes: %s nodes\r\n", + locale.toString((uint)nodeCount).rightJustified(16, ' ').toLocal8Bit().constData()); + mg_printf(connection, " Internal Nodes: %s nodes (%5.2f%%)\r\n", + locale.toString((uint)internalNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(), + ((float)internalNodeCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, " Leaf Nodes: %s nodes (%5.2f%%)\r\n", + locale.toString((uint)leafNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(), + ((float)leafNodeCount/(float)nodeCount) * AS_PERCENT); + mg_printf(connection, "%s", "\r\n"); + mg_printf(connection, "%s", "VoxelNode Children Population Statistics...\r\n"); + checkSum = 0; + for (int i=0; i <= NUMBER_OF_CHILDREN; i++) { + checkSum += VoxelNode::getChildrenCount(i); + mg_printf(connection, " Nodes with %d children: %s nodes (%5.2f%%)\r\n", i, + locale.toString((uint)VoxelNode::getChildrenCount(i)).rightJustified(16, ' ').toLocal8Bit().constData(), + ((float)VoxelNode::getChildrenCount(i)/(float)nodeCount) * AS_PERCENT); + } + mg_printf(connection, "%s", " ----------------------\r\n"); + mg_printf(connection, " Total: %s nodes\r\n", + locale.toString((uint)checkSum).rightJustified(16, ' ').toLocal8Bit().constData()); + +#ifdef BLENDED_UNION_CHILDREN mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "VoxelNode Children Encoding Statistics...\r\n"); - mg_printf(connection, " Single or No Children: %10.llu nodes (%5.2f%%)\r\n", + + mg_printf(connection, " Single or No Children: %10.llu nodes (%5.2f%%)\r\n", VoxelNode::getSingleChildrenCount(), ((float)VoxelNode::getSingleChildrenCount()/(float)nodeCount) * AS_PERCENT); mg_printf(connection, " Two Children as Offset: %10.llu nodes (%5.2f%%)\r\n", VoxelNode::getTwoChildrenOffsetCount(), @@ -150,11 +190,11 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, " Three Children as External: %10.llu nodes (%5.2f%%)\r\n", VoxelNode::getThreeChildrenExternalCount(), ((float)VoxelNode::getThreeChildrenExternalCount()/(float)nodeCount) * AS_PERCENT); - mg_printf(connection, " Children as External Array: %10.llu nodes (%5.2f%%)\r\n", + mg_printf(connection, " Children as External Array: %10.llu nodes (%5.2f%%)\r\n", VoxelNode::getExternalChildrenCount(), ((float)VoxelNode::getExternalChildrenCount()/(float)nodeCount) * AS_PERCENT); - uint64_t checkSum = VoxelNode::getSingleChildrenCount() + + checkSum = VoxelNode::getSingleChildrenCount() + VoxelNode::getTwoChildrenOffsetCount() + VoxelNode::getTwoChildrenExternalCount() + VoxelNode::getThreeChildrenOffsetCount() + VoxelNode::getThreeChildrenExternalCount() + VoxelNode::getExternalChildrenCount(); @@ -162,17 +202,6 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", " ----------------\r\n"); mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); mg_printf(connection, " Expected: %10.lu nodes\r\n", nodeCount); - - mg_printf(connection, "%s", "\r\n"); - mg_printf(connection, "%s", "VoxelNode Children Population Statistics...\r\n"); - checkSum = 0; - for (int i=0; i <= NUMBER_OF_CHILDREN; i++) { - checkSum += VoxelNode::getChildrenCount(i); - mg_printf(connection, " Nodes with %d children: %10.llu nodes (%5.2f%%)\r\n", i, - VoxelNode::getChildrenCount(i), ((float)VoxelNode::getChildrenCount(i)/(float)nodeCount) * AS_PERCENT); - } - mg_printf(connection, "%s", " ----------------\r\n"); - mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum); mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "In other news....\r\n"); @@ -180,6 +209,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { VoxelNode::getCouldStoreFourChildrenInternally()); mg_printf(connection, "could NOT store 4 children internally: %10.llu nodes\r\n", VoxelNode::getCouldNotStoreFourChildrenInternally()); +#endif return 1; } else { diff --git a/libraries/voxels/src/JurisdictionSender.cpp b/libraries/voxels/src/JurisdictionSender.cpp index 150d04440f..d00d09b9e9 100644 --- a/libraries/voxels/src/JurisdictionSender.cpp +++ b/libraries/voxels/src/JurisdictionSender.cpp @@ -21,16 +21,22 @@ JurisdictionSender::JurisdictionSender(JurisdictionMap* map, PacketSenderNotify* ReceivedPacketProcessor(), _jurisdictionMap(map) { + pthread_mutex_init(&_requestingNodeMutex, 0); } +JurisdictionSender::~JurisdictionSender() { + pthread_mutex_destroy(&_requestingNodeMutex); +} + + void JurisdictionSender::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); if (node) { QUuid nodeUUID = node->getUUID(); - lock(); + lockRequestingNodes(); _nodesRequestingJurisdictions.insert(nodeUUID); - unlock(); + unlockRequestingNodes(); } } } @@ -52,6 +58,7 @@ bool JurisdictionSender::process() { } int nodeCount = 0; + lockRequestingNodes(); for (std::set::iterator nodeIterator = _nodesRequestingJurisdictions.begin(); nodeIterator != _nodesRequestingJurisdictions.end(); nodeIterator++) { @@ -66,6 +73,7 @@ bool JurisdictionSender::process() { _nodesRequestingJurisdictions.erase(nodeIterator); } } + unlockRequestingNodes(); // set our packets per second to be the number of nodes setPacketsPerSecond(nodeCount); diff --git a/libraries/voxels/src/JurisdictionSender.h b/libraries/voxels/src/JurisdictionSender.h index 9678eb15e2..2cf3a6b932 100644 --- a/libraries/voxels/src/JurisdictionSender.h +++ b/libraries/voxels/src/JurisdictionSender.h @@ -25,6 +25,7 @@ public: static const int DEFAULT_PACKETS_PER_SECOND = 1; JurisdictionSender(JurisdictionMap* map, PacketSenderNotify* notify = NULL); + ~JurisdictionSender(); void setJurisdiction(JurisdictionMap* map) { _jurisdictionMap = map; } @@ -33,7 +34,15 @@ public: protected: virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + /// Locks all the resources of the thread. + void lockRequestingNodes() { pthread_mutex_lock(&_requestingNodeMutex); } + + /// Unlocks all the resources of the thread. + void unlockRequestingNodes() { pthread_mutex_unlock(&_requestingNodeMutex); } + + private: + pthread_mutex_t _requestingNodeMutex; JurisdictionMap* _jurisdictionMap; std::set _nodesRequestingJurisdictions; }; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 456a2d8e58..4ba90c87c0 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -65,8 +65,11 @@ void VoxelNode::init(unsigned char * octalCode) { // set up the _children union _childBitmask = 0; _childrenExternal = false; + +#ifdef BLENDED_UNION_CHILDREN _children.external = NULL; _singleChildrenCount++; +#endif _childrenCount[0]++; // default pointers to child nodes to NULL @@ -80,7 +83,11 @@ void VoxelNode::init(unsigned char * octalCode) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { _simpleChildArray[i] = NULL; } -#endif +#endif + +#ifdef SIMPLE_EXTERNAL_CHILDREN + _children.single = NULL; +#endif _unknownBufferIndex = true; setBufferIndex(GLBUFFER_INDEX_UNKNOWN); @@ -314,20 +321,50 @@ uint64_t VoxelNode::_getChildAtIndexCalls = 0; uint64_t VoxelNode::_setChildAtIndexTime = 0; uint64_t VoxelNode::_setChildAtIndexCalls = 0; +#ifdef BLENDED_UNION_CHILDREN uint64_t VoxelNode::_singleChildrenCount = 0; uint64_t VoxelNode::_twoChildrenOffsetCount = 0; uint64_t VoxelNode::_twoChildrenExternalCount = 0; uint64_t VoxelNode::_threeChildrenOffsetCount = 0; uint64_t VoxelNode::_threeChildrenExternalCount = 0; -uint64_t VoxelNode::_externalChildrenCount = 0; -uint64_t VoxelNode::_childrenCount[NUMBER_OF_CHILDREN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint64_t VoxelNode::_couldStoreFourChildrenInternally = 0; uint64_t VoxelNode::_couldNotStoreFourChildrenInternally = 0; +#endif + +uint64_t VoxelNode::_externalChildrenCount = 0; +uint64_t VoxelNode::_childrenCount[NUMBER_OF_CHILDREN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { #ifdef SIMPLE_CHILD_ARRAY return _simpleChildArray[childIndex]; -#else +#endif // SIMPLE_CHILD_ARRAY + +#ifdef SIMPLE_EXTERNAL_CHILDREN + int childCount = getChildCount(); + + switch (childCount) { + case 0: { + return NULL; + } break; + + case 1: { + // if our single child is the one being requested, return it, otherwise + // return null + int firstIndex = getNthBit(_childBitmask, 1); + if (firstIndex == childIndex) { + return _children.single; + } else { + return NULL; + } + } break; + + default : { + return _children.external[childIndex]; + } break; + } +#endif // def SIMPLE_EXTERNAL_CHILDREN + +#ifdef BLENDED_UNION_CHILDREN PerformanceWarning warn(false,"getChildAtIndex",false,&_getChildAtIndexTime,&_getChildAtIndexCalls); VoxelNode* result = NULL; int childCount = getChildCount(); @@ -439,6 +476,7 @@ VoxelNode* VoxelNode::getChildAtIndex(int childIndex) const { #endif } +#ifdef BLENDED_UNION_CHILDREN void VoxelNode::storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo) { int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this; int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this; @@ -633,6 +671,7 @@ void VoxelNode::checkStoreFourChildren(VoxelNode* childOne, VoxelNode* childTwo, _couldNotStoreFourChildrenInternally++; } } +#endif void VoxelNode::deleteAllChildren() { // first delete all the VoxelNode objects... @@ -643,6 +682,7 @@ void VoxelNode::deleteAllChildren() { } } +#ifdef BLENDED_UNION_CHILDREN // now, reset our internal state and ANY and all population data int childCount = getChildCount(); switch (childCount) { @@ -686,17 +726,79 @@ void VoxelNode::deleteAllChildren() { delete[] _children.external; } _children.single = NULL; +#endif // BLENDED_UNION_CHILDREN } void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) { #ifdef SIMPLE_CHILD_ARRAY + int previousChildCount = getChildCount(); if (child) { setAtBit(_childBitmask, childIndex); } else { clearAtBit(_childBitmask, childIndex); } + int newChildCount = getChildCount(); + + // store the child in our child array _simpleChildArray[childIndex] = child; -#else + + // track our population data + if (previousChildCount != newChildCount) { + _childrenCount[previousChildCount]--; + _childrenCount[newChildCount]++; + } +#endif + +#ifdef SIMPLE_EXTERNAL_CHILDREN + + int firstIndex = getNthBit(_childBitmask, 1); + int secondIndex = getNthBit(_childBitmask, 2); + + int previousChildCount = getChildCount(); + if (child) { + setAtBit(_childBitmask, childIndex); + } else { + clearAtBit(_childBitmask, childIndex); + } + int newChildCount = getChildCount(); + + // track our population data + if (previousChildCount != newChildCount) { + _childrenCount[previousChildCount]--; + _childrenCount[newChildCount]++; + } + + if ((previousChildCount == 0 || previousChildCount == 1) && newChildCount == 0) { + _children.single = NULL; + } else if (previousChildCount == 0 && newChildCount == 1) { + _children.single = child; + } else if (previousChildCount == 1 && newChildCount == 2) { + VoxelNode* previousChild = _children.single; + _children.external = new VoxelNode*[NUMBER_OF_CHILDREN]; + memset(_children.external, 0, sizeof(VoxelNode*) * NUMBER_OF_CHILDREN); + _children.external[firstIndex] = previousChild; + _children.external[childIndex] = child; + + _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(VoxelNode*); + + } else if (previousChildCount == 2 && newChildCount == 1) { + assert(child == NULL); // we are removing a child, so this must be true! + VoxelNode* previousFirstChild = _children.external[firstIndex]; + VoxelNode* previousSecondChild = _children.external[secondIndex]; + delete[] _children.external; + _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(VoxelNode*); + if (childIndex == firstIndex) { + _children.single = previousSecondChild; + } else { + _children.single = previousFirstChild; + } + } else { + _children.external[childIndex] = child; + } + +#endif // def SIMPLE_EXTERNAL_CHILDREN + +#ifdef BLENDED_UNION_CHILDREN PerformanceWarning warn(false,"setChildAtIndex",false,&_setChildAtIndexTime,&_setChildAtIndexCalls); // Here's how we store things... diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index c9e892ebb9..17760f0514 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -10,7 +10,8 @@ #define __hifi__VoxelNode__ //#define HAS_AUDIT_CHILDREN -#define SIMPLE_CHILD_ARRAY +//#define SIMPLE_CHILD_ARRAY +#define SIMPLE_EXTERNAL_CHILDREN #include #include "AABox.h" @@ -131,24 +132,30 @@ public: static uint64_t getSetChildAtIndexTime() { return _setChildAtIndexTime; } static uint64_t getSetChildAtIndexCalls() { return _setChildAtIndexCalls; } +#ifdef BLENDED_UNION_CHILDREN static uint64_t getSingleChildrenCount() { return _singleChildrenCount; } static uint64_t getTwoChildrenOffsetCount() { return _twoChildrenOffsetCount; } static uint64_t getTwoChildrenExternalCount() { return _twoChildrenExternalCount; } static uint64_t getThreeChildrenOffsetCount() { return _threeChildrenOffsetCount; } static uint64_t getThreeChildrenExternalCount() { return _threeChildrenExternalCount; } + static uint64_t getCouldStoreFourChildrenInternally() { return _couldStoreFourChildrenInternally; } + static uint64_t getCouldNotStoreFourChildrenInternally() { return _couldNotStoreFourChildrenInternally; } +#endif + static uint64_t getExternalChildrenCount() { return _externalChildrenCount; } static uint64_t getChildrenCount(int childCount) { return _childrenCount[childCount]; } - static uint64_t getCouldStoreFourChildrenInternally() { return _couldStoreFourChildrenInternally; } - static uint64_t getCouldNotStoreFourChildrenInternally() { return _couldNotStoreFourChildrenInternally; } - +#ifdef BLENDED_UNION_CHILDREN #ifdef HAS_AUDIT_CHILDREN void auditChildren(const char* label) const; #endif // def HAS_AUDIT_CHILDREN +#endif // def BLENDED_UNION_CHILDREN private: void deleteAllChildren(); void setChildAtIndex(int childIndex, VoxelNode* child); + +#ifdef BLENDED_UNION_CHILDREN void storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo); void retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo); void storeThreeChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree); @@ -156,7 +163,7 @@ private: void decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const; void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree); void checkStoreFourChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree, VoxelNode* childFour); - +#endif void calculateAABox(); void init(unsigned char * octalCode); void notifyDeleteHooks(); @@ -174,20 +181,29 @@ private: /// Client and server, pointers to child nodes, various encodings #ifdef SIMPLE_CHILD_ARRAY - VoxelNode* _simpleChildArray[8]; /// Only used when HAS_AUDIT_CHILDREN is enabled to help debug children encoding + VoxelNode* _simpleChildArray[8]; /// Only used when SIMPLE_CHILD_ARRAY is enabled +#endif + +#ifdef SIMPLE_EXTERNAL_CHILDREN + union children_t { + VoxelNode* single; + VoxelNode** external; + } _children; #endif +#ifdef BLENDED_UNION_CHILDREN union children_t { VoxelNode* single; int32_t offsetsTwoChildren[2]; uint64_t offsetsThreeChildrenEncoded; VoxelNode** external; } _children; - #ifdef HAS_AUDIT_CHILDREN VoxelNode* _childrenArray[8]; /// Only used when HAS_AUDIT_CHILDREN is enabled to help debug children encoding #endif // def HAS_AUDIT_CHILDREN +#endif //def BLENDED_UNION_CHILDREN + uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes _voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes @@ -237,16 +253,17 @@ private: static uint64_t _setChildAtIndexTime; static uint64_t _setChildAtIndexCalls; +#ifdef BLENDED_UNION_CHILDREN static uint64_t _singleChildrenCount; static uint64_t _twoChildrenOffsetCount; static uint64_t _twoChildrenExternalCount; static uint64_t _threeChildrenOffsetCount; static uint64_t _threeChildrenExternalCount; - static uint64_t _externalChildrenCount; - static uint64_t _childrenCount[NUMBER_OF_CHILDREN + 1]; - static uint64_t _couldStoreFourChildrenInternally; static uint64_t _couldNotStoreFourChildrenInternally; +#endif + static uint64_t _externalChildrenCount; + static uint64_t _childrenCount[NUMBER_OF_CHILDREN + 1]; }; #endif /* defined(__hifi__VoxelNode__) */ \ No newline at end of file