mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 13:58:51 +02:00
Merge pull request #8879 from AndrewMeadows/show-physics-stats
add Bullet profile info to PerformanceTimer stats
This commit is contained in:
commit
9846614468
8 changed files with 86 additions and 19 deletions
|
@ -3969,8 +3969,6 @@ void Application::update(float deltaTime) {
|
||||||
auto collisionEvents = _physicsEngine->getCollisionEvents();
|
auto collisionEvents = _physicsEngine->getCollisionEvents();
|
||||||
avatarManager->handleCollisionEvents(collisionEvents);
|
avatarManager->handleCollisionEvents(collisionEvents);
|
||||||
|
|
||||||
_physicsEngine->dumpStatsIfNecessary();
|
|
||||||
|
|
||||||
if (!_aboutToQuit) {
|
if (!_aboutToQuit) {
|
||||||
PerformanceTimer perfTimer("entities");
|
PerformanceTimer perfTimer("entities");
|
||||||
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
|
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
|
||||||
|
@ -3983,6 +3981,13 @@ void Application::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
|
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
|
||||||
|
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
|
||||||
|
_physicsEngine->harvestPerformanceStats();
|
||||||
|
}
|
||||||
|
// NOTE: the PhysicsEngine stats are written to stdout NOT to Qt log framework
|
||||||
|
_physicsEngine->dumpStatsIfNecessary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -605,6 +605,7 @@ Menu::Menu() {
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandOtherAvatarTiming, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandOtherAvatarTiming, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false);
|
||||||
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPhysicsSimulationTiming, 0, false);
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer);
|
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer);
|
||||||
addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, qApp, SLOT(runTests()));
|
addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, qApp, SLOT(runTests()));
|
||||||
|
|
|
@ -104,6 +104,7 @@ namespace MenuOption {
|
||||||
const QString ExpandMyAvatarTiming = "Expand /myAvatar";
|
const QString ExpandMyAvatarTiming = "Expand /myAvatar";
|
||||||
const QString ExpandOtherAvatarTiming = "Expand /otherAvatar";
|
const QString ExpandOtherAvatarTiming = "Expand /otherAvatar";
|
||||||
const QString ExpandPaintGLTiming = "Expand /paintGL";
|
const QString ExpandPaintGLTiming = "Expand /paintGL";
|
||||||
|
const QString ExpandPhysicsSimulationTiming = "Expand /physics";
|
||||||
const QString ExpandUpdateTiming = "Expand /update";
|
const QString ExpandUpdateTiming = "Expand /update";
|
||||||
const QString Faceshift = "Faceshift";
|
const QString Faceshift = "Faceshift";
|
||||||
const QString FirstPerson = "First Person";
|
const QString FirstPerson = "First Person";
|
||||||
|
|
|
@ -55,7 +55,9 @@ Stats::Stats(QQuickItem* parent) : QQuickItem(parent) {
|
||||||
bool Stats::includeTimingRecord(const QString& name) {
|
bool Stats::includeTimingRecord(const QString& name) {
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
|
||||||
if (name.startsWith("/idle/update/")) {
|
if (name.startsWith("/idle/update/")) {
|
||||||
if (name.startsWith("/idle/update/myAvatar/")) {
|
if (name.startsWith("/idle/update/physics/")) {
|
||||||
|
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming);
|
||||||
|
} else if (name.startsWith("/idle/update/myAvatar/")) {
|
||||||
if (name.startsWith("/idle/update/myAvatar/simulate/")) {
|
if (name.startsWith("/idle/update/myAvatar/simulate/")) {
|
||||||
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandMyAvatarSimulateTiming);
|
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandMyAvatarSimulateTiming);
|
||||||
}
|
}
|
||||||
|
@ -369,7 +371,7 @@ void Stats::updateStats(bool force) {
|
||||||
QString functionName = j.value();
|
QString functionName = j.value();
|
||||||
const PerformanceTimerRecord& record = allRecords.value(functionName);
|
const PerformanceTimerRecord& record = allRecords.value(functionName);
|
||||||
perfLines += QString("%1: %2 [%3]\n").
|
perfLines += QString("%1: %2 [%3]\n").
|
||||||
arg(QString(qPrintable(functionName)), 90, noBreakingSpace).
|
arg(QString(qPrintable(functionName)), -80, noBreakingSpace).
|
||||||
arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace).
|
arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace).
|
||||||
arg((int)record.getCount(), 6, 10, noBreakingSpace);
|
arg((int)record.getCount(), 6, 10, noBreakingSpace);
|
||||||
linesDisplayed++;
|
linesDisplayed++;
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <PhysicsCollisionGroups.h>
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
|
||||||
|
#include <PerfStat.h>
|
||||||
|
|
||||||
#include "CharacterController.h"
|
#include "CharacterController.h"
|
||||||
#include "ObjectMotionState.h"
|
#include "ObjectMotionState.h"
|
||||||
#include "PhysicsEngine.h"
|
#include "PhysicsEngine.h"
|
||||||
|
@ -286,6 +288,47 @@ void PhysicsEngine::stepSimulation() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhysicsEngine::harvestPerformanceStats() {
|
||||||
|
// unfortunately the full context names get too long for our stats presentation format
|
||||||
|
//QString contextName = PerformanceTimer::getContextName(); // TODO: how to show full context name?
|
||||||
|
QString contextName("...");
|
||||||
|
|
||||||
|
CProfileIterator* profileIterator = CProfileManager::Get_Iterator();
|
||||||
|
if (profileIterator) {
|
||||||
|
// hunt for stepSimulation context
|
||||||
|
profileIterator->First();
|
||||||
|
for (int32_t childIndex = 0; !profileIterator->Is_Done(); ++childIndex) {
|
||||||
|
if (QString(profileIterator->Get_Current_Name()) == "stepSimulation") {
|
||||||
|
profileIterator->Enter_Child(childIndex);
|
||||||
|
recursivelyHarvestPerformanceStats(profileIterator, contextName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
profileIterator->Next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsEngine::recursivelyHarvestPerformanceStats(CProfileIterator* profileIterator, QString contextName) {
|
||||||
|
QString parentContextName = contextName + QString("/") + QString(profileIterator->Get_Current_Parent_Name());
|
||||||
|
// get the stats for the children
|
||||||
|
int32_t numChildren = 0;
|
||||||
|
profileIterator->First();
|
||||||
|
while (!profileIterator->Is_Done()) {
|
||||||
|
QString childContextName = parentContextName + QString("/") + QString(profileIterator->Get_Current_Name());
|
||||||
|
uint64_t time = (uint64_t)((btScalar)MSECS_PER_SECOND * profileIterator->Get_Current_Total_Time());
|
||||||
|
PerformanceTimer::addTimerRecord(childContextName, time);
|
||||||
|
profileIterator->Next();
|
||||||
|
++numChildren;
|
||||||
|
}
|
||||||
|
// recurse the children
|
||||||
|
for (int32_t i = 0; i < numChildren; ++i) {
|
||||||
|
profileIterator->Enter_Child(i);
|
||||||
|
recursivelyHarvestPerformanceStats(profileIterator, contextName);
|
||||||
|
}
|
||||||
|
// retreat back to parent
|
||||||
|
profileIterator->Enter_Parent();
|
||||||
|
}
|
||||||
|
|
||||||
void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) {
|
void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) {
|
||||||
BT_PROFILE("ownershipInfection");
|
BT_PROFILE("ownershipInfection");
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
void reinsertObject(ObjectMotionState* object);
|
void reinsertObject(ObjectMotionState* object);
|
||||||
|
|
||||||
void stepSimulation();
|
void stepSimulation();
|
||||||
|
void harvestPerformanceStats();
|
||||||
void updateContactMap();
|
void updateContactMap();
|
||||||
|
|
||||||
bool hasOutgoingChanges() const { return _hasOutgoingChanges; }
|
bool hasOutgoingChanges() const { return _hasOutgoingChanges; }
|
||||||
|
@ -89,6 +90,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addObjectToDynamicsWorld(ObjectMotionState* motionState);
|
void addObjectToDynamicsWorld(ObjectMotionState* motionState);
|
||||||
|
void recursivelyHarvestPerformanceStats(CProfileIterator* profileIterator, QString contextName);
|
||||||
|
|
||||||
/// \brief bump any objects that touch this one, then remove contact info
|
/// \brief bump any objects that touch this one, then remove contact info
|
||||||
void bumpAndPruneContacts(ObjectMotionState* motionState);
|
void bumpAndPruneContacts(ObjectMotionState* motionState);
|
||||||
|
|
|
@ -31,8 +31,8 @@ bool PerformanceWarning::_suppressShortTimings = false;
|
||||||
// Destructor handles recording all of our stats
|
// Destructor handles recording all of our stats
|
||||||
PerformanceWarning::~PerformanceWarning() {
|
PerformanceWarning::~PerformanceWarning() {
|
||||||
quint64 end = usecTimestampNow();
|
quint64 end = usecTimestampNow();
|
||||||
quint64 elapsedusec = (end - _start);
|
quint64 elapsedUsec = (end - _start);
|
||||||
double elapsedmsec = elapsedusec / 1000.0;
|
double elapsedmsec = elapsedUsec / 1000.0;
|
||||||
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
double elapsedsec = (end - _start) / 1000000.0;
|
double elapsedsec = (end - _start) / 1000000.0;
|
||||||
|
@ -53,7 +53,7 @@ PerformanceWarning::~PerformanceWarning() {
|
||||||
}
|
}
|
||||||
// if the caller gave us a pointer to store the running total, track it now.
|
// if the caller gave us a pointer to store the running total, track it now.
|
||||||
if (_runningTotal) {
|
if (_runningTotal) {
|
||||||
*_runningTotal += elapsedusec;
|
*_runningTotal += elapsedUsec;
|
||||||
}
|
}
|
||||||
if (_totalCalls) {
|
if (_totalCalls) {
|
||||||
*_totalCalls += 1;
|
*_totalCalls += 1;
|
||||||
|
@ -65,11 +65,11 @@ PerformanceWarning::~PerformanceWarning() {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
const quint64 STALE_STAT_PERIOD = 4 * USECS_PER_SECOND;
|
const quint64 STALE_STAT_PERIOD = 4 * USECS_PER_SECOND;
|
||||||
|
|
||||||
void PerformanceTimerRecord::tallyResult(const quint64& now) {
|
void PerformanceTimerRecord::tallyResult(const quint64& now) {
|
||||||
if (_numAccumulations > 0) {
|
if (_numAccumulations > 0) {
|
||||||
_numTallies++;
|
_numTallies++;
|
||||||
_movingAverage.updateAverage(_runningTotal - _lastTotal);
|
_movingAverage.updateAverage(_runningTotal - _lastTotal);
|
||||||
_lastTotal = _runningTotal;
|
_lastTotal = _runningTotal;
|
||||||
_numAccumulations = 0;
|
_numAccumulations = 0;
|
||||||
_expiry = now + STALE_STAT_PERIOD;
|
_expiry = now + STALE_STAT_PERIOD;
|
||||||
}
|
}
|
||||||
|
@ -96,10 +96,10 @@ PerformanceTimer::PerformanceTimer(const QString& name) {
|
||||||
|
|
||||||
PerformanceTimer::~PerformanceTimer() {
|
PerformanceTimer::~PerformanceTimer() {
|
||||||
if (_isActive && _start != 0) {
|
if (_isActive && _start != 0) {
|
||||||
quint64 elapsedusec = (usecTimestampNow() - _start);
|
quint64 elapsedUsec = (usecTimestampNow() - _start);
|
||||||
QString& fullName = _fullNames[QThread::currentThread()];
|
QString& fullName = _fullNames[QThread::currentThread()];
|
||||||
PerformanceTimerRecord& namedRecord = _records[fullName];
|
PerformanceTimerRecord& namedRecord = _records[fullName];
|
||||||
namedRecord.accumulateResult(elapsedusec);
|
namedRecord.accumulateResult(elapsedUsec);
|
||||||
fullName.resize(fullName.size() - (_name.size() + 1));
|
fullName.resize(fullName.size() - (_name.size() + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,17 @@ bool PerformanceTimer::isActive() {
|
||||||
return _isActive;
|
return _isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
QString PerformanceTimer::getContextName() {
|
||||||
|
return _fullNames[QThread::currentThread()];
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void PerformanceTimer::addTimerRecord(const QString& fullName, quint64 elapsedUsec) {
|
||||||
|
PerformanceTimerRecord& namedRecord = _records[fullName];
|
||||||
|
namedRecord.accumulateResult(elapsedUsec);
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void PerformanceTimer::setActive(bool active) {
|
void PerformanceTimer::setActive(bool active) {
|
||||||
if (active != _isActive) {
|
if (active != _isActive) {
|
||||||
|
@ -117,7 +128,7 @@ void PerformanceTimer::setActive(bool active) {
|
||||||
_fullNames.clear();
|
_fullNames.clear();
|
||||||
_records.clear();
|
_records.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "PerformanceTimer has been turned" << ((active) ? "on" : "off");
|
qDebug() << "PerformanceTimer has been turned" << ((active) ? "on" : "off");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +153,7 @@ void PerformanceTimer::dumpAllTimerRecords() {
|
||||||
QMapIterator<QString, PerformanceTimerRecord> i(_records);
|
QMapIterator<QString, PerformanceTimerRecord> i(_records);
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
i.next();
|
i.next();
|
||||||
qCDebug(shared) << i.key() << ": average " << i.value().getAverage()
|
qCDebug(shared) << i.key() << ": average " << i.value().getAverage()
|
||||||
<< " [" << i.value().getMovingAverage() << "]"
|
<< " [" << i.value().getMovingAverage() << "]"
|
||||||
<< "usecs over" << i.value().getCount() << "calls";
|
<< "usecs over" << i.value().getCount() << "calls";
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
_alwaysDisplay(alwaysDisplay),
|
_alwaysDisplay(alwaysDisplay),
|
||||||
_runningTotal(runningTotal),
|
_runningTotal(runningTotal),
|
||||||
_totalCalls(totalCalls) { }
|
_totalCalls(totalCalls) { }
|
||||||
|
|
||||||
quint64 elapsed() const { return (usecTimestampNow() - _start); };
|
quint64 elapsed() const { return (usecTimestampNow() - _start); };
|
||||||
|
|
||||||
~PerformanceWarning();
|
~PerformanceWarning();
|
||||||
|
@ -56,14 +56,14 @@ public:
|
||||||
class PerformanceTimerRecord {
|
class PerformanceTimerRecord {
|
||||||
public:
|
public:
|
||||||
PerformanceTimerRecord() : _runningTotal(0), _lastTotal(0), _numAccumulations(0), _numTallies(0), _expiry(0) {}
|
PerformanceTimerRecord() : _runningTotal(0), _lastTotal(0), _numAccumulations(0), _numTallies(0), _expiry(0) {}
|
||||||
|
|
||||||
void accumulateResult(const quint64& elapsed) { _runningTotal += elapsed; ++_numAccumulations; }
|
void accumulateResult(const quint64& elapsed) { _runningTotal += elapsed; ++_numAccumulations; }
|
||||||
void tallyResult(const quint64& now);
|
void tallyResult(const quint64& now);
|
||||||
bool isStale(const quint64& now) const { return now > _expiry; }
|
bool isStale(const quint64& now) const { return now > _expiry; }
|
||||||
quint64 getAverage() const { return (_numTallies == 0) ? 0 : _runningTotal / _numTallies; }
|
quint64 getAverage() const { return (_numTallies == 0) ? 0 : _runningTotal / _numTallies; }
|
||||||
quint64 getMovingAverage() const { return (_numTallies == 0) ? 0 : _movingAverage.getAverage(); }
|
quint64 getMovingAverage() const { return (_numTallies == 0) ? 0 : _movingAverage.getAverage(); }
|
||||||
quint64 getCount() const { return _numTallies; }
|
quint64 getCount() const { return _numTallies; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint64 _runningTotal;
|
quint64 _runningTotal;
|
||||||
quint64 _lastTotal;
|
quint64 _lastTotal;
|
||||||
|
@ -81,7 +81,9 @@ public:
|
||||||
|
|
||||||
static bool isActive();
|
static bool isActive();
|
||||||
static void setActive(bool active);
|
static void setActive(bool active);
|
||||||
|
|
||||||
|
static QString getContextName();
|
||||||
|
static void addTimerRecord(const QString& fullName, quint64 elapsedUsec);
|
||||||
static const PerformanceTimerRecord& getTimerRecord(const QString& name) { return _records[name]; };
|
static const PerformanceTimerRecord& getTimerRecord(const QString& name) { return _records[name]; };
|
||||||
static const QMap<QString, PerformanceTimerRecord>& getAllTimerRecords() { return _records; };
|
static const QMap<QString, PerformanceTimerRecord>& getAllTimerRecords() { return _records; };
|
||||||
static void tallyAllTimerRecords();
|
static void tallyAllTimerRecords();
|
||||||
|
|
Loading…
Reference in a new issue