added more client side voxel stats including lost packets, out of order packets, and average flight time

This commit is contained in:
ZappoMan 2013-11-27 13:37:47 -08:00
parent 21bf10b9bf
commit 7f9d0849bd
7 changed files with 186 additions and 35 deletions

View file

@ -4318,6 +4318,24 @@ void Application::nodeKilled(Node* node) {
}
}
void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength,
sockaddr senderAddress, bool wasStatsPacket) {
// Attempt to identify the sender from it's address.
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
if (voxelServer) {
QUuid nodeUUID = voxelServer->getUUID();
// now that we know the node ID, let's add these stats to the stats for that node...
_voxelSceneStatsLock.lockForWrite();
if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) {
VoxelSceneStats& stats = _voxelServerSceneStats[nodeUUID];
stats.trackIncomingVoxelPacket(messageData, messageLength, wasStatsPacket);
}
_voxelSceneStatsLock.unlock();
}
}
int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress) {
// But, also identify the sender, and keep track of the contained jurisdiction root for this server

View file

@ -465,6 +465,8 @@ private:
PieMenu _pieMenu;
int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress);
void trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength,
sockaddr senderAddress, bool wasStatsPacket);
NodeToJurisdictionMap _voxelServerJurisdictions;
NodeToVoxelSceneStats _voxelServerSceneStats;

View file

@ -25,6 +25,8 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char*
ssize_t messageLength = packetLength;
Application* app = Application::getInstance();
bool wasStatsPacket = false;
// check to see if the UI thread asked us to kill the voxel tree. since we're the only thread allowed to do that
if (app->_wantToKillLocalVoxels) {
@ -38,6 +40,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char*
if (packetData[0] == PACKET_TYPE_VOXEL_STATS) {
int statsMessageLength = app->parseVoxelStats(packetData, messageLength, senderAddress);
wasStatsPacket = true;
if (messageLength > statsMessageLength) {
packetData += statsMessageLength;
messageLength -= statsMessageLength;
@ -50,6 +53,9 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char*
} // fall through to piggyback message
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
app->trackIncomingVoxelPacket(packetData, messageLength, senderAddress, wasStatsPacket);
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {

View file

@ -27,7 +27,7 @@ VoxelStatsDialog::VoxelStatsDialog(QWidget* parent, NodeToVoxelSceneStats* model
for (int i = 0; i < MAX_VOXEL_SERVERS; i++) {
_voxelServerLables[i] = 0;
_extraServerDetails[i] = false;
_extraServerDetails[i] = LESS;
}
for (int i = 0; i < MAX_STATS; i++) {
@ -67,16 +67,20 @@ void VoxelStatsDialog::moreless(const QString& link) {
QString serverNumberString = linkDetails[SERVER_NUMBER_ITEM];
QString command = linkDetails[COMMAND_ITEM];
int serverNumber = serverNumberString.toInt();
if (command == "more") {
_extraServerDetails[serverNumber-1] = true;
_extraServerDetails[serverNumber-1] = MORE;
} else if (command == "most") {
_extraServerDetails[serverNumber-1] = MOST;
} else {
_extraServerDetails[serverNumber-1] = false;
_extraServerDetails[serverNumber-1] = LESS;
}
}
int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) {
char strBuf[64];
const int STATS_LABEL_WIDTH = 600;
_statCount++; // increment our current stat count
@ -98,6 +102,7 @@ int VoxelStatsDialog::AddStatItem(const char* caption, unsigned colorRGBA) {
label->setPalette(palette);
snprintf(strBuf, sizeof(strBuf), " %s:", caption);
_form->addRow(strBuf, label);
label->setFixedWidth(STATS_LABEL_WIDTH);
return _statCount;
}
@ -213,7 +218,6 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) {
showAllVoxelServers();
this->QDialog::paintEvent(event);
//this->setFixedSize(this->width(), this->height());
}
void VoxelStatsDialog::showAllVoxelServers() {
@ -239,6 +243,8 @@ void VoxelStatsDialog::showAllVoxelServers() {
}
std::stringstream serverDetails("");
std::stringstream extraDetails("");
std::stringstream linkDetails("");
if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
serverDetails << "active ";
@ -247,7 +253,6 @@ void VoxelStatsDialog::showAllVoxelServers() {
}
QUuid nodeUUID = node->getUUID();
serverDetails << " " << nodeUUID.toString().toLocal8Bit().constData() << " ";
NodeToJurisdictionMap& voxelServerJurisdictions = Application::getInstance()->getVoxelServerJurisdictions();
@ -280,44 +285,86 @@ void VoxelStatsDialog::showAllVoxelServers() {
} // jurisdiction
// now lookup stats details for this server...
Application::getInstance()->lockVoxelSceneStats();
NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getVoxelSceneStats();
if (sceneStats->find(nodeUUID) != sceneStats->end()) {
VoxelSceneStats& stats = sceneStats->at(nodeUUID);
if (_extraServerDetails[serverNumber-1] != LESS) {
Application::getInstance()->lockVoxelSceneStats();
NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getVoxelSceneStats();
if (sceneStats->find(nodeUUID) != sceneStats->end()) {
VoxelSceneStats& stats = sceneStats->at(nodeUUID);
QString totalString = locale.toString((uint)stats.getTotalVoxels());
QString internalString = locale.toString((uint)stats.getTotalInternal());
QString leavesString = locale.toString((uint)stats.getTotalLeaves());
switch (_extraServerDetails[serverNumber-1]) {
case MOST: {
extraDetails << "<br/>" ;
const unsigned long USECS_PER_MSEC = 1000;
float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC;
float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC;
serverDetails << "<br/>" << "Voxels: " <<
totalString.toLocal8Bit().constData() << " total " <<
internalString.toLocal8Bit().constData() << " internal " <<
leavesString.toLocal8Bit().constData() << " leaves ";
QString lastFullEncodeString = locale.toString(lastFullEncode);
QString lastFullSendString = locale.toString(lastFullSend);
extraDetails << "<br/>" << "Last Full Scene... " <<
"Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " <<
"Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms ";
const unsigned long USECS_PER_MSEC = 1000;
float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC;
float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC;
for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) {
VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i);
VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item);
extraDetails << "<br/>" << itemInfo.caption << " " << stats.getItemValue(item);
}
} // fall through... since MOST has all of MORE
case MORE: {
QString totalString = locale.toString((uint)stats.getTotalVoxels());
QString internalString = locale.toString((uint)stats.getTotalInternal());
QString leavesString = locale.toString((uint)stats.getTotalLeaves());
QString lastFullEncodeString = locale.toString(lastFullEncode);
QString lastFullSendString = locale.toString(lastFullSend);
serverDetails << "<br/>" << "Node UUID: " <<
nodeUUID.toString().toLocal8Bit().constData() << " ";
serverDetails << "<br/>" << "Last Full Scene... " <<
"Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " <<
"Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms ";
serverDetails << "<br/>" << "Voxels: " <<
totalString.toLocal8Bit().constData() << " total " <<
internalString.toLocal8Bit().constData() << " internal " <<
leavesString.toLocal8Bit().constData() << " leaves ";
QString incomingPacketsString = locale.toString((uint)stats.getIncomingPackets());
QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes());
QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes());
QString incomingOutOfOrderString = locale.toString((uint)stats.getIncomingOutOfOrder());
QString incomingLikelyLostString = locale.toString((uint)stats.getIncomingLikelyLost());
QString incomingFlightTimeString = locale.toString(stats.getIncomingFlightTimeAverage());
serverDetails << "<br/>" << "Incoming Packets: " <<
incomingPacketsString.toLocal8Bit().constData() <<
" Out of Order: " << incomingOutOfOrderString.toLocal8Bit().constData() <<
" Likely Lost: " << incomingLikelyLostString.toLocal8Bit().constData();
serverDetails << "<br/>" <<
" Average Flight Time: " << incomingFlightTimeString.toLocal8Bit().constData() << " msecs";
serverDetails << "<br/>" << "Incoming" <<
" Bytes: " << incomingBytesString.toLocal8Bit().constData() <<
" Wasted Bytes: " << incomingWastedBytesString.toLocal8Bit().constData();
serverDetails << extraDetails.str();
if (_extraServerDetails[serverNumber-1] == MORE) {
linkDetails << " " << " [<a href='most-" << serverNumber << "'>most...</a>]";
linkDetails << " " << " [<a href='less-" << serverNumber << "'>less...</a>]";
} else {
linkDetails << " " << " [<a href='more-" << serverNumber << "'>less...</a>]";
linkDetails << " " << " [<a href='less-" << serverNumber << "'>least...</a>]";
}
if (_extraServerDetails[serverNumber-1]) {
for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) {
VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i);
VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item);
serverDetails << "<br/>" << itemInfo.caption << " " << stats.getItemValue(item);
} break;
case LESS: {
// nothing
} break;
}
serverDetails << " " << " [<a href='less-" << serverNumber << "'>less...</a>]";
} else {
serverDetails << " " << " [<a href='more-" << serverNumber << "'>more...</a>]";
}
Application::getInstance()->unlockVoxelSceneStats();
} else {
linkDetails << " " << " [<a href='more-" << serverNumber << "'>more...</a>]";
linkDetails << " " << " [<a href='most-" << serverNumber << "'>most...</a>]";
}
Application::getInstance()->unlockVoxelSceneStats();
serverDetails << linkDetails.str();
_labels[_voxelServerLables[serverCount - 1]]->setText(serverDetails.str().c_str());
} // is VOXEL_SERVER
} // Node Loop

View file

@ -45,6 +45,9 @@ protected:
void showAllVoxelServers();
private:
typedef enum { LESS, MORE, MOST } details;
QFormLayout* _form;
QLabel* _labels[MAX_STATS];
NodeToVoxelSceneStats* _model;
@ -57,7 +60,7 @@ private:
int _voxelsRendered;
int _voxelServerLables[MAX_VOXEL_SERVERS];
int _voxelServerLabelsCount;
bool _extraServerDetails[MAX_VOXEL_SERVERS];
details _extraServerDetails[MAX_VOXEL_SERVERS];
};
#endif /* defined(__interface__VoxelStatsDialog__) */

View file

@ -13,6 +13,7 @@
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include "VoxelPacketData.h"
#include "VoxelNode.h"
#include "VoxelSceneStats.h"
@ -21,6 +22,7 @@ const int samples = 100;
VoxelSceneStats::VoxelSceneStats() :
_elapsedAverage(samples),
_bitsPerVoxelAverage(samples),
_incomingFlightTimeAverage(samples),
_jurisdictionRoot(NULL)
{
reset();
@ -28,6 +30,13 @@ VoxelSceneStats::VoxelSceneStats() :
_isStarted = false;
_lastFullTotalEncodeTime = 0;
_lastFullElapsed = 0;
_incomingPacket = 0;
_incomingBytes = 0;
_incomingWastedBytes = 0;
_incomingLastSequence = 0;
_incomingOutOfOrder = 0;
_incomingLikelyLost = 0;
}
// copy constructor
@ -121,6 +130,13 @@ void VoxelSceneStats::copyFromOther(const VoxelSceneStats& other) {
_jurisdictionEndNodes.push_back(endNodeCodeCopy);
}
}
_incomingPacket = other._incomingPacket;
_incomingBytes = other._incomingBytes;
_incomingWastedBytes = other._incomingWastedBytes;
_incomingLastSequence = other._incomingLastSequence;
_incomingOutOfOrder = other._incomingOutOfOrder;
_incomingLikelyLost = other._incomingLikelyLost;
}
@ -782,4 +798,44 @@ const char* VoxelSceneStats::getItemValue(Item item) {
return _itemValueBuffer;
}
void VoxelSceneStats::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, bool wasStatsPacket) {
_incomingPacket++;
_incomingBytes += messageLength;
if (!wasStatsPacket) {
_incomingWastedBytes += (MAX_PACKET_SIZE - messageLength);
}
int numBytesPacketHeader = numBytesForPacketHeader(messageData);
unsigned char* dataAt = messageData + numBytesPacketHeader;
//VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt));
dataAt += sizeof(VOXEL_PACKET_FLAGS);
VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SEQUENCE);
VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt);
dataAt += sizeof(VOXEL_PACKET_SENT_TIME);
//bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT);
//bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT);
VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
int flightTime = arrivedAt - sentAt;
const int USECS_PER_MSEC = 1000;
float flightTimeMsecs = flightTime / USECS_PER_MSEC;
_incomingFlightTimeAverage.updateAverage(flightTimeMsecs);
// detect out of order packets
if (sequence < _incomingLastSequence) {
_incomingOutOfOrder++;
}
// detect likely lost packets
if (sequence > (_incomingLastSequence+1)) {
_incomingLikelyLost++;
}
_incomingLastSequence = sequence;
}

View file

@ -151,7 +151,17 @@ public:
unsigned long getLastFullTotalEncodeTime() const { return _lastFullTotalEncodeTime; }
unsigned long getLastFullElapsedTime() const { return _lastFullElapsed; }
// Used in client implementations to track individual voxel packets
void trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, bool wasStatsPacket);
unsigned int getIncomingPackets() const { return _incomingPacket; }
unsigned long getIncomingBytes() const { return _incomingBytes; }
unsigned long getIncomingWastedBytes() const { return _incomingWastedBytes; }
unsigned int getIncomingOutOfOrder() const { return _incomingOutOfOrder; }
unsigned int getIncomingLikelyLost() const { return _incomingLikelyLost; }
float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); }
private:
void copyFromOther(const VoxelSceneStats& other);
@ -236,6 +246,15 @@ private:
unsigned long _bytes;
unsigned int _passes;
// incoming packets stats
unsigned int _incomingPacket;
unsigned long _incomingBytes;
unsigned long _incomingWastedBytes;
unsigned int _incomingLastSequence;
unsigned int _incomingOutOfOrder;
unsigned int _incomingLikelyLost;
SimpleMovingAverage _incomingFlightTimeAverage;
// features related items
bool _isMoving;
bool _isFullScene;