bool DomainContentBackupManager::process() { if (isStillRunning()) { constexpr int64_t MSECS_TO_USECS = 1000; constexpr int64_t USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms std::this_thread::sleep_for(std::chrono::microseconds(USECS_TO_SLEEP)); if (_isRecovering) { bool isStillRecovering = any_of(begin(_backupHandlers), end(_backupHandlers), [](const BackupHandlerPointer& handler) { return handler->getRecoveryStatus().first; }); if (!isStillRecovering) { _isRecovering = false; _recoveryFilename = ""; emit recoveryCompleted(); } } auto now = p_high_resolution_clock::now(); auto sinceLastSave = now - _lastCheck; if (sinceLastSave > _persistInterval) { _lastCheck = now; if (!_isRecovering) { backup(); } } } return isStillRunning(); }
bool OctreeSendThread::process() { quint64 start = usecTimestampNow(); bool gotLock = false; // don't do any send processing until the initial load of the octree is complete... if (_myServer->isInitialLoadComplete()) { SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); if (node) { // make sure the node list doesn't kill our node while we're using it if (node->getMutex().tryLock()) { gotLock = true; OctreeQueryNode* nodeData = NULL; nodeData = (OctreeQueryNode*) node->getLinkedData(); int packetsSent = 0; // 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)); } packetsSent = packetDistributor(node, nodeData, viewFrustumChanged); } node->getMutex().unlock(); // we're done with this node for now. } } } 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 if (isStillRunning() && gotLock) { // dynamically sleep until we need to fire off the next set of octree elements int elapsed = (usecTimestampNow() - start); int usecToSleep = OCTREE_SEND_INTERVAL_USECS - elapsed; if (usecToSleep > 0) { PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { std::cout << "Last send took too much time, not sleeping!\n"; } } } return isStillRunning(); // keep running till they terminate us }
bool ReceivedPacketProcessor::process() { quint64 now = usecTimestampNow(); quint64 sinceLastWindow = now - _lastWindowAt; if (sinceLastWindow > USECS_PER_SECOND) { lock(); float secondsSinceLastWindow = sinceLastWindow / USECS_PER_SECOND; float incomingPacketsPerSecondInWindow = (float)_lastWindowIncomingPackets / secondsSinceLastWindow; _incomingPPS.updateAverage(incomingPacketsPerSecondInWindow); float processedPacketsPerSecondInWindow = (float)_lastWindowProcessedPackets / secondsSinceLastWindow; _processedPPS.updateAverage(processedPacketsPerSecondInWindow); _lastWindowAt = now; _lastWindowIncomingPackets = 0; _lastWindowProcessedPackets = 0; unlock(); } if (_packets.size() == 0) { _waitingOnPacketsMutex.lock(); _hasPackets.wait(&_waitingOnPacketsMutex, getMaxWait()); _waitingOnPacketsMutex.unlock(); } preProcess(); if (!_packets.size()) { return isStillRunning(); } lock(); std::list<NodeSharedReceivedMessagePair> currentPackets; currentPackets.swap(_packets); unlock(); for(auto& packetPair : currentPackets) { processPacket(packetPair.second, packetPair.first); _lastWindowProcessedPackets++; midProcess(); } lock(); for(auto& packetPair : currentPackets) { _nodePacketCounts[packetPair.first->getUUID()]--; } unlock(); postProcess(); return isStillRunning(); // keep running till they terminate us }
bool OctreeSendThread::process() { if (_isShuttingDown) { return false; // exit early if we're shutting down } // check that our server and assignment is still valid if (!_myServer || !_myAssignment) { return false; // exit early if it's not, it means the server is shutting down } OctreeServer::didProcess(this); quint64 start = usecTimestampNow(); // don't do any send processing until the initial load of the octree is complete... if (_myServer->isInitialLoadComplete()) { if (_node) { _nodeMissingCount = 0; OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(_node->getLinkedData()); // Sometimes the node data has not yet been linked, in which case we can't really do anything if (nodeData && !nodeData->isShuttingDown()) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); packetDistributor(nodeData, viewFrustumChanged); } } } if (_isShuttingDown) { return false; // exit early if we're shutting down } // Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap if (isStillRunning()) { // dynamically sleep until we need to fire off the next set of octree elements int elapsed = (usecTimestampNow() - start); int usecToSleep = OCTREE_SEND_INTERVAL_USECS - elapsed; if (usecToSleep > 0) { PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { const int MIN_USEC_TO_SLEEP = 1; usleep(MIN_USEC_TO_SLEEP); } } return isStillRunning(); // keep running till they terminate us }
bool JurisdictionListener::queueJurisdictionRequest() { //qDebug() << "JurisdictionListener::queueJurisdictionRequest()\n"; static unsigned char buffer[MAX_PACKET_SIZE]; unsigned char* bufferOut = &buffer[0]; ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_JURISDICTION_REQUEST); int nodeCount = 0; NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (nodeList->getNodeActiveSocketOrPing(&(*node)) && node->getType() == getNodeType()) { const HifiSockAddr* nodeAddress = node->getActiveSocket(); PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); nodeCount++; } } if (nodeCount > 0) { setPacketsPerSecond(nodeCount); } else { setPacketsPerSecond(NO_SERVER_CHECK_RATE); } // keep going if still running return isStillRunning(); }
bool JurisdictionListener::queueJurisdictionRequest() { static unsigned char buffer[MAX_PACKET_SIZE]; unsigned char* bufferOut = &buffer[0]; ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_VOXEL_JURISDICTION_REQUEST); int nodeCount = 0; NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { // only send to the NodeTypes that are interested in our jurisdiction details const int numNodeTypes = 1; const NODE_TYPE nodeTypes[numNodeTypes] = { NODE_TYPE_VOXEL_SERVER }; if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) { sockaddr* nodeAddress = node->getActiveSocket(); PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); nodeCount++; } } // set our packets per second to be the number of nodes setPacketsPerSecond(nodeCount); // keep going if still running return isStillRunning(); }
bool JurisdictionSender::process() { bool continueProcessing = isStillRunning(); // call our ReceivedPacketProcessor base class process so we'll get any pending packets if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) { int nodeCount = 0; lockRequestingNodes(); while (!_nodesRequestingJurisdictions.empty()) { QUuid nodeUUID = _nodesRequestingJurisdictions.front(); _nodesRequestingJurisdictions.pop(); SharedNodePointer node = DependencyManager::get<NodeList>()->nodeWithUUID(nodeUUID); if (node && node->getActiveSocket()) { auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket() : JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType()); _packetSender.queuePacketForSending(node, std::move(packet)); nodeCount++; } } unlockRequestingNodes(); // set our packets per second to be the number of nodes _packetSender.setPacketsPerSecond(nodeCount); continueProcessing = _packetSender.process(); } return continueProcessing; }
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 << "times we checked, we are going to stop attempting to send."; return false; // stop processing and shutdown, our node no longer exists } quint64 start = usecTimestampNow(); // don't do any send processing until the initial load of the octree is complete... if (_myServer->isInitialLoadComplete()) { SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); if (node) { _nodeMissingCount = 0; OctreeQueryNode* nodeData = NULL; nodeData = (OctreeQueryNode*) node->getLinkedData(); // Sometimes the node data has not yet been linked, in which case we can't really do anything if (nodeData) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); packetDistributor(node, nodeData, viewFrustumChanged); } } else { _nodeMissingCount++; } } // Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap if (isStillRunning()) { // dynamically sleep until we need to fire off the next set of octree elements int elapsed = (usecTimestampNow() - start); int usecToSleep = OCTREE_SEND_INTERVAL_USECS - elapsed; if (usecToSleep > 0) { PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { const int MIN_USEC_TO_SLEEP = 1; usleep(MIN_USEC_TO_SLEEP); } } return isStillRunning(); // keep running till they terminate us }
bool PacketSender::threadedProcess() { bool hasSlept = false; if (_lastSendTime == 0) { _lastSendTime = usecTimestampNow(); } // in threaded mode, we keep running and just empty our packet queue sleeping enough to keep our PPS on target while (_packets.size() > 0) { // Recalculate our SEND_INTERVAL_USECS each time, in case the caller has changed it on us.. int packetsPerSecondTarget = (_packetsPerSecond > MINIMUM_PACKETS_PER_SECOND) ? _packetsPerSecond : MINIMUM_PACKETS_PER_SECOND; quint64 intervalBetweenSends = USECS_PER_SECOND / packetsPerSecondTarget; quint64 sleepInterval = (intervalBetweenSends > SENDING_INTERVAL_ADJUST) ? intervalBetweenSends - SENDING_INTERVAL_ADJUST : intervalBetweenSends; // We'll sleep before we send, this way, we can set our last send time to be our ACTUAL last send time quint64 now = usecTimestampNow(); quint64 elapsed = now - _lastSendTime; int usecToSleep = sleepInterval - elapsed; // If we've never sent, or it's been a long time since we sent, then our elapsed time will be quite large // and therefore usecToSleep will be less than 0 and we won't sleep before sending... if (usecToSleep > 0) { if (usecToSleep > MAX_SLEEP_INTERVAL) { usecToSleep = MAX_SLEEP_INTERVAL; } usleep(usecToSleep); hasSlept = true; } // call our non-threaded version of ourselves bool keepRunning = nonThreadedProcess(); if (!keepRunning) { break; } } // if threaded and we haven't slept? We want to wait for our consumer to signal us with new packets if (!hasSlept) { // wait till we have packets _waitingOnPacketsMutex.lock(); _hasPackets.wait(&_waitingOnPacketsMutex); _waitingOnPacketsMutex.unlock(); } return isStillRunning(); }
bool JurisdictionListener::process() { bool continueProcessing = isStillRunning(); // If we're still running, and we don't have any requests waiting to be sent, then queue our jurisdiction requests if (continueProcessing && !hasPacketsToSend()) { queueJurisdictionRequest(); continueProcessing = PacketSender::process(); } if (continueProcessing) { // NOTE: This will sleep if there are no pending packets to process continueProcessing = ReceivedPacketProcessor::process(); } return continueProcessing; }
bool PacketSender::threadedProcess() { bool hasSlept = false; if (_lastSendTime == 0) { _lastSendTime = usecTimestampNow(); } // in threaded mode, we keep running and just empty our packet queue sleeping enough to keep our PPS on target while (_packets.size() > 0) { // Recalculate our SEND_INTERVAL_USECS each time, in case the caller has changed it on us.. int packetsPerSecondTarget = (_packetsPerSecond > MINIMUM_PACKETS_PER_SECOND) ? _packetsPerSecond : MINIMUM_PACKETS_PER_SECOND; quint64 intervalBetweenSends = USECS_PER_SECOND / packetsPerSecondTarget; quint64 sleepInterval = (intervalBetweenSends > SENDING_INTERVAL_ADJUST) ? intervalBetweenSends - SENDING_INTERVAL_ADJUST : intervalBetweenSends; // We'll sleep before we send, this way, we can set our last send time to be our ACTUAL last send time quint64 now = usecTimestampNow(); quint64 elapsed = now - _lastSendTime; int usecToSleep = sleepInterval - elapsed; // If we've never sent, or it's been a long time since we sent, then our elapsed time will be quite large // and therefore usecToSleep will be less than 0 and we won't sleep before sending... if (usecToSleep > 0) { if (usecToSleep > MAX_SLEEP_INTERVAL) { usecToSleep = MAX_SLEEP_INTERVAL; } usleep(usecToSleep); hasSlept = true; } // call our non-threaded version of ourselves bool keepRunning = nonThreadedProcess(); if (!keepRunning) { break; } } // if threaded and we haven't slept? We want to sleep a little so we don't hog the CPU, but // we don't want to sleep too long because how ever much we sleep will delay any future unsent // packets that arrive while we're sleeping. So we sleep 1/2 of our target fps interval if (!hasSlept) { usleep(MINIMAL_SLEEP_INTERVAL); } return isStillRunning(); }
bool ReceivedPacketProcessor::process() { if (_packets.size() == 0) { _waitingOnPacketsMutex.lock(); _hasPackets.wait(&_waitingOnPacketsMutex); _waitingOnPacketsMutex.unlock(); } while (_packets.size() > 0) { lock(); // lock to make sure nothing changes on us NetworkPacket& packet = _packets.front(); // get the oldest packet NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us _packets.erase(_packets.begin()); // remove the oldest packet _nodePacketCounts[temporary.getNode()->getUUID()]--; unlock(); // let others add to the packets processPacket(temporary.getNode(), temporary.getByteArray()); // process our temporary copy } return isStillRunning(); // keep running till they terminate us }
bool ReceivedPacketProcessor::process() { // If a derived class handles process sleeping, like the JurisdiciontListener, then it can set // this _dontSleep member and we will honor that request. if (_packets.size() == 0 && !_dontSleep) { const uint64_t RECEIVED_THREAD_SLEEP_INTERVAL = (1000 * 1000)/60; // check at 60fps usleep(RECEIVED_THREAD_SLEEP_INTERVAL); } while (_packets.size() > 0) { lock(); // lock to make sure nothing changes on us NetworkPacket& packet = _packets.front(); // get the oldest packet NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us _packets.erase(_packets.begin()); // remove the oldest packet unlock(); // let others add to the packets processPacket(temporary.getAddress(), temporary.getData(), temporary.getLength()); // process our temporary copy } return isStillRunning(); // keep running till they terminate us }
GenericThread::~GenericThread() { // we only need to call terminate() if we're actually threaded and still running if (isStillRunning() && isThreaded()) { terminate(); } }
// We may be called more frequently than we get packets or need to send packets, we may also get called less frequently. // // If we're called more often then out target PPS then we will space out our actual sends to be a single packet for multiple // calls to process. Those calls to proces in which we do not need to send a packet to keep up with our target PPS we will // just track our call rate (in order to predict our sends per call) but we won't actually send any packets. // // When we are called less frequently than we have packets to send, we will send enough packets per call to keep up with our // target PPS. // // We also keep a running total of packets sent over multiple calls to process() so that we can adjust up or down for // possible rounding error that would occur if we only considered whole integer packet counts per call to process bool PacketSender::nonThreadedProcess() { quint64 now = usecTimestampNow(); if (_lastProcessCallTime == 0) { _lastProcessCallTime = now - _usecsPerProcessCallHint; } const quint64 MINIMUM_POSSIBLE_CALL_TIME = 10; // in usecs const quint64 USECS_PER_SECOND = 1000 * 1000; const float ZERO_RESET_CALLS_PER_SECOND = 1; // used in guard against divide by zero // keep track of our process call times, so we have a reliable account of how often our caller calls us quint64 elapsedSinceLastCall = now - _lastProcessCallTime; _lastProcessCallTime = now; _averageProcessCallTime.updateAverage(elapsedSinceLastCall); float averageCallTime = 0; const int TRUST_AVERAGE_AFTER = AVERAGE_CALL_TIME_SAMPLES * 2; if (_usecsPerProcessCallHint == 0 || _averageProcessCallTime.getSampleCount() > TRUST_AVERAGE_AFTER) { averageCallTime = _averageProcessCallTime.getAverage(); } else { averageCallTime = _usecsPerProcessCallHint; } if (_packets.size() == 0) { // in non-threaded mode, if there's nothing to do, just return, keep running till they terminate us return isStillRunning(); } // This only happens once, the first time we get this far... so we can use it as an accurate initialization // point for these important timing variables if (_lastPPSCheck == 0) { _lastPPSCheck = now; // pretend like our lifetime began once call cycle for now, this makes our lifetime PPS start out most accurately _started = now - (quint64)averageCallTime; } float averagePacketsPerCall = 0; // might be less than 1, if our caller calls us more frequently than the target PPS int packetsSentThisCall = 0; int packetsToSendThisCall = 0; // Since we're in non-threaded mode, we need to determine how many packets to send per call to process // based on how often we get called... We do this by keeping a running average of our call times, and we determine // how many packets to send per call // We assume you can't possibly call us less than MINIMUM_POSSIBLE_CALL_TIME apart if (averageCallTime <= 0) { averageCallTime = MINIMUM_POSSIBLE_CALL_TIME; } // we can determine how many packets we need to send per call to achieve our desired // packets per second send rate. float callsPerSecond = USECS_PER_SECOND / averageCallTime; // theoretically we could get called less than 1 time per second... but since we're using floats, it really shouldn't be // possible to get 0 calls per second, but we will guard agains that here, just in case. if (callsPerSecond == 0) { callsPerSecond = ZERO_RESET_CALLS_PER_SECOND; } // This is the average number of packets per call... averagePacketsPerCall = _packetsPerSecond / callsPerSecond; packetsToSendThisCall = averagePacketsPerCall; // if we get called more than 1 per second, we want to mostly divide the packets evenly across the calls... // but we want to track the remainder and make sure over the course of a second, we are sending the target PPS // e.g. // 200pps called 60 times per second... // 200/60 = 3.333... so really... // each call we should send 3 // every 3rd call we should send 4... // 3,3,4,3,3,4...3,3,4 = 200... // if we get called less than 1 per second, then we want to send more than our PPS each time... // e.g. // 200pps called ever 1332.5ms // 200 / (1000/1332.5) = 200/(0.7505) = 266.5 packets per call // so... // every other call we should send 266 packets // then on the next call we should send 267 packets // So no mater whether or not we're getting called more or less than once per second, we still need to do some bookkeeping // to make sure we send a few extra packets to even out our flow rate. quint64 elapsedSinceLastCheck = now - _lastPPSCheck; // we might want to tun this in the future and only check after a certain number of call intervals. for now we check // each time and adjust accordingly const float CALL_INTERVALS_TO_CHECK = 1; const float MIN_CALL_INTERVALS_PER_RESET = 5; // we will reset our check PPS and time each second (callsPerSecond) or at least 5 calls (if we get called less frequently // than 5 times per second) This gives us sufficient smoothing in our packet adjustments float callIntervalsPerReset = std::max(callsPerSecond, MIN_CALL_INTERVALS_PER_RESET); if (elapsedSinceLastCheck > (averageCallTime * CALL_INTERVALS_TO_CHECK)) { float ppsOverCheckInterval = (float)_packetsOverCheckInterval; float ppsExpectedForCheckInterval = (float)_packetsPerSecond * ((float)elapsedSinceLastCheck / (float)USECS_PER_SECOND); if (ppsOverCheckInterval < ppsExpectedForCheckInterval) { int adjust = ppsExpectedForCheckInterval - ppsOverCheckInterval; packetsToSendThisCall += adjust; } else if (ppsOverCheckInterval > ppsExpectedForCheckInterval) { int adjust = ppsOverCheckInterval - ppsExpectedForCheckInterval; packetsToSendThisCall -= adjust; } // now, do we want to reset the check interval? don't want to completely reset, because we would still have // a rounding error. instead, we check to see that we've passed the reset interval (which is much larger than // the check interval), and on those reset intervals we take the second half average and keep that for the next // interval window... if (elapsedSinceLastCheck > (averageCallTime * callIntervalsPerReset)) { // Keep average packets and time for "second half" of check interval _lastPPSCheck += (elapsedSinceLastCheck / 2); _packetsOverCheckInterval = (_packetsOverCheckInterval / 2); elapsedSinceLastCheck = now - _lastPPSCheck; } } auto packetsLeft = _packets.size(); // Now that we know how many packets to send this call to process, just send them. while ((packetsSentThisCall < packetsToSendThisCall) && (packetsLeft > 0)) { lock(); NodePacketPair packetPair = std::move(_packets.front()); _packets.pop_front(); packetsLeft = _packets.size(); unlock(); // send the packet through the NodeList... DependencyManager::get<NodeList>()->sendUnreliablePacket(*packetPair.second, *packetPair.first); packetsSentThisCall++; _packetsOverCheckInterval++; _totalPacketsSent++; int packetSize = packetPair.second->getDataSize(); _totalBytesSent += packetSize; emit packetSent(packetSize); _lastSendTime = now; } return isStillRunning(); }
bool PacketSender::process() { uint64_t USECS_PER_SECOND = 1000 * 1000; uint64_t SEND_INTERVAL_USECS = (_packetsPerSecond == 0) ? USECS_PER_SECOND : (USECS_PER_SECOND / _packetsPerSecond); // keep track of our process call times, so we have a reliable account of how often our caller calls us uint64_t now = usecTimestampNow(); uint64_t elapsedSinceLastCall = now - _lastProcessCallTime; _lastProcessCallTime = now; _averageProcessCallTime.updateAverage(elapsedSinceLastCall); if (_packets.size() == 0) { if (isThreaded()) { usleep(SEND_INTERVAL_USECS); } else { return isStillRunning(); // in non-threaded mode, if there's nothing to do, just return, keep running till they terminate us } } int packetsPerCall = _packets.size(); // in threaded mode, we just empty this! int packetsThisCall = 0; // if we're in non-threaded mode, then we actually need to determine how many packets to send per call to process // based on how often we get called... We do this by keeping a running average of our call times, and we determine // how many packets to send per call if (!isThreaded()) { int averageCallTime; const int TRUST_AVERAGE_AFTER = AVERAGE_CALL_TIME_SAMPLES * 2; if (_usecsPerProcessCallHint == 0 || _averageProcessCallTime.getSampleCount() > TRUST_AVERAGE_AFTER) { averageCallTime = _averageProcessCallTime.getAverage(); } else { averageCallTime = _usecsPerProcessCallHint; } // we can determine how many packets we need to send per call to achieve our desired // packets per second send rate. int callsPerSecond = USECS_PER_SECOND / averageCallTime; packetsPerCall = ceil(_packetsPerSecond / callsPerSecond); // send at least one packet per call, if we have it if (packetsPerCall < 1) { packetsPerCall = 1; } } int packetsLeft = _packets.size(); bool keepGoing = packetsLeft > 0; while (keepGoing) { NetworkPacket& packet = _packets.front(); // send the packet through the NodeList... UDPSocket* nodeSocket = NodeList::getInstance()->getNodeSocket(); nodeSocket->send(&packet.getAddress(), packet.getData(), packet.getLength()); packetsThisCall++; if (_notify) { _notify->packetSentNotification(packet.getLength()); } lock(); _packets.erase(_packets.begin()); unlock(); packetsLeft = _packets.size(); // in threaded mode, we go till we're empty if (isThreaded()) { keepGoing = packetsLeft > 0; // dynamically sleep until we need to fire off the next set of voxels we only sleep in threaded mode if (keepGoing) { uint64_t elapsed = now - _lastSendTime; int usecToSleep = std::max(SEND_INTERVAL_USECS, SEND_INTERVAL_USECS - elapsed); // we only sleep in non-threaded mode if (usecToSleep > 0) { usleep(usecToSleep); } } } else { // in non-threaded mode, we send as many packets as we need per expected call to process() keepGoing = (packetsThisCall < packetsPerCall) && (packetsLeft > 0); } _lastSendTime = now; } return isStillRunning(); // keep running till they terminate us }
bool OctreePersistThread::process() { if (!_initialLoadComplete) { quint64 loadStarted = usecTimestampNow(); qDebug() << "loading Octrees from file: " << _filename << "..."; bool persistantFileRead; _tree->lockForWrite(); { PerformanceWarning warn(true, "Loading Octree File", true); persistantFileRead = _tree->readFromSVOFile(_filename.toLocal8Bit().constData()); _tree->pruneTree(); } _tree->unlock(); quint64 loadDone = usecTimestampNow(); _loadTimeUSecs = loadDone - loadStarted; _tree->clearDirtyBit(); // the tree is clean since we just loaded it qDebug("DONE loading Octrees from file... fileRead=%s", debug::valueOf(persistantFileRead)); unsigned long nodeCount = OctreeElement::getNodeCount(); unsigned long internalNodeCount = OctreeElement::getInternalNodeCount(); unsigned long leafNodeCount = OctreeElement::getLeafNodeCount(); qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves", nodeCount, internalNodeCount, leafNodeCount); bool wantDebug = false; if (wantDebug) { double usecPerGet = (double)OctreeElement::getGetChildAtIndexTime() / (double)OctreeElement::getGetChildAtIndexCalls(); qDebug() << "getChildAtIndexCalls=" << OctreeElement::getGetChildAtIndexCalls() << " getChildAtIndexTime=" << OctreeElement::getGetChildAtIndexTime() << " perGet=" << usecPerGet; double usecPerSet = (double)OctreeElement::getSetChildAtIndexTime() / (double)OctreeElement::getSetChildAtIndexCalls(); qDebug() << "setChildAtIndexCalls=" << OctreeElement::getSetChildAtIndexCalls() << " setChildAtIndexTime=" << OctreeElement::getSetChildAtIndexTime() << " perSet=" << usecPerSet; } _initialLoadComplete = true; _lastBackup = _lastCheck = usecTimestampNow(); // we just loaded, no need to save again time(&_lastPersistTime); emit loadCompleted(); } if (isStillRunning()) { quint64 MSECS_TO_USECS = 1000; quint64 USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms usleep(USECS_TO_SLEEP); // do our updates then check to save... _tree->update(); quint64 now = usecTimestampNow(); quint64 sinceLastSave = now - _lastCheck; quint64 intervalToCheck = _persistInterval * MSECS_TO_USECS; if (sinceLastSave > intervalToCheck) { _lastCheck = now; persist(); } } // if we were asked to debugTimestampNow do that now... if (_debugTimestampNow) { quint64 now = usecTimestampNow(); quint64 sinceLastDebug = now - _lastTimeDebug; quint64 DEBUG_TIMESTAMP_INTERVAL = 600000000; // every 10 minutes if (sinceLastDebug > DEBUG_TIMESTAMP_INTERVAL) { _lastTimeDebug = usecTimestampNow(true); // ask for debug output } } return isStillRunning(); // keep running till they terminate us }