mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-05 06:05:31 +02:00
added more client side voxel stats including lost packets, out of order packets, and average flight time
This commit is contained in:
parent
21bf10b9bf
commit
7f9d0849bd
7 changed files with 186 additions and 35 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue