342 lines · 13.6 KB · C++
RawDownload
////  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 "OctreeStatsProvider.h" #include "Application.h"#include "Menu.h"#include "octree/OctreePacketProcessor.h" OctreeStatsProvider::OctreeStatsProvider(QObject* parent) :    QObject(parent),    _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() {    showOctreeServersOfType(NodeType::EntityServer);} void OctreeStatsProvider::showOctreeServersOfType(NodeType_t serverType) {    m_servers.clear();    int serverCount = 0;     auto node = DependencyManager::get<NodeList>()->soloNodeOfType(serverType);    if (node) {        ++serverCount;         QString lesserDetails;        QString moreDetails;        QString mostDetails;         if (node->getActiveSocket()) {            lesserDetails += "active ";        } else {            lesserDetails += "inactive ";        }         QUuid nodeUUID = node->getUUID();         // 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);    }     if (serverCount != m_serversNum) {        m_serversNum = serverCount;        emit serversNumChanged(m_serversNum);    }    emit serversChanged(m_servers);}