first cut at new voxel scene stats

This commit is contained in:
ZappoMan 2013-11-05 10:29:56 -08:00
parent 0fe09aa327
commit 09dab892d3
10 changed files with 464 additions and 89 deletions

View file

@ -3280,6 +3280,13 @@ 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);
voxelStats.str("");
voxelStats <<
"Local Voxels Total: " << VoxelNode::getNodeCount() << ", " <<
@ -3288,29 +3295,71 @@ void Application::displayStats() {
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
// iterate all the current voxel stats, and list their sending modes
voxelStats.str("");
char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
voxelStats << "Voxels Sent from Server: " << voxelDetails;
voxelStats << "Voxel Sending Mode: [";
int serverCount = 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) {
voxelStats << ",";
}
if (stats.isMoving()) {
voxelStats << "M";
} else {
voxelStats << "S";
}
// calculate server node totals
totalNodes += stats.getTotalVoxels();
totalInternal += stats.getTotalInternal();
totalLeaves += stats.getTotalLeaves();
}
if (serverCount == 0) {
voxelStats << "---";
}
voxelStats << "] " << serverCount << " servers";
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' ');
QString serversInternalString = locale.toString((uint)totalInternal);
QString serversLeavesString = locale.toString((uint)totalLeaves);
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());
voxelStats.str("");
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED);
voxelStats << "Scene Send Time from Server: " << voxelDetails;
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() << "]";
if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {
_recentMaxPackets = 0;
_resetRecentMaxPacketsSoon = false;
}
if (voxelPacketsToProcess == 0) {
_resetRecentMaxPacketsSoon = true;
} else {
if (voxelPacketsToProcess > _recentMaxPackets) {
_recentMaxPackets = voxelPacketsToProcess;
}
}
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());
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
char avatarMixerStats[200];
@ -3903,6 +3952,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) {
@ -3918,7 +3971,7 @@ void Application::nodeKilled(Node* node) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
printf("voxel server going away...... v[%f, %f, %f, %f]\n",
printf(">>>>>>>>>>>>>>>> HERE>>>>>>>>> voxel server going away...... v[%f, %f, %f, %f]\n",
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
// Add the jurisditionDetails object to the list of "fade outs"
@ -3927,6 +3980,13 @@ void Application::nodeKilled(Node* node) {
const float slightly_smaller = 0.99;
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
_voxelFades.push_back(fade);
// we should remove it...
_voxelServerJurisdictions.erase(nodeUUID);
}
if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) {
_voxelServerSceneStats.erase(nodeUUID);
}
} else if (node->getLinkedData() == _lookatTargetAvatar) {
_lookatTargetAvatar = NULL;
@ -3935,19 +3995,39 @@ 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 data, and stick it into our averaging stats object for now... even though this
// means mixing in stats from potentially multiple servers.
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];
if (!oldStats.isMoving() && temp.isMoving()) {
_voxelServerSceneStats[nodeUUID].unpackFromMessage(messageData, messageLength);
qDebug() << ">>>>>>>>>> STARTING!!! " << nodeUUID << " <<<<<<<<<<<\n";
} else if (oldStats.isMoving() && !temp.isMoving()) {
_voxelServerSceneStats[nodeUUID].unpackFromMessage(messageData, messageLength);
qDebug() << ">>>>>>>>>> FINISHED!!! " << nodeUUID << " <<<<<<<<<<<\n";
} else if (!oldStats.isMoving() && !temp.isMoving()) {
//qDebug() << ">>>>>>>>>> all still " << nodeUUID << " <<<<<<<<<<<\n";
} else {
qDebug() << ">>>>>>>>>> still moving... " << nodeUUID << " <<<<<<<<<<<\n";
}
} 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()) {
@ -3966,7 +4046,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;

View file

@ -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; }
@ -417,10 +417,10 @@ private:
PieMenu _pieMenu;
VoxelSceneStats _voxelSceneStats;
int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress);
NodeToJurisdictionMap _voxelServerJurisdictions;
NodeToVoxelSceneStats _voxelServerSceneStats;
std::vector<VoxelFade> _voxelFades;
};

View file

@ -13,8 +13,6 @@
#include <QLabel>
#include <QSlider>
#include <VoxelSceneStats.h>
class LodToolsDialog : public QDialog {
Q_OBJECT
public:

View file

@ -14,46 +14,70 @@
#include <VoxelSceneStats.h>
#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);
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 +85,106 @@ 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 " <<
"Rendered: " << voxels->getVoxelsRendered() / 1000.f << "K " <<
"Written: " << voxels->getVoxelsWritten() / 1000.f << "K " <<
"Abandoned: " << voxels->getAbandonedVoxels() / 1000.f << "K " <<
"Updated: " << 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;
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";
} else {
sendingMode << "S";
}
}
sendingMode << " - " << serverCount << " servers";
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());
/**
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() << "]";
**/
this->QDialog::paintEvent(event);
this->setFixedSize(this->width(), this->height());
//this->setFixedSize(this->width(), this->height());
}
void VoxelStatsDialog::reject() {

View file

@ -10,15 +10,18 @@
#define __hifi__VoxelStatsDialog__
#include <QDialog>
#include <QFormLayout>
#include <QLabel>
#include <VoxelSceneStats.h>
#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__) */

View file

@ -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__) */

View file

@ -97,6 +97,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;

View file

@ -88,6 +88,7 @@ void 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(),

View file

@ -7,6 +7,9 @@
//
//
#include <QString>
#include <QStringList>
#include <PacketHeaders.h>
#include <SharedUtil.h>
@ -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,142 @@ char* VoxelSceneStats::getItemValue(Item item) {
return _itemValueBuffer;
}
int VoxelSceneStats::getItemDetailsCount(Item item) {
return _ITEMS[item].detailsCount;
}
float VoxelSceneStats::getItemDetailsValue(Item item, int detailIndex) {
const uint64_t USECS_PER_SECOND = 1000 * 1000;
int calcFPS, calculatedKBPS;
const int MAX_DETAILS_ITEMS = 6;
float items[MAX_DETAILS_ITEMS];
switch(item) {
case ITEM_ELAPSED: {
calcFPS = (float)USECS_PER_SECOND / (float)_elapsed;
items[0] = _elapsed;
items[1] = calcFPS;
break;
}
case ITEM_ENCODE:
calcFPS = (float)USECS_PER_SECOND / (float)_totalEncodeTime;
items[0] = _totalEncodeTime;
items[1] = calcFPS;
break;
case ITEM_PACKETS: {
float elapsedSecs = ((float)_elapsed / (float)USECS_PER_SECOND);
calculatedKBPS = elapsedSecs == 0 ? 0 : ((_bytes * 8) / elapsedSecs) / 1000;
items[0] = _packets;
items[1] = _bytes;
items[2] = calculatedKBPS;
break;
}
case ITEM_VOXELS_SERVER: {
items[0] = _totalVoxels;
items[1] = _totalInternal;
items[2] = _totalLeaves;
break;
}
case ITEM_VOXELS: {
unsigned long total = _existsInPacketBitsWritten + _colorSent;
float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total;
float averageBPV = _bitsPerVoxelAverage.getAverage();
items[0] = total;
items[1] = calculatedBPV;
items[2] = averageBPV;
items[3] = _existsInPacketBitsWritten;
items[4] = _colorSent;
break;
}
case ITEM_TRAVERSED: {
items[0] = _traversed;
items[1] = _internal;
items[2] = _leaves;
break;
}
case ITEM_SKIPPED: {
unsigned long total = _skippedDistance + _skippedOutOfView +
_skippedWasInView + _skippedNoChange + _skippedOccluded;
unsigned long internal = _internalSkippedDistance + _internalSkippedOutOfView +
_internalSkippedWasInView + _internalSkippedNoChange + _internalSkippedOccluded;
unsigned long leaves = _leavesSkippedDistance + _leavesSkippedOutOfView +
_leavesSkippedWasInView + _leavesSkippedNoChange + _leavesSkippedOccluded;
items[0] = total;
items[1] = internal;
items[2] = leaves;
break;
}
case ITEM_SKIPPED_DISTANCE: {
items[0] = _skippedDistance;
items[1] = _internalSkippedDistance;
items[2] = _leavesSkippedDistance;
break;
}
case ITEM_SKIPPED_OUT_OF_VIEW: {
items[0] = _skippedOutOfView;
items[1] = _internalSkippedOutOfView;
items[2] = _leavesSkippedOutOfView;
break;
}
case ITEM_SKIPPED_WAS_IN_VIEW: {
items[0] = _skippedWasInView;
items[1] = _internalSkippedWasInView;
items[2] = _leavesSkippedWasInView;
break;
}
case ITEM_SKIPPED_NO_CHANGE: {
items[0] = _skippedNoChange;
items[1] = _internalSkippedNoChange;
items[2] = _leavesSkippedNoChange;
break;
}
case ITEM_SKIPPED_OCCLUDED: {
items[0] = _skippedOccluded;
items[1] = _internalSkippedOccluded;
items[2] = _leavesSkippedOccluded;
break;
}
case ITEM_COLORS: {
items[0] = _colorSent;
items[1] = _internalColorSent;
items[2] = _leavesColorSent;
break;
}
case ITEM_DIDNT_FIT: {
items[0] = _didntFit;
items[1] = _internalDidntFit;
items[2] = _leavesDidntFit;
items[3] = _treesRemoved;
break;
}
case ITEM_BITS: {
items[0] = _colorBitsWritten;
items[1] = _existsBitsWritten;
items[2] = _existsInPacketBitsWritten;
break;
}
case ITEM_MODE: {
items[0] = _isMoving ? 1.0 : 0.0;
items[1] = !_isMoving ? 1.0 : 0.0;
items[2] = _isFullScene ? 1.0 : 0.0;
items[3] = !_isFullScene ? 1.0 : 0.0;
break;
}
default:
sprintf(_itemValueBuffer, "");
break;
}
return items[detailIndex];
}
const char* VoxelSceneStats::getItemDetailsLabel(Item item, int detailIndex) {
QString labels(_ITEMS[item].detailsLabels);
QStringList labelsList = labels.split(QString(","));
QString label = labelsList.at(detailIndex);
sprintf(_itemValueBuffer, "%s", label.toLocal8Bit().constData());
return _itemValueBuffer;
}

View file

@ -14,6 +14,10 @@
#include <NodeList.h>
#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,7 +130,21 @@ 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 a count of the number of detailed values for an item tracked by VoxelSceneStats
/// \param Item item The item from the stats you're interested in.
int getItemDetailsCount(Item item);
/// The value for the detailed component for an item tracked by VoxelSceneStats
/// \param Item item The item from the stats you're interested in.
/// \param int detailIndex The index for the detailed componet from the stats you're interested in.
float getItemDetailsValue(Item item, int detailIndex);
/// The label for the detailed component for an item tracked by VoxelSceneStats
/// \param Item item The item from the stats you're interested in.
/// \param int detailIndex The index for the detailed componet from the stats you're interested in.
const char* getItemDetailsLabel(Item item, int detailIndex);
/// Returns OctCode for root node of the jurisdiction of this particular voxel server
unsigned char* getJurisdictionRoot() const { return _jurisdictionRoot; }
@ -132,6 +152,11 @@ public:
/// Returns list of OctCodes for end nodes of the jurisdiction of this particular voxel server
const std::vector<unsigned char*>& 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 +249,9 @@ private:
std::vector<unsigned char*> _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<QUuid, VoxelSceneStats> NodeToVoxelSceneStats;
typedef std::map<QUuid, VoxelSceneStats>::iterator NodeToVoxelSceneStatsIterator;
#endif /* defined(__hifi__VoxelSceneStats__) */