mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 03:17:06 +02:00
Merge pull request #9886 from vladest/tablet-ui-entity-statistics
Tablet ui entity statistics
This commit is contained in:
commit
563d59bda9
8 changed files with 845 additions and 1 deletions
244
interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml
Normal file
244
interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml
Normal file
|
@ -0,0 +1,244 @@
|
|||
//
|
||||
// TabletEntityStatistics.qml
|
||||
//
|
||||
// Created by Vlad Stelmahovsky on 3/11/17
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControls
|
||||
import "../../windows"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
objectName: "EntityStatistics"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
property bool isHMD: false
|
||||
|
||||
color: hifi.colors.baseGray
|
||||
|
||||
property int colorScheme: hifi.colorSchemes.dark
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Component.onCompleted: {
|
||||
OctreeStats.startUpdates()
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
OctreeStats.stopUpdates()
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: scrollView
|
||||
width: parent.width
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: hifi.dimensions.tabletMenuHeader
|
||||
contentWidth: column.implicitWidth
|
||||
contentHeight: column.implicitHeight
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: column
|
||||
anchors.margins: 10
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
y: hifi.dimensions.tabletMenuHeader //-bgNavBar
|
||||
spacing: 20
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Elements on Servers:")
|
||||
text: OctreeStats.serverElements
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Local Elements:")
|
||||
text: OctreeStats.localElements
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Elements Memory:")
|
||||
text: OctreeStats.localElementsMemory
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Sending Mode:")
|
||||
text: OctreeStats.sendingMode
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Incoming Entity Packets:")
|
||||
text: OctreeStats.processedPackets
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Processed Packets Elements:")
|
||||
text: OctreeStats.processedPacketsElements
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Processed Packets Entities:")
|
||||
text: OctreeStats.processedPacketsEntities
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Processed Packets Timing:")
|
||||
text: OctreeStats.processedPacketsTiming
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Outbound Entity Packets:")
|
||||
text: OctreeStats.outboundEditPackets
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Entity Update Time:")
|
||||
text: OctreeStats.entityUpdateTime
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
titleText: qsTr("Entity Updates:")
|
||||
text: OctreeStats.entityUpdates
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: OctreeStats.serversNum
|
||||
|
||||
delegate: Column {
|
||||
id: serverColumn
|
||||
width: scrollView.width - 10
|
||||
x: 5
|
||||
spacing: 5
|
||||
|
||||
state: "less"
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
id: serverStats
|
||||
width: parent.width
|
||||
titleText: qsTr("Entity Server ") + (index+1) + ":"
|
||||
colorScheme: root.colorScheme
|
||||
color: OctreeStats.getColor()
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttonsRow
|
||||
width: parent.width
|
||||
height: 30
|
||||
spacing: 10
|
||||
|
||||
HifiControls.Button {
|
||||
id: moreButton
|
||||
color: hifi.buttons.blue
|
||||
colorScheme: root.colorScheme
|
||||
width: parent.width / 2 - 10
|
||||
height: 30
|
||||
onClicked: {
|
||||
if (serverColumn.state === "less") {
|
||||
serverColumn.state = "more"
|
||||
} else if (serverColumn.state === "more") {
|
||||
serverColumn.state = "most"
|
||||
} else {
|
||||
serverColumn.state = "more"
|
||||
}
|
||||
}
|
||||
}
|
||||
HifiControls.Button {
|
||||
id: mostButton
|
||||
color: hifi.buttons.blue
|
||||
colorScheme: root.colorScheme
|
||||
height: 30
|
||||
width: parent.width / 2 - 10
|
||||
onClicked: {
|
||||
if (serverColumn.state === "less") {
|
||||
serverColumn.state = "most"
|
||||
} else if (serverColumn.state === "more") {
|
||||
serverColumn.state = "less"
|
||||
} else {
|
||||
serverColumn.state = "less"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
states: [
|
||||
State {
|
||||
name: "less"
|
||||
PropertyChanges { target: moreButton; text: qsTr("more..."); }
|
||||
PropertyChanges { target: mostButton; text: qsTr("most..."); }
|
||||
PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3]; }
|
||||
},
|
||||
State {
|
||||
name: "more"
|
||||
PropertyChanges { target: moreButton; text: qsTr("most..."); }
|
||||
PropertyChanges { target: mostButton; text: qsTr("less..."); }
|
||||
PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3] +
|
||||
OctreeStats.servers[index*3 + 1]; }
|
||||
},
|
||||
State {
|
||||
name: "most"
|
||||
PropertyChanges { target: moreButton; text: qsTr("less..."); }
|
||||
PropertyChanges { target: mostButton; text: qsTr("least..."); }
|
||||
PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3] +
|
||||
OctreeStats.servers[index*3 + 1] +
|
||||
OctreeStats.servers[index*3 + 2]; }
|
||||
}
|
||||
]
|
||||
} //servers column
|
||||
} //repeater
|
||||
} //column
|
||||
} //flickable
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// TabletEntityStatistics.qml
|
||||
//
|
||||
// Created by Vlad Stelmahovsky on 3/11/17
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControls
|
||||
|
||||
Column {
|
||||
id: root
|
||||
property int colorScheme: hifi.colorSchemes.dark
|
||||
|
||||
property alias titleText: titleLabel.text
|
||||
property alias text: valueLabel.text
|
||||
property alias color: valueLabel.color
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 10
|
||||
|
||||
HifiControls.Label {
|
||||
id: titleLabel
|
||||
size: 20
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
colorScheme: root.colorScheme
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: valueLabel
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
wrapMode: Text.WordWrap
|
||||
size: 16
|
||||
color: enabled ? (root.colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGray : hifi.colors.lightGrayText)
|
||||
: (root.colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight);
|
||||
}
|
||||
}
|
|
@ -173,6 +173,7 @@
|
|||
#include "ui/overlays/Overlays.h"
|
||||
#include "Util.h"
|
||||
#include "InterfaceParentFinder.h"
|
||||
#include "ui/OctreeStatsProvider.h"
|
||||
|
||||
#include "FrameTimingsScriptingInterface.h"
|
||||
#include <GPUIdent.h>
|
||||
|
@ -523,6 +524,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
||||
DependencyManager::set<EntityScriptClient>();
|
||||
DependencyManager::set<EntityScriptServerLogClient>();
|
||||
DependencyManager::set<OctreeStatsProvider>(nullptr, qApp->getOcteeSceneStats());
|
||||
return previousSessionCrashed;
|
||||
}
|
||||
|
||||
|
@ -1807,6 +1809,7 @@ Application::~Application() {
|
|||
DependencyManager::destroy<GeometryCache>();
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
DependencyManager::destroy<OctreeStatsProvider>();
|
||||
|
||||
ResourceManager::cleanup();
|
||||
|
||||
|
@ -6398,6 +6401,18 @@ void Application::loadLODToolsDialog() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
void Application::loadEntityStatisticsDialog() {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||
if (tablet->getToolbarMode() || (!tablet->getTabletRoot() && !isHMDMode())) {
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
dialogsManager->octreeStatsDetails();
|
||||
} else {
|
||||
tablet->pushOntoStack("../../hifi/dialogs/TabletEntityStatistics.qml");
|
||||
}
|
||||
|
||||
}
|
||||
void Application::toggleLogDialog() {
|
||||
if (! _logDialog) {
|
||||
_logDialog = new LogDialog(nullptr, getLogger());
|
||||
|
|
|
@ -404,6 +404,7 @@ public slots:
|
|||
|
||||
Q_INVOKABLE void toggleMuteAudio();
|
||||
void loadLODToolsDialog();
|
||||
void loadEntityStatisticsDialog();
|
||||
|
||||
private slots:
|
||||
void showDesktop();
|
||||
|
|
|
@ -547,8 +547,10 @@ Menu::Menu() {
|
|||
|
||||
// Developer > Entities >>>
|
||||
MenuWrapper* entitiesOptionsMenu = developerMenu->addMenu("Entities");
|
||||
|
||||
addActionToQMenuAndActionHash(entitiesOptionsMenu, MenuOption::OctreeStats, 0,
|
||||
dialogsManager.data(), SLOT(octreeStatsDetails()));
|
||||
qApp, SLOT(loadEntityStatisticsDialog()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(entitiesOptionsMenu, MenuOption::ShowRealtimeEntityStats);
|
||||
|
||||
// Developer > Network >>>
|
||||
|
|
377
interface/src/ui/OctreeStatsProvider.cpp
Normal file
377
interface/src/ui/OctreeStatsProvider.cpp
Normal file
|
@ -0,0 +1,377 @@
|
|||
//
|
||||
// OctreeStatsProvider.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Vlad Stelmahovsky on 3/12/17.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "../octree/OctreePacketProcessor.h"
|
||||
#include "ui/OctreeStatsProvider.h"
|
||||
|
||||
OctreeStatsProvider::OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model) :
|
||||
QObject(parent),
|
||||
_model(model)
|
||||
, _statCount(0)
|
||||
, _averageUpdatesPerSecond(SAMPLES_PER_SECOND)
|
||||
{
|
||||
//schedule updates
|
||||
connect(&_updateTimer, &QTimer::timeout, this, &OctreeStatsProvider::updateOctreeStatsData);
|
||||
_updateTimer.setInterval(100);
|
||||
//timer will be rescheduled on each new timeout
|
||||
_updateTimer.setSingleShot(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start updates statistics
|
||||
*/
|
||||
void OctreeStatsProvider::startUpdates() {
|
||||
_updateTimer.start();
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop updates statistics
|
||||
*/
|
||||
void OctreeStatsProvider::stopUpdates() {
|
||||
_updateTimer.stop();
|
||||
}
|
||||
|
||||
QColor OctreeStatsProvider::getColor() const {
|
||||
static int statIndex = 1;
|
||||
static quint32 rotatingColors[] = { GREENISH, YELLOWISH, GREYISH };
|
||||
quint32 colorRGBA = rotatingColors[statIndex % (sizeof(rotatingColors)/sizeof(rotatingColors[0]))];
|
||||
quint32 rgb = colorRGBA >> 8;
|
||||
const quint32 colorpart1 = 0xfefefeu;
|
||||
const quint32 colorpart2 = 0xf8f8f8;
|
||||
rgb = ((rgb & colorpart1) >> 1) + ((rgb & colorpart2) >> 3);
|
||||
statIndex++;
|
||||
return QColor::fromRgb(rgb);
|
||||
}
|
||||
|
||||
OctreeStatsProvider::~OctreeStatsProvider() {
|
||||
_updateTimer.stop();
|
||||
}
|
||||
|
||||
int OctreeStatsProvider::serversNum() const {
|
||||
return m_serversNum;
|
||||
}
|
||||
|
||||
void OctreeStatsProvider::updateOctreeStatsData() {
|
||||
|
||||
// Processed Entities Related stats
|
||||
auto entities = qApp->getEntities();
|
||||
auto entitiesTree = entities->getTree();
|
||||
|
||||
// Do this ever paint event... even if we don't update
|
||||
auto totalTrackedEdits = entitiesTree->getTotalTrackedEdits();
|
||||
|
||||
const quint64 SAMPLING_WINDOW = USECS_PER_SECOND / SAMPLES_PER_SECOND;
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 sinceLastWindow = now - _lastWindowAt;
|
||||
auto editsInLastWindow = totalTrackedEdits - _lastKnownTrackedEdits;
|
||||
float sinceLastWindowInSeconds = (float)sinceLastWindow / (float)USECS_PER_SECOND;
|
||||
float recentUpdatesPerSecond = (float)editsInLastWindow / sinceLastWindowInSeconds;
|
||||
if (sinceLastWindow > SAMPLING_WINDOW) {
|
||||
_averageUpdatesPerSecond.updateAverage(recentUpdatesPerSecond);
|
||||
_lastWindowAt = now;
|
||||
_lastKnownTrackedEdits = totalTrackedEdits;
|
||||
}
|
||||
|
||||
// Only refresh our stats every once in a while, unless asked for realtime
|
||||
quint64 REFRESH_AFTER = Menu::getInstance()->isOptionChecked(MenuOption::ShowRealtimeEntityStats) ? 0 : USECS_PER_SECOND;
|
||||
quint64 sinceLastRefresh = now - _lastRefresh;
|
||||
if (sinceLastRefresh < REFRESH_AFTER) {
|
||||
_updateTimer.start((REFRESH_AFTER - sinceLastRefresh)/1000);
|
||||
return;
|
||||
}
|
||||
// Only refresh our stats every once in a while, unless asked for realtime
|
||||
//if no realtime, then update once per second. Otherwise consider 60FPS update, ie 16ms interval
|
||||
//int updateinterval = Menu::getInstance()->isOptionChecked(MenuOption::ShowRealtimeEntityStats) ? 16 : 1000;
|
||||
_updateTimer.start(REFRESH_AFTER/1000);
|
||||
|
||||
const int FLOATING_POINT_PRECISION = 3;
|
||||
|
||||
m_localElementsMemory = QString("Elements RAM: %1MB").arg(OctreeElement::getTotalMemoryUsage() / 1000000.0f, 5, 'f', 4);
|
||||
emit localElementsMemoryChanged(m_localElementsMemory);
|
||||
|
||||
// Local Elements
|
||||
m_localElements = QString("Total: %1 / Internal: %2 / Leaves: %3").
|
||||
arg(OctreeElement::getNodeCount()).
|
||||
arg(OctreeElement::getInternalNodeCount()).
|
||||
arg(OctreeElement::getLeafNodeCount());
|
||||
emit localElementsChanged(m_localElements);
|
||||
|
||||
// iterate all the current octree stats, and list their sending modes, total their octree elements, etc...
|
||||
int serverCount = 0;
|
||||
int movingServerCount = 0;
|
||||
unsigned long totalNodes = 0;
|
||||
unsigned long totalInternal = 0;
|
||||
unsigned long totalLeaves = 0;
|
||||
|
||||
m_sendingMode.clear();
|
||||
NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats();
|
||||
sceneStats->withReadLock([&] {
|
||||
for (NodeToOctreeSceneStatsIterator i = sceneStats->begin(); i != sceneStats->end(); i++) {
|
||||
//const QUuid& uuid = i->first;
|
||||
OctreeSceneStats& stats = i->second;
|
||||
serverCount++;
|
||||
|
||||
// calculate server node totals
|
||||
totalNodes += stats.getTotalElements();
|
||||
totalInternal += stats.getTotalInternal();
|
||||
totalLeaves += stats.getTotalLeaves();
|
||||
|
||||
// Sending mode
|
||||
if (serverCount > 1) {
|
||||
m_sendingMode += ",";
|
||||
}
|
||||
if (stats.isMoving()) {
|
||||
m_sendingMode += "M";
|
||||
movingServerCount++;
|
||||
} else {
|
||||
m_sendingMode += "S";
|
||||
}
|
||||
if (stats.isFullScene()) {
|
||||
m_sendingMode += "F";
|
||||
} else {
|
||||
m_sendingMode += "p";
|
||||
}
|
||||
}
|
||||
});
|
||||
m_sendingMode += QString(" - %1 servers").arg(serverCount);
|
||||
if (movingServerCount > 0) {
|
||||
m_sendingMode += " <SCENE NOT STABLE> ";
|
||||
} else {
|
||||
m_sendingMode += " <SCENE STABLE> ";
|
||||
}
|
||||
|
||||
emit sendingModeChanged(m_sendingMode);
|
||||
|
||||
// Server Elements
|
||||
m_serverElements = QString("Total: %1 / Internal: %2 / Leaves: %3").
|
||||
arg(totalNodes).arg(totalInternal).arg(totalLeaves);
|
||||
emit serverElementsChanged(m_serverElements);
|
||||
|
||||
|
||||
// Processed Packets Elements
|
||||
auto averageElementsPerPacket = entities->getAverageElementsPerPacket();
|
||||
auto averageEntitiesPerPacket = entities->getAverageEntitiesPerPacket();
|
||||
|
||||
auto averageElementsPerSecond = entities->getAverageElementsPerSecond();
|
||||
auto averageEntitiesPerSecond = entities->getAverageEntitiesPerSecond();
|
||||
|
||||
auto averageWaitLockPerPacket = entities->getAverageWaitLockPerPacket();
|
||||
auto averageUncompressPerPacket = entities->getAverageUncompressPerPacket();
|
||||
auto averageReadBitstreamPerPacket = entities->getAverageReadBitstreamPerPacket();
|
||||
|
||||
const OctreePacketProcessor& entitiesPacketProcessor = qApp->getOctreePacketProcessor();
|
||||
|
||||
auto incomingPacketsDepth = entitiesPacketProcessor.packetsToProcessCount();
|
||||
auto incomingPPS = entitiesPacketProcessor.getIncomingPPS();
|
||||
auto processedPPS = entitiesPacketProcessor.getProcessedPPS();
|
||||
auto treeProcessedPPS = entities->getAveragePacketsPerSecond();
|
||||
|
||||
m_processedPackets = QString("Queue Size: %1 Packets / Network IN: %2 PPS / Queue OUT: %3 PPS / Tree IN: %4 PPS")
|
||||
.arg(incomingPacketsDepth)
|
||||
.arg(incomingPPS, 5, 'f', FLOATING_POINT_PRECISION)
|
||||
.arg(processedPPS, 5, 'f', FLOATING_POINT_PRECISION)
|
||||
.arg(treeProcessedPPS, 5, 'f', FLOATING_POINT_PRECISION);
|
||||
emit processedPacketsChanged(m_processedPackets);
|
||||
|
||||
m_processedPacketsElements = QString("%1 per packet / %2 per second")
|
||||
.arg(averageElementsPerPacket, 5, 'f', FLOATING_POINT_PRECISION)
|
||||
.arg(averageElementsPerSecond, 5, 'f', FLOATING_POINT_PRECISION);
|
||||
emit processedPacketsElementsChanged(m_processedPacketsElements);
|
||||
|
||||
m_processedPacketsEntities = QString("%1 per packet / %2 per second")
|
||||
.arg(averageEntitiesPerPacket, 5, 'f', FLOATING_POINT_PRECISION)
|
||||
.arg(averageEntitiesPerSecond, 5, 'f', FLOATING_POINT_PRECISION);
|
||||
emit processedPacketsEntitiesChanged(m_processedPacketsEntities);
|
||||
|
||||
m_processedPacketsTiming = QString("Lock Wait: %1 (usecs) / Uncompress: %2 (usecs) / Process: %3 (usecs)")
|
||||
.arg(averageWaitLockPerPacket)
|
||||
.arg(averageUncompressPerPacket)
|
||||
.arg(averageReadBitstreamPerPacket);
|
||||
emit processedPacketsTimingChanged(m_processedPacketsTiming);
|
||||
|
||||
auto entitiesEditPacketSender = qApp->getEntityEditPacketSender();
|
||||
auto outboundPacketsDepth = entitiesEditPacketSender->packetsToSendCount();
|
||||
auto outboundQueuedPPS = entitiesEditPacketSender->getLifetimePPSQueued();
|
||||
auto outboundSentPPS = entitiesEditPacketSender->getLifetimePPS();
|
||||
|
||||
m_outboundEditPackets = QString("Queue Size: %1 packets / Queued IN: %2 PPS / Sent OUT: %3 PPS")
|
||||
.arg(outboundPacketsDepth)
|
||||
.arg(outboundQueuedPPS, 5, 'f', FLOATING_POINT_PRECISION)
|
||||
.arg(outboundSentPPS, 5, 'f', FLOATING_POINT_PRECISION);
|
||||
emit outboundEditPacketsChanged(m_outboundEditPackets);
|
||||
|
||||
// Entity Edits update time
|
||||
auto averageEditDelta = entitiesTree->getAverageEditDeltas();
|
||||
auto maxEditDelta = entitiesTree->getMaxEditDelta();
|
||||
|
||||
m_entityUpdateTime = QString("Average: %1 (usecs) / Max: %2 (usecs)")
|
||||
.arg(averageEditDelta)
|
||||
.arg(maxEditDelta);
|
||||
emit entityUpdateTimeChanged(m_entityUpdateTime);
|
||||
|
||||
// Entity Edits
|
||||
auto bytesPerEdit = entitiesTree->getAverageEditBytes();
|
||||
|
||||
auto updatesPerSecond = _averageUpdatesPerSecond.getAverage();
|
||||
if (updatesPerSecond < 1) {
|
||||
updatesPerSecond = 0; // we don't really care about small updates per second so suppress those
|
||||
}
|
||||
|
||||
m_entityUpdates = QString("%1 updates per second / %2 total updates / Average Size: %3 bytes")
|
||||
.arg(updatesPerSecond, 5, 'f', FLOATING_POINT_PRECISION)
|
||||
.arg(totalTrackedEdits)
|
||||
.arg(bytesPerEdit);
|
||||
emit entityUpdatesChanged(m_entityUpdates);
|
||||
|
||||
updateOctreeServers();
|
||||
}
|
||||
|
||||
void OctreeStatsProvider::updateOctreeServers() {
|
||||
int serverCount = 0;
|
||||
|
||||
showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity",
|
||||
qApp->getEntityServerJurisdictions());
|
||||
if (m_serversNum != serverCount) {
|
||||
m_serversNum = serverCount;
|
||||
emit serversNumChanged(m_serversNum);
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeStatsProvider::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName,
|
||||
NodeToJurisdictionMap& serverJurisdictions) {
|
||||
|
||||
m_servers.clear();
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
|
||||
// only send to the NodeTypes that are NodeType_t_VOXEL_SERVER
|
||||
if (node->getType() == serverType) {
|
||||
serverCount++;
|
||||
|
||||
QString lesserDetails;
|
||||
QString moreDetails;
|
||||
QString mostDetails;
|
||||
|
||||
if (node->getActiveSocket()) {
|
||||
lesserDetails += "active ";
|
||||
} else {
|
||||
lesserDetails += "inactive ";
|
||||
}
|
||||
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
|
||||
// lookup our nodeUUID in the jurisdiction map, if it's missing then we're
|
||||
// missing at least one jurisdiction
|
||||
serverJurisdictions.withReadLock([&] {
|
||||
if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) {
|
||||
lesserDetails += " unknown jurisdiction ";
|
||||
return;
|
||||
}
|
||||
const JurisdictionMap& map = serverJurisdictions[nodeUUID];
|
||||
|
||||
auto rootCode = map.getRootOctalCode();
|
||||
|
||||
if (rootCode) {
|
||||
QString rootCodeHex = octalCodeToHexString(rootCode.get());
|
||||
|
||||
VoxelPositionSize rootDetails;
|
||||
voxelDetailsForCode(rootCode.get(), rootDetails);
|
||||
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
|
||||
lesserDetails += QString(" jurisdiction: %1 [%2, %3, %4: %5]")
|
||||
.arg(rootCodeHex)
|
||||
.arg(rootDetails.x)
|
||||
.arg(rootDetails.y)
|
||||
.arg(rootDetails.z)
|
||||
.arg(rootDetails.s);
|
||||
} else {
|
||||
lesserDetails += " jurisdiction has no rootCode";
|
||||
} // root code
|
||||
});
|
||||
|
||||
// now lookup stats details for this server...
|
||||
NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats();
|
||||
sceneStats->withReadLock([&] {
|
||||
if (sceneStats->find(nodeUUID) != sceneStats->end()) {
|
||||
OctreeSceneStats& stats = sceneStats->at(nodeUUID);
|
||||
|
||||
float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC;
|
||||
float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC;
|
||||
float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND;
|
||||
float lastFullPackets = stats.getLastFullTotalPackets();
|
||||
float lastFullPPS = lastFullPackets;
|
||||
if (lastFullSendInSeconds > 0) {
|
||||
lastFullPPS = lastFullPackets / lastFullSendInSeconds;
|
||||
}
|
||||
|
||||
mostDetails += QString("<br/><br/>Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS")
|
||||
.arg(lastFullEncode)
|
||||
.arg(lastFullSend)
|
||||
.arg(lastFullPackets)
|
||||
.arg(stats.getLastFullTotalBytes())
|
||||
.arg(lastFullPPS);
|
||||
|
||||
for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) {
|
||||
OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i);
|
||||
OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item);
|
||||
mostDetails += QString("<br/> %1 %2")
|
||||
.arg(itemInfo.caption).arg(stats.getItemValue(item));
|
||||
}
|
||||
|
||||
moreDetails += "<br/>Node UUID: " +nodeUUID.toString() + " ";
|
||||
|
||||
moreDetails += QString("<br/>Elements: %1 total %2 internal %3 leaves ")
|
||||
.arg(stats.getTotalElements())
|
||||
.arg(stats.getTotalInternal())
|
||||
.arg(stats.getTotalLeaves());
|
||||
|
||||
const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats();
|
||||
qint64 clockSkewInUsecs = node->getClockSkewUsec();
|
||||
qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC;
|
||||
|
||||
moreDetails += QString("<br/>Incoming Packets: %1/ Lost: %2/ Recovered: %3")
|
||||
.arg(stats.getIncomingPackets())
|
||||
.arg(seqStats.getLost())
|
||||
.arg(seqStats.getRecovered());
|
||||
|
||||
moreDetails += QString("<br/> Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4")
|
||||
.arg(seqStats.getOutOfOrder())
|
||||
.arg(seqStats.getEarly())
|
||||
.arg(seqStats.getLate())
|
||||
.arg(seqStats.getUnreasonable());
|
||||
|
||||
moreDetails += QString("<br/> Average Flight Time: %1 msecs")
|
||||
.arg(stats.getIncomingFlightTimeAverage());
|
||||
|
||||
moreDetails += QString("<br/> Average Ping Time: %1 msecs")
|
||||
.arg(node->getPingMs());
|
||||
|
||||
moreDetails += QString("<br/> Average Clock Skew: %1 msecs [%2]")
|
||||
.arg(clockSkewInMS)
|
||||
.arg(formatUsecTime(clockSkewInUsecs));
|
||||
|
||||
|
||||
moreDetails += QString("<br/>Incoming Bytes: %1 Wasted Bytes: %2")
|
||||
.arg(stats.getIncomingBytes())
|
||||
.arg(stats.getIncomingWastedBytes());
|
||||
}
|
||||
});
|
||||
m_servers.append(lesserDetails);
|
||||
m_servers.append(moreDetails);
|
||||
m_servers.append(mostDetails);
|
||||
} // is VOXEL_SERVER
|
||||
});
|
||||
emit serversChanged(m_servers);
|
||||
}
|
||||
|
||||
|
154
interface/src/ui/OctreeStatsProvider.h
Normal file
154
interface/src/ui/OctreeStatsProvider.h
Normal file
|
@ -0,0 +1,154 @@
|
|||
//
|
||||
// OctreeStatsProvider.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Vlad Stelmahovsky on 3/12/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_OctreeStatsProvider_h
|
||||
#define hifi_OctreeStatsProvider_h
|
||||
|
||||
#include <OctreeSceneStats.h>
|
||||
#include <QTimer>
|
||||
#include <QColor>
|
||||
|
||||
#include "DependencyManager.h"
|
||||
|
||||
#define MAX_STATS 100
|
||||
#define MAX_VOXEL_SERVERS 50
|
||||
#define DEFAULT_COLOR 0
|
||||
|
||||
class OctreeStatsProvider : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
Q_PROPERTY(int serversNum READ serversNum NOTIFY serversNumChanged)
|
||||
Q_PROPERTY(QString serverElements READ serverElements NOTIFY serverElementsChanged)
|
||||
Q_PROPERTY(QString localElements READ localElements NOTIFY localElementsChanged)
|
||||
Q_PROPERTY(QString localElementsMemory READ localElementsMemory NOTIFY localElementsMemoryChanged)
|
||||
Q_PROPERTY(QString sendingMode READ sendingMode NOTIFY sendingModeChanged)
|
||||
Q_PROPERTY(QString processedPackets READ processedPackets NOTIFY processedPacketsChanged)
|
||||
Q_PROPERTY(QString processedPacketsElements READ processedPacketsElements NOTIFY processedPacketsElementsChanged)
|
||||
Q_PROPERTY(QString processedPacketsEntities READ processedPacketsEntities NOTIFY processedPacketsEntitiesChanged)
|
||||
Q_PROPERTY(QString processedPacketsTiming READ processedPacketsTiming NOTIFY processedPacketsTimingChanged)
|
||||
Q_PROPERTY(QString outboundEditPackets READ outboundEditPackets NOTIFY outboundEditPacketsChanged)
|
||||
Q_PROPERTY(QString entityUpdateTime READ entityUpdateTime NOTIFY entityUpdateTimeChanged)
|
||||
Q_PROPERTY(QString entityUpdates READ entityUpdates NOTIFY entityUpdatesChanged)
|
||||
|
||||
Q_PROPERTY(QStringList servers READ servers NOTIFY serversChanged)
|
||||
|
||||
public:
|
||||
OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model);
|
||||
~OctreeStatsProvider();
|
||||
|
||||
int serversNum() const;
|
||||
|
||||
QString serverElements() const {
|
||||
return m_serverElements;
|
||||
}
|
||||
|
||||
QString localElements() const {
|
||||
return m_localElements;
|
||||
}
|
||||
|
||||
QString localElementsMemory() const {
|
||||
return m_localElementsMemory;
|
||||
}
|
||||
|
||||
QString sendingMode() const {
|
||||
return m_sendingMode;
|
||||
}
|
||||
|
||||
QString processedPackets() const {
|
||||
return m_processedPackets;
|
||||
}
|
||||
|
||||
QString processedPacketsElements() const {
|
||||
return m_processedPacketsElements;
|
||||
}
|
||||
|
||||
QString processedPacketsEntities() const {
|
||||
return m_processedPacketsEntities;
|
||||
}
|
||||
|
||||
QString processedPacketsTiming() const {
|
||||
return m_processedPacketsTiming;
|
||||
}
|
||||
|
||||
QString outboundEditPackets() const {
|
||||
return m_outboundEditPackets;
|
||||
}
|
||||
|
||||
QString entityUpdateTime() const {
|
||||
return m_entityUpdateTime;
|
||||
}
|
||||
|
||||
QString entityUpdates() const {
|
||||
return m_entityUpdates;
|
||||
}
|
||||
|
||||
QStringList servers() const {
|
||||
return m_servers;
|
||||
}
|
||||
|
||||
signals:
|
||||
|
||||
void serversNumChanged(int serversNum);
|
||||
void serverElementsChanged(const QString &serverElements);
|
||||
void localElementsChanged(const QString &localElements);
|
||||
void sendingModeChanged(const QString &sendingMode);
|
||||
void processedPacketsChanged(const QString &processedPackets);
|
||||
void localElementsMemoryChanged(const QString &localElementsMemory);
|
||||
void processedPacketsElementsChanged(const QString &processedPacketsElements);
|
||||
void processedPacketsEntitiesChanged(const QString &processedPacketsEntities);
|
||||
void processedPacketsTimingChanged(const QString &processedPacketsTiming);
|
||||
void outboundEditPacketsChanged(const QString &outboundEditPackets);
|
||||
void entityUpdateTimeChanged(const QString &entityUpdateTime);
|
||||
void entityUpdatesChanged(const QString &entityUpdates);
|
||||
|
||||
void serversChanged(const QStringList &servers);
|
||||
|
||||
public slots:
|
||||
void startUpdates();
|
||||
void stopUpdates();
|
||||
QColor getColor() const;
|
||||
|
||||
private slots:
|
||||
void updateOctreeStatsData();
|
||||
protected:
|
||||
void updateOctreeServers();
|
||||
void showOctreeServersOfType(int& serverNumber, NodeType_t serverType,
|
||||
const char* serverTypeName, NodeToJurisdictionMap& serverJurisdictions);
|
||||
|
||||
private:
|
||||
NodeToOctreeSceneStats* _model;
|
||||
int _statCount;
|
||||
|
||||
const int SAMPLES_PER_SECOND = 10;
|
||||
SimpleMovingAverage _averageUpdatesPerSecond;
|
||||
quint64 _lastWindowAt = usecTimestampNow();
|
||||
quint64 _lastKnownTrackedEdits = 0;
|
||||
|
||||
quint64 _lastRefresh = 0;
|
||||
|
||||
QTimer _updateTimer;
|
||||
int m_serversNum {0};
|
||||
QString m_serverElements;
|
||||
QString m_localElements;
|
||||
QString m_localElementsMemory;
|
||||
QString m_sendingMode;
|
||||
QString m_processedPackets;
|
||||
QString m_processedPacketsElements;
|
||||
QString m_processedPacketsEntities;
|
||||
QString m_processedPacketsTiming;
|
||||
QString m_outboundEditPackets;
|
||||
QString m_entityUpdateTime;
|
||||
QString m_entityUpdates;
|
||||
QStringList m_servers;
|
||||
};
|
||||
|
||||
#endif // hifi_OctreeStatsProvider_h
|
|
@ -44,6 +44,7 @@
|
|||
#include "avatar/AvatarManager.h"
|
||||
#include "AudioClient.h"
|
||||
#include "LODManager.h"
|
||||
#include "ui/OctreeStatsProvider.h"
|
||||
|
||||
static const float DPI = 30.47f;
|
||||
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
||||
|
@ -185,6 +186,7 @@ void Web3DOverlay::loadSourceURL() {
|
|||
_webSurface->getRootContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("pathToFonts", "../../");
|
||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());
|
||||
|
||||
|
|
Loading…
Reference in a new issue