//// PerfStat.cpp// libraries/shared/src//// Created by Brad Hefta-Gaub on 3/29/13.// 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 "PerfStat.h" #include <cstdio>#include <map>#include <string> #include <QDebug>#include <QThread> #include "NumericalConstants.h"#include "SharedLogging.h" // ----------------------------------------------------------------------------// PerformanceWarning// ---------------------------------------------------------------------------- // Static class members initialization here!bool PerformanceWarning::_suppressShortTimings = false; // Destructor handles recording all of our statsPerformanceWarning::~PerformanceWarning() { quint64 end = usecTimestampNow(); quint64 elapsedUsec = (end - _start); double elapsedmsec = elapsedUsec / 1000.0; if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) { if (elapsedmsec > 1000) { double elapsedsec = (end - _start) / 1000000.0; qCDebug(shared, "%s took %.2lf seconds %s", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") ); } else { if (_suppressShortTimings) { if (elapsedmsec > 10) { qCDebug(shared, "%s took %.1lf milliseconds %s", _message, elapsedmsec, (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!")); } } else { qCDebug(shared, "%s took %.2lf milliseconds %s", _message, elapsedmsec, (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!")); } } } else if (_alwaysDisplay) { qCDebug(shared, "%s took %.2lf milliseconds", _message, elapsedmsec); } // if the caller gave us a pointer to store the running total, track it now. if (_runningTotal) { *_runningTotal += elapsedUsec; } if (_totalCalls) { *_totalCalls += 1; }}; // ----------------------------------------------------------------------------// PerformanceTimerRecord// ----------------------------------------------------------------------------const quint64 STALE_STAT_PERIOD = 4 * USECS_PER_SECOND; void PerformanceTimerRecord::tallyResult(const quint64& now) { if (_numAccumulations > 0) { _numTallies++; _movingAverage.updateAverage(_runningTotal - _lastTotal); _lastTotal = _runningTotal; _numAccumulations = 0; _expiry = now + STALE_STAT_PERIOD; }} // ----------------------------------------------------------------------------// PerformanceTimer// ---------------------------------------------------------------------------- std::atomic<bool> PerformanceTimer::_isActive(false);std::mutex PerformanceTimer::_mutex;QHash<QThread*, QString> PerformanceTimer::_fullNames;QMap<QString, PerformanceTimerRecord> PerformanceTimer::_records; PerformanceTimer::PerformanceTimer(const QString& name) { if (_isActive) { _name = name; { std::lock_guard<std::mutex> guard(_mutex); QString& fullName = _fullNames[QThread::currentThread()]; fullName.append("/"); fullName.append(_name); } _start = usecTimestampNow(); }} PerformanceTimer::~PerformanceTimer() { if (_isActive && _start != 0) { quint64 elapsedUsec = (usecTimestampNow() - _start); std::lock_guard<std::mutex> guard(_mutex); QString& fullName = _fullNames[QThread::currentThread()]; PerformanceTimerRecord& namedRecord = _records[fullName]; namedRecord.accumulateResult(elapsedUsec); fullName.resize(fullName.size() - (_name.size() + 1)); }} // staticbool PerformanceTimer::isActive() { return _isActive;} // staticQString PerformanceTimer::getContextName() { std::lock_guard<std::mutex> guard(_mutex); return _fullNames[QThread::currentThread()];} // staticvoid PerformanceTimer::addTimerRecord(const QString& fullName, quint64 elapsedUsec) { std::lock_guard<std::mutex> guard(_mutex); PerformanceTimerRecord& namedRecord = _records[fullName]; namedRecord.accumulateResult(elapsedUsec);} // staticvoid PerformanceTimer::setActive(bool active) { if (active != _isActive) { _isActive.store(active); if (!active) { std::lock_guard<std::mutex> guard(_mutex); _fullNames.clear(); _records.clear(); } qCDebug(shared) << "PerformanceTimer has been turned" << ((active) ? "on" : "off"); }} // staticQMap<QString, PerformanceTimerRecord> PerformanceTimer::getAllTimerRecords() { std::lock_guard<std::mutex> guard(_mutex); return _records;}; // staticvoid PerformanceTimer::tallyAllTimerRecords() { std::lock_guard<std::mutex> guard(_mutex); QMap<QString, PerformanceTimerRecord>::iterator recordsItr = _records.begin(); QMap<QString, PerformanceTimerRecord>::const_iterator recordsEnd = _records.end(); quint64 now = usecTimestampNow(); while (recordsItr != recordsEnd) { recordsItr.value().tallyResult(now); if (recordsItr.value().isStale(now)) { // purge stale records recordsItr = _records.erase(recordsItr); } else { ++recordsItr; } }} void PerformanceTimer::dumpAllTimerRecords() { std::lock_guard<std::mutex> guard(_mutex); QMapIterator<QString, PerformanceTimerRecord> i(_records); while (i.hasNext()) { i.next(); qCDebug(shared) << i.key() << ": average " << i.value().getAverage() << " [" << i.value().getMovingAverage() << "]" << "usecs over" << i.value().getCount() << "calls"; }}
//
// PerfStat.cpp
// libraries/shared/src
//
// Created by Brad Hefta-Gaub on 3/29/13.
// 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 "PerfStat.h"
#include <cstdio>
#include <map>
#include <string>
#include <QDebug>
#include <QThread>
#include "NumericalConstants.h"
#include "SharedLogging.h"
// ----------------------------------------------------------------------------
// PerformanceWarning
// ----------------------------------------------------------------------------
// Static class members initialization here!
bool PerformanceWarning::_suppressShortTimings = false;
// Destructor handles recording all of our stats
PerformanceWarning::~PerformanceWarning() {
quint64 end = usecTimestampNow();
quint64 elapsedUsec = (end - _start);
double elapsedmsec = elapsedUsec / 1000.0;
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - _start) / 1000000.0;
qCDebug(shared, "%s took %.2lf seconds %s", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") );
} else {
if (_suppressShortTimings) {
if (elapsedmsec > 10) {
qCDebug(shared, "%s took %.1lf milliseconds %s", _message, elapsedmsec,
(_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!"));
}
} else {
qCDebug(shared, "%s took %.2lf milliseconds %s", _message, elapsedmsec,
(_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!"));
}
}
} else if (_alwaysDisplay) {
qCDebug(shared, "%s took %.2lf milliseconds", _message, elapsedmsec);
}
// if the caller gave us a pointer to store the running total, track it now.
if (_runningTotal) {
*_runningTotal += elapsedUsec;
}
if (_totalCalls) {
*_totalCalls += 1;
}
};
// ----------------------------------------------------------------------------
// PerformanceTimerRecord
// ----------------------------------------------------------------------------
const quint64 STALE_STAT_PERIOD = 4 * USECS_PER_SECOND;
void PerformanceTimerRecord::tallyResult(const quint64& now) {
if (_numAccumulations > 0) {
_numTallies++;
_movingAverage.updateAverage(_runningTotal - _lastTotal);
_lastTotal = _runningTotal;
_numAccumulations = 0;
_expiry = now + STALE_STAT_PERIOD;
}
}
// ----------------------------------------------------------------------------
// PerformanceTimer
// ----------------------------------------------------------------------------
std::atomic<bool> PerformanceTimer::_isActive(false);
std::mutex PerformanceTimer::_mutex;
QHash<QThread*, QString> PerformanceTimer::_fullNames;
QMap<QString, PerformanceTimerRecord> PerformanceTimer::_records;
PerformanceTimer::PerformanceTimer(const QString& name) {
if (_isActive) {
_name = name;
{
std::lock_guard<std::mutex> guard(_mutex);
QString& fullName = _fullNames[QThread::currentThread()];
fullName.append("/");
fullName.append(_name);
}
_start = usecTimestampNow();
}
}
PerformanceTimer::~PerformanceTimer() {
if (_isActive && _start != 0) {
quint64 elapsedUsec = (usecTimestampNow() - _start);
std::lock_guard<std::mutex> guard(_mutex);
QString& fullName = _fullNames[QThread::currentThread()];
PerformanceTimerRecord& namedRecord = _records[fullName];
namedRecord.accumulateResult(elapsedUsec);
fullName.resize(fullName.size() - (_name.size() + 1));
}
}
// static
bool PerformanceTimer::isActive() {
return _isActive;
}
// static
QString PerformanceTimer::getContextName() {
std::lock_guard<std::mutex> guard(_mutex);
return _fullNames[QThread::currentThread()];
}
// static
void PerformanceTimer::addTimerRecord(const QString& fullName, quint64 elapsedUsec) {
std::lock_guard<std::mutex> guard(_mutex);
PerformanceTimerRecord& namedRecord = _records[fullName];
namedRecord.accumulateResult(elapsedUsec);
}
// static
void PerformanceTimer::setActive(bool active) {
if (active != _isActive) {
_isActive.store(active);
if (!active) {
std::lock_guard<std::mutex> guard(_mutex);
_fullNames.clear();
_records.clear();
}
qCDebug(shared) << "PerformanceTimer has been turned" << ((active) ? "on" : "off");
}
}
// static
QMap<QString, PerformanceTimerRecord> PerformanceTimer::getAllTimerRecords() {
std::lock_guard<std::mutex> guard(_mutex);
return _records;
};
// static
void PerformanceTimer::tallyAllTimerRecords() {
std::lock_guard<std::mutex> guard(_mutex);
QMap<QString, PerformanceTimerRecord>::iterator recordsItr = _records.begin();
QMap<QString, PerformanceTimerRecord>::const_iterator recordsEnd = _records.end();
quint64 now = usecTimestampNow();
while (recordsItr != recordsEnd) {
recordsItr.value().tallyResult(now);
if (recordsItr.value().isStale(now)) {
// purge stale records
recordsItr = _records.erase(recordsItr);
} else {
++recordsItr;
}
}
}
void PerformanceTimer::dumpAllTimerRecords() {
std::lock_guard<std::mutex> guard(_mutex);
QMapIterator<QString, PerformanceTimerRecord> i(_records);
while (i.hasNext()) {
i.next();
qCDebug(shared) << i.key() << ": average " << i.value().getAverage()
<< " [" << i.value().getMovingAverage() << "]"
<< "usecs over" << i.value().getCount() << "calls";
}
}