diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fbf383cc6f..5d7b7ee67b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3396,20 +3396,91 @@ void Application::displayStats() { sprintf(avatarStats, "Avatar: pos %.3f, %.3f, %.3f, vel %.1f, yaw = %.2f", avatarPos.x, avatarPos.y, avatarPos.z, glm::length(_myAvatar.getVelocity()), _myAvatar.getBodyYaw()); drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarStats); - - QLocale locale(QLocale::English); + Node* avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); + char avatarMixerStats[200]; + if (avatarMixer) { + sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps", + roundf(avatarMixer->getAverageKilobitsPerSecond()), + roundf(avatarMixer->getAveragePacketsPerSecond())); + } else { + sprintf(avatarMixerStats, "No Avatar Mixer"); + } + statsVerticalOffset += PELS_PER_LINE; + drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarMixerStats); + + // Used for formatting voxel stats details + statsVerticalOffset += PELS_PER_LINE; // skip a line for voxels + QLocale locale(QLocale::English); std::stringstream voxelStats; - voxelStats.precision(4); - voxelStats << "Voxels " << - "Max: " << _voxels.getMaxVoxels() / 1000.f << "K " << - "Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " << - "Written: " << _voxels.getVoxelsWritten() / 1000.f << "K " << - "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K " << - "Updated: " << _voxels.getVoxelsUpdated() / 1000.f << "K "; + + // iterate all the current voxel stats, and list their sending modes, and total voxel counts + std::stringstream sendingMode(""); + sendingMode << "Voxel Sending Mode: ["; + int serverCount = 0; + int movingServerCount = 0; + unsigned long totalNodes = 0; + unsigned long totalInternal = 0; + unsigned long totalLeaves = 0; + for(NodeToVoxelSceneStatsIterator i = _voxelServerSceneStats.begin(); i != _voxelServerSceneStats.end(); i++) { + //const QUuid& uuid = i->first; + VoxelSceneStats& stats = i->second; + serverCount++; + if (serverCount > 1) { + sendingMode << ","; + } + if (stats.isMoving()) { + sendingMode << "M"; + movingServerCount++; + } else { + sendingMode << "S"; + } + + // calculate server node totals + totalNodes += stats.getTotalVoxels(); + totalInternal += stats.getTotalInternal(); + totalLeaves += stats.getTotalLeaves(); + } + if (serverCount == 0) { + sendingMode << "---"; + } + sendingMode << "] " << serverCount << " servers"; + if (movingServerCount > 0) { + sendingMode << " "; + } else { + sendingMode << " "; + } + + QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); + QString serversInternalString = locale.toString((uint)totalInternal); + QString serversLeavesString = locale.toString((uint)totalLeaves); + + // Server Voxels + voxelStats.str(""); + voxelStats << + "Server Voxels Total: " << serversTotalString.toLocal8Bit().constData() << " / " << + "Internal: " << serversInternalString.toLocal8Bit().constData() << " / " << + "Leaves: " << serversLeavesString.toLocal8Bit().constData() << ""; statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + unsigned long localTotal = VoxelNode::getNodeCount(); + unsigned long localInternal = VoxelNode::getInternalNodeCount(); + unsigned long localLeaves = VoxelNode::getLeafNodeCount(); + QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); + QString localInternalString = locale.toString((uint)localInternal); + QString localLeavesString = locale.toString((uint)localLeaves); + + // Local Voxels + voxelStats.str(""); + voxelStats << + "Local Voxels Total: " << localTotalString.toLocal8Bit().constData() << " / " << + "Internal: " << localInternalString.toLocal8Bit().constData() << " / " << + "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; + statsVerticalOffset += PELS_PER_LINE; + drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + + // Local Voxel Memory Usage voxelStats.str(""); voxelStats << "Voxels Memory Nodes: " << VoxelNode::getTotalMemoryUsage() / 1000000.f << "MB " @@ -3421,51 +3492,25 @@ void Application::displayStats() { statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - unsigned long localTotal = VoxelNode::getNodeCount(); - unsigned long localInternal = VoxelNode::getInternalNodeCount(); - unsigned long localLeaves = VoxelNode::getLeafNodeCount(); - QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); - QString localInternalString = locale.toString((uint)localInternal); - QString localLeavesString = locale.toString((uint)localLeaves); - - + // Voxel Rendering voxelStats.str(""); - voxelStats << - "Local Voxels Total: " << localTotalString.toLocal8Bit().constData() << " / " << - "Internal: " << localInternalString.toLocal8Bit().constData() << " / " << - "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; + voxelStats.precision(4); + voxelStats << "Voxel Rendering Slots" << + "Max: " << _voxels.getMaxVoxels() / 1000.f << "K " << + "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " << + "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K "; statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - voxelStats.str(""); - char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS); - voxelStats << "Voxels Sent from Server: " << voxelDetails; + // draw Sending mode AFTER server node stats statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - - voxelStats.str(""); - voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED); - voxelStats << "Scene Send Time from Server: " << voxelDetails; - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - - voxelStats.str(""); - voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE); - voxelStats << "Encode Time on Server: " << voxelDetails; - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - - voxelStats.str(""); - voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_MODE); - voxelStats << "Sending Mode: " << voxelDetails; - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)sendingMode.str().c_str()); + // Incoming packets voxelStats.str(""); int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); QString packetsString = locale.toString((int)voxelPacketsToProcess); QString maxString = locale.toString((int)_recentMaxPackets); - voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData() << " [Recent Max: " << maxString.toLocal8Bit().constData() << "]"; @@ -3483,19 +3528,8 @@ void Application::displayStats() { statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - - Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); - char avatarMixerStats[200]; - - if (avatarMixer) { - sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps", - roundf(avatarMixer->getAverageKilobitsPerSecond()), - roundf(avatarMixer->getAveragePacketsPerSecond())); - } else { - sprintf(avatarMixerStats, "No Avatar Mixer"); - } - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarMixerStats); + + // Leap data statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)LeapManager::statusString().c_str()); @@ -4075,6 +4109,10 @@ void Application::domainChanged(QString domain) { // reset the environment so that we don't erroneously end up with multiple _environment.resetToDefault(); + + // reset our node to stats and node to jurisdiction maps... since these must be changing... + _voxelServerJurisdictions.clear(); + _voxelServerSceneStats.clear(); } void Application::nodeAdded(Node* node) { @@ -4101,6 +4139,14 @@ void Application::nodeKilled(Node* node) { fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; _voxelFades.push_back(fade); } + + // If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server + _voxelServerJurisdictions.erase(nodeUUID); + } + + // also clean up scene stats for that server + if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) { + _voxelServerSceneStats.erase(nodeUUID); } } else if (node->getLinkedData() == _lookatTargetAvatar) { _lookatTargetAvatar = NULL; @@ -4109,19 +4155,43 @@ void Application::nodeKilled(Node* node) { int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress) { - // parse the incoming stats data, and stick it into our averaging stats object for now... even though this - // means mixing in stats from potentially multiple servers. - int statsMessageLength = _voxelSceneStats.unpackFromMessage(messageData, messageLength); - // But, also identify the sender, and keep track of the contained jurisdiction root for this server Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); + // parse the incoming stats datas stick it in a temporary object for now, while we + // determine which server it belongs to + VoxelSceneStats temp; + int statsMessageLength = temp.unpackFromMessage(messageData, messageLength); + // quick fix for crash... why would voxelServer be NULL? if (voxelServer) { QUuid nodeUUID = voxelServer->getUUID(); - + + // now that we know the node ID, let's add these stats to the stats for that node... + if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) { + VoxelSceneStats& oldStats = _voxelServerSceneStats[nodeUUID]; + + // this if construct is a little strange because we aren't quite using it yet. But + // we want to keep this logic in here for now because we plan to use it soon to determine + // additional network optimization states and better rate control + if (!oldStats.isMoving() && temp.isMoving()) { + // we think we are starting to move + _voxelServerSceneStats[nodeUUID].unpackFromMessage(messageData, messageLength); + } else if (oldStats.isMoving() && !temp.isMoving()) { + // we think we are done moving + _voxelServerSceneStats[nodeUUID].unpackFromMessage(messageData, messageLength); + } else if (!oldStats.isMoving() && !temp.isMoving()) { + // we think we are still not moving + } else { + // we think we are still moving + } + + } else { + _voxelServerSceneStats[nodeUUID] = temp; + } + VoxelPositionSize rootDetails; - voxelDetailsForCode(_voxelSceneStats.getJurisdictionRoot(), rootDetails); + voxelDetailsForCode(temp.getJurisdictionRoot(), rootDetails); // see if this is the first we've heard of this node... if (_voxelServerJurisdictions.find(nodeUUID) == _voxelServerJurisdictions.end()) { @@ -4142,7 +4212,7 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng // but VoxelSceneStats thinks it's just returning a reference to it's contents. So we need to make a copy of the // details from the VoxelSceneStats to construct the JurisdictionMap JurisdictionMap jurisdictionMap; - jurisdictionMap.copyContents(_voxelSceneStats.getJurisdictionRoot(), _voxelSceneStats.getJurisdictionEndNodes()); + jurisdictionMap.copyContents(temp.getJurisdictionRoot(), temp.getJurisdictionEndNodes()); _voxelServerJurisdictions[nodeUUID] = jurisdictionMap; } return statsMessageLength; diff --git a/interface/src/Application.h b/interface/src/Application.h index 4e370c9c7f..d6814139e1 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -135,7 +135,7 @@ public: QSettings* getSettings() { return _settings; } Swatch* getSwatch() { return &_swatch; } QMainWindow* getWindow() { return _window; } - VoxelSceneStats* getVoxelSceneStats() { return &_voxelSceneStats; } + NodeToVoxelSceneStats* getVoxelSceneStats() { return &_voxelServerSceneStats; } QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } GeometryCache* getGeometryCache() { return &_geometryCache; } @@ -448,10 +448,10 @@ private: PieMenu _pieMenu; - VoxelSceneStats _voxelSceneStats; int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress); NodeToJurisdictionMap _voxelServerJurisdictions; + NodeToVoxelSceneStats _voxelServerSceneStats; std::vector _voxelFades; }; diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h index fad9749776..ee14196188 100644 --- a/interface/src/ui/LodToolsDialog.h +++ b/interface/src/ui/LodToolsDialog.h @@ -13,8 +13,6 @@ #include #include -#include - class LodToolsDialog : public QDialog { Q_OBJECT public: diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index cdc39fc69c..47bcbf4c64 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -14,46 +14,72 @@ #include +#include "Application.h" + #include "ui/VoxelStatsDialog.h" - -VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, VoxelSceneStats* model) : +VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint), _model(model) { + + _statCount = 0; - char strBuf[64]; + for (int i = 0; i < MAX_STATS; i++) { + _labels[i] = NULL; + } this->setWindowTitle("Voxel Statistics"); // Create layouter - QFormLayout* form = new QFormLayout(); - this->QDialog::setLayout(form); + _form = new QFormLayout(); + this->QDialog::setLayout(_form); - // Setup labels - for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { - VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); - VoxelSceneStats::ItemInfo& itemInfo = _model->getItemInfo(item); - QLabel* label = _labels[item] = new QLabel(); + // Setup stat items + _serverVoxels = AddStatItem("Voxels on Servers", GREENISH); + _localVoxels = AddStatItem("Local Voxels", YELLOWISH); + _localVoxelsMemory = AddStatItem("Voxels Memory", GREYISH); + _voxelsRendered = AddStatItem("Voxels Rendered", GREENISH); + _sendingMode = AddStatItem("Sending Mode", YELLOWISH); - // Set foreground color to 62.5% brightness of the meter (otherwise will be hard to read on the bright background) - QPalette palette = label->palette(); - unsigned rgb = itemInfo.colorRGBA >> 8; - const unsigned colorpart1 = 0xfefefeu; - const unsigned colorpart2 = 0xf8f8f8; - rgb = ((rgb & colorpart1) >> 1) + ((rgb & colorpart2) >> 3); - palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb)); - label->setPalette(palette); - - const int STATS_LABEL_WIDTH = 550; - label->setFixedWidth(STATS_LABEL_WIDTH); + /** NOT YET READY + VoxelSceneStats temp; + for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { + VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); + VoxelSceneStats::ItemInfo& itemInfo = temp.getItemInfo(item); + AddStatItem(itemInfo.caption, itemInfo.colorRGBA); + } + **/ +} - snprintf(strBuf, sizeof(strBuf), " %s:", itemInfo.caption); - form->addRow(strBuf, label); - } +int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) { + char strBuf[64]; + const int STATS_LABEL_WIDTH = 550; + + _statCount++; // increment our current stat count + + QLabel* label = _labels[_statCount] = new QLabel(); + + // Set foreground color to 62.5% brightness of the meter (otherwise will be hard to read on the bright background) + QPalette palette = label->palette(); + + // This goofiness came from the bandwidth meter code, it basically stores a color in an unsigned and extracts it + unsigned rgb = colorRGBA >> 8; + const unsigned colorpart1 = 0xfefefeu; + const unsigned colorpart2 = 0xf8f8f8; + rgb = ((rgb & colorpart1) >> 1) + ((rgb & colorpart2) >> 3); + palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb)); + label->setPalette(palette); + + label->setFixedWidth(STATS_LABEL_WIDTH); + + snprintf(strBuf, sizeof(strBuf), " %s:", caption); + _form->addRow(strBuf, label); + + return _statCount; } VoxelStatsDialog::~VoxelStatsDialog() { - for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; ++i) { + for (int i = 0; i < _statCount; i++) { delete _labels[i]; } } @@ -61,16 +87,104 @@ VoxelStatsDialog::~VoxelStatsDialog() { void VoxelStatsDialog::paintEvent(QPaintEvent* event) { // Update labels - char strBuf[256]; - for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { - VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); - QLabel* label = _labels[item]; - snprintf(strBuf, sizeof(strBuf), "%s", _model->getItemValue(item)); - label->setText(strBuf); + + VoxelSystem* voxels = Application::getInstance()->getVoxels(); + QLabel* label; + QLocale locale(QLocale::English); + std::stringstream statsValue; + statsValue.precision(4); + + // Voxels Rendered + label = _labels[_voxelsRendered]; + statsValue << "Max: " << voxels->getMaxVoxels() / 1000.f << "K " << + "Drawn: " << voxels->getVoxelsWritten() / 1000.f << "K " << + "Abandoned: " << voxels->getAbandonedVoxels() / 1000.f << "K " << + "ReadBuffer: " << voxels->getVoxelsRendered() / 1000.f << "K " << + "Changed: " << voxels->getVoxelsUpdated() / 1000.f << "K "; + label->setText(statsValue.str().c_str()); + + // Voxels Memory Usage + label = _labels[_localVoxelsMemory]; + statsValue.str(""); + statsValue << + "Nodes RAM: " << VoxelNode::getTotalMemoryUsage() / 1000000.f << "MB " + "Geometry RAM: " << voxels->getVoxelMemoryUsageRAM() / 1000000.f << "MB " << + "VBO: " << voxels->getVoxelMemoryUsageVBO() / 1000000.f << "MB "; + if (voxels->hasVoxelMemoryUsageGPU()) { + statsValue << "GPU: " << voxels->getVoxelMemoryUsageGPU() / 1000000.f << "MB "; + } + label->setText(statsValue.str().c_str()); + + // Local Voxels + label = _labels[_localVoxels]; + unsigned long localTotal = VoxelNode::getNodeCount(); + unsigned long localInternal = VoxelNode::getInternalNodeCount(); + unsigned long localLeaves = VoxelNode::getLeafNodeCount(); + QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); + QString localInternalString = locale.toString((uint)localInternal); + QString localLeavesString = locale.toString((uint)localLeaves); + + statsValue.str(""); + statsValue << + "Total: " << localTotalString.toLocal8Bit().constData() << " / " << + "Internal: " << localInternalString.toLocal8Bit().constData() << " / " << + "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; + label->setText(statsValue.str().c_str()); + + // iterate all the current voxel stats, and list their sending modes, total their voxels, etc... + std::stringstream sendingMode(""); + + int serverCount = 0; + int movingServerCount = 0; + unsigned long totalNodes = 0; + unsigned long totalInternal = 0; + unsigned long totalLeaves = 0; + NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getVoxelSceneStats(); + for(NodeToVoxelSceneStatsIterator i = sceneStats->begin(); i != sceneStats->end(); i++) { + //const QUuid& uuid = i->first; + VoxelSceneStats& stats = i->second; + serverCount++; + + // calculate server node totals + totalNodes += stats.getTotalVoxels(); + totalInternal += stats.getTotalInternal(); + totalLeaves += stats.getTotalLeaves(); + + // Sending mode + if (serverCount > 1) { + sendingMode << ","; + } + if (stats.isMoving()) { + sendingMode << "M"; + movingServerCount++; + } else { + sendingMode << "S"; + } + } + sendingMode << " - " << serverCount << " servers"; + if (movingServerCount > 0) { + sendingMode << " "; + } else { + sendingMode << " "; } + label = _labels[_sendingMode]; + label->setText(sendingMode.str().c_str()); + + // Server Voxels + QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); + QString serversInternalString = locale.toString((uint)totalInternal); + QString serversLeavesString = locale.toString((uint)totalLeaves); + label = _labels[_serverVoxels]; + statsValue.str(""); + statsValue << + "Total: " << serversTotalString.toLocal8Bit().constData() << " / " << + "Internal: " << serversInternalString.toLocal8Bit().constData() << " / " << + "Leaves: " << serversLeavesString.toLocal8Bit().constData() << ""; + label->setText(statsValue.str().c_str()); + this->QDialog::paintEvent(event); - this->setFixedSize(this->width(), this->height()); + //this->setFixedSize(this->width(), this->height()); } void VoxelStatsDialog::reject() { diff --git a/interface/src/ui/VoxelStatsDialog.h b/interface/src/ui/VoxelStatsDialog.h index 474f65a1e3..b76d4d58dd 100644 --- a/interface/src/ui/VoxelStatsDialog.h +++ b/interface/src/ui/VoxelStatsDialog.h @@ -10,15 +10,18 @@ #define __hifi__VoxelStatsDialog__ #include +#include #include #include +#define MAX_STATS 40 + class VoxelStatsDialog : public QDialog { Q_OBJECT public: // Sets up the UI - VoxelStatsDialog(QWidget* parent, VoxelSceneStats* model); + VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model); ~VoxelStatsDialog(); signals: @@ -34,9 +37,19 @@ protected: // Emits a 'closed' signal when this dialog is closed. void closeEvent(QCloseEvent*); + int AddStatItem(const char* caption, unsigned colorRGBA); + private: - QLabel* _labels[VoxelSceneStats::ITEM_COUNT]; - VoxelSceneStats* _model; + QFormLayout* _form; + QLabel* _labels[MAX_STATS]; + NodeToVoxelSceneStats* _model; + int _statCount; + + int _sendingMode; + int _serverVoxels; + int _localVoxels; + int _localVoxelsMemory; + int _voxelsRendered; }; #endif /* defined(__interface__VoxelStatsDialog__) */ diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h index e8a6bc22d0..9788aafe58 100644 --- a/libraries/shared/src/SimpleMovingAverage.h +++ b/libraries/shared/src/SimpleMovingAverage.h @@ -15,7 +15,7 @@ class SimpleMovingAverage { public: - SimpleMovingAverage(int numSamplesToAverage); + SimpleMovingAverage(int numSamplesToAverage = 100); int updateAverage(float sample); void reset(); @@ -30,8 +30,8 @@ private: float _average; float _eventDeltaAverage; - const float WEIGHTING; - const float ONE_MINUS_WEIGHTING; + float WEIGHTING; + float ONE_MINUS_WEIGHTING; }; #endif /* defined(__hifi__Stats__) */ diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 2cede147b3..c4b36574a0 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -103,6 +103,7 @@ void VoxelNodeData::resetVoxelPacket() { // the clients requested color state. _currentPacketIsColor = (LOW_RES_MONO && getWantLowResMoving() && _viewFrustumChanging) ? false : getWantColor(); PACKET_TYPE voxelPacketType = _currentPacketIsColor ? PACKET_TYPE_VOXEL_DATA : PACKET_TYPE_VOXEL_DATA_MONOCHROME; + int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType); _voxelPacketAt = _voxelPacket + numBytesPacketHeader; _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader; diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 4bfed9c9ad..7f16caa307 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -107,6 +107,7 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), nodeData->getPacket(), nodeData->getPacketLength()); } + nodeData->stats.markAsSent(); } else { // just send the voxel packet NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), diff --git a/libraries/voxels/src/VoxelSceneStats.cpp b/libraries/voxels/src/VoxelSceneStats.cpp index f4570d93a2..cce7d7d7b3 100644 --- a/libraries/voxels/src/VoxelSceneStats.cpp +++ b/libraries/voxels/src/VoxelSceneStats.cpp @@ -7,6 +7,9 @@ // // +#include +#include + #include #include @@ -521,30 +524,26 @@ void VoxelSceneStats::printDebugDetails() { qDebug(" trees removed : %lu\n", _treesRemoved ); } -const unsigned greenish = 0x40ff40d0; -const unsigned yellowish = 0xffef40c0; -const unsigned greyish = 0xd0d0d0a0; - VoxelSceneStats::ItemInfo VoxelSceneStats::_ITEMS[] = { - { "Elapsed" , greenish }, - { "Encode" , yellowish }, - { "Network" , greyish }, - { "Voxels on Server" , greenish }, - { "Voxels Sent" , yellowish }, - { "Colors Sent" , greyish }, - { "Bitmasks Sent" , greenish }, - { "Traversed" , yellowish }, - { "Skipped - Total" , greyish }, - { "Skipped - Distance" , greenish }, - { "Skipped - Out of View", yellowish }, - { "Skipped - Was in View", greyish }, - { "Skipped - No Change" , greenish }, - { "Skipped - Occluded" , yellowish }, - { "Didn't fit in packet" , greyish }, - { "Mode" , greenish }, + { "Elapsed" , GREENISH , 2 , "Elapsed,fps" }, + { "Encode" , YELLOWISH , 2 , "Time,fps" }, + { "Network" , GREYISH , 3 , "Packets,Bytes,KBPS" }, + { "Voxels on Server" , GREENISH , 3 , "Total,Internal,Leaves" }, + { "Voxels Sent" , YELLOWISH , 5 , "Total,Bits/Voxel,Avg Bits/Voxel,Internal,Leaves" }, + { "Colors Sent" , GREYISH , 3 , "Total,Internal,Leaves" }, + { "Bitmasks Sent" , GREENISH , 3 , "Colors,Exists,In Packets" }, + { "Traversed" , YELLOWISH , 3 , "Total,Internal,Leaves" }, + { "Skipped - Total" , GREYISH , 3 , "Total,Internal,Leaves" }, + { "Skipped - Distance" , GREENISH , 3 , "Total,Internal,Leaves" }, + { "Skipped - Out of View", YELLOWISH , 3 , "Total,Internal,Leaves" }, + { "Skipped - Was in View", GREYISH , 3 , "Total,Internal,Leaves" }, + { "Skipped - No Change" , GREENISH , 3 , "Total,Internal,Leaves" }, + { "Skipped - Occluded" , YELLOWISH , 3 , "Total,Internal,Leaves" }, + { "Didn't fit in packet" , GREYISH , 4 , "Total,Internal,Leaves,Removed" }, + { "Mode" , GREENISH , 4 , "Moving,Stationary,Partial,Full" }, }; -char* VoxelSceneStats::getItemValue(Item item) { +const char* VoxelSceneStats::getItemValue(Item item) { const uint64_t USECS_PER_SECOND = 1000 * 1000; int calcFPS, calcAverageFPS, calculatedKBPS; switch(item) { @@ -651,3 +650,4 @@ char* VoxelSceneStats::getItemValue(Item item) { return _itemValueBuffer; } + diff --git a/libraries/voxels/src/VoxelSceneStats.h b/libraries/voxels/src/VoxelSceneStats.h index fe358c686c..c93633fea7 100644 --- a/libraries/voxels/src/VoxelSceneStats.h +++ b/libraries/voxels/src/VoxelSceneStats.h @@ -14,6 +14,10 @@ #include #include "JurisdictionMap.h" +#define GREENISH 0x40ff40d0 +#define YELLOWISH 0xffef40c0 +#define GREYISH 0xd0d0d0a0 + class VoxelNode; /// Collects statistics for calculating and sending a scene from a voxel server to an interface client @@ -114,8 +118,10 @@ public: /// Meta information about each stats item struct ItemInfo { - char const* const caption; - unsigned colorRGBA; + char const* const caption; + unsigned colorRGBA; + int detailsCount; + const char* detailsLabels; }; /// Returns details about items tracked by VoxelSceneStats @@ -124,14 +130,19 @@ public: /// Returns a UI formatted value of an item tracked by VoxelSceneStats /// \param Item item The item from the stats you're interested in. - char* getItemValue(Item item); - + const char* getItemValue(Item item); + /// Returns OctCode for root node of the jurisdiction of this particular voxel server unsigned char* getJurisdictionRoot() const { return _jurisdictionRoot; } /// Returns list of OctCodes for end nodes of the jurisdiction of this particular voxel server const std::vector& getJurisdictionEndNodes() const { return _jurisdictionEndNodes; } + bool isMoving() const { return _isMoving; }; + unsigned long getTotalVoxels() const { return _totalVoxels; } + unsigned long getTotalInternal() const { return _totalInternal; } + unsigned long getTotalLeaves() const { return _totalLeaves; } + private: bool _isReadyToSend; unsigned char _statsMessage[MAX_PACKET_SIZE]; @@ -224,4 +235,9 @@ private: std::vector _jurisdictionEndNodes; }; +/// Map between node IDs and their reported VoxelSceneStats. Typically used by classes that need to know which nodes sent +/// which voxel stats +typedef std::map NodeToVoxelSceneStats; +typedef std::map::iterator NodeToVoxelSceneStatsIterator; + #endif /* defined(__hifi__VoxelSceneStats__) */