Merge pull request #9283 from ZappoMan/improveInterval

more precise use of timers
This commit is contained in:
Brad Hefta-Gaub 2016-12-30 11:46:58 -08:00 committed by GitHub
commit 2096e98aa6
16 changed files with 92 additions and 33 deletions

View file

@ -1135,7 +1135,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&_settingsThread, SIGNAL(finished()), &_settingsTimer, SLOT(stop())); connect(&_settingsThread, SIGNAL(finished()), &_settingsTimer, SLOT(stop()));
_settingsTimer.moveToThread(&_settingsThread); _settingsTimer.moveToThread(&_settingsThread);
_settingsTimer.setSingleShot(false); _settingsTimer.setSingleShot(false);
_settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL); _settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable
_settingsThread.start(); _settingsThread.start();
if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) { if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) {
@ -1240,7 +1240,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Periodically send fps as a user activity event // Periodically send fps as a user activity event
QTimer* sendStatsTimer = new QTimer(this); QTimer* sendStatsTimer = new QTimer(this);
sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS); sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS); // 10s, Qt::CoarseTimer acceptable
connect(sendStatsTimer, &QTimer::timeout, this, [this]() { connect(sendStatsTimer, &QTimer::timeout, this, [this]() {
QJsonObject properties = {}; QJsonObject properties = {};
@ -1342,7 +1342,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Periodically check for count of nearby avatars // Periodically check for count of nearby avatars
static int lastCountOfNearbyAvatars = -1; static int lastCountOfNearbyAvatars = -1;
QTimer* checkNearbyAvatarsTimer = new QTimer(this); QTimer* checkNearbyAvatarsTimer = new QTimer(this);
checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok
connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() { connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() {
auto avatarManager = DependencyManager::get<AvatarManager>(); auto avatarManager = DependencyManager::get<AvatarManager>();
int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(), int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(),
@ -1500,16 +1500,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Monitor model assets (e.g., from Clara.io) added to the world that may need resizing. // Monitor model assets (e.g., from Clara.io) added to the world that may need resizing.
static const int ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS = 1000; static const int ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS = 1000;
_addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS); _addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable
connect(&_addAssetToWorldResizeTimer, &QTimer::timeout, this, &Application::addAssetToWorldCheckModelSize); connect(&_addAssetToWorldResizeTimer, &QTimer::timeout, this, &Application::addAssetToWorldCheckModelSize);
// Auto-update and close adding asset to world info message box. // Auto-update and close adding asset to world info message box.
static const int ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS = 5000; static const int ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS = 5000;
_addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS); _addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS); // 5s, Qt::CoarseTimer acceptable
_addAssetToWorldInfoTimer.setSingleShot(true); _addAssetToWorldInfoTimer.setSingleShot(true);
connect(&_addAssetToWorldInfoTimer, &QTimer::timeout, this, &Application::addAssetToWorldInfoTimeout); connect(&_addAssetToWorldInfoTimer, &QTimer::timeout, this, &Application::addAssetToWorldInfoTimeout);
static const int ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS = 8000; static const int ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS = 8000;
_addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS); _addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS); // 8s, Qt::CoarseTimer acceptable
_addAssetToWorldErrorTimer.setSingleShot(true); _addAssetToWorldErrorTimer.setSingleShot(true);
connect(&_addAssetToWorldErrorTimer, &QTimer::timeout, this, &Application::addAssetToWorldErrorTimeout); connect(&_addAssetToWorldErrorTimer, &QTimer::timeout, this, &Application::addAssetToWorldErrorTimeout);

View file

@ -91,7 +91,7 @@ void DiskCacheEditor::makeDialog() {
static const int REFRESH_INTERVAL = 100; // msec static const int REFRESH_INTERVAL = 100; // msec
_refreshTimer = new QTimer(_dialog); _refreshTimer = new QTimer(_dialog);
_refreshTimer->setInterval(REFRESH_INTERVAL); _refreshTimer->setInterval(REFRESH_INTERVAL); // Qt::CoarseTimer acceptable, no need for real time accuracy
_refreshTimer->setSingleShot(false); _refreshTimer->setSingleShot(false);
QObject::connect(_refreshTimer.data(), &QTimer::timeout, this, &DiskCacheEditor::refresh); QObject::connect(_refreshTimer.data(), &QTimer::timeout, this, &DiskCacheEditor::refresh);
_refreshTimer->start(); _refreshTimer->start();

View file

@ -426,7 +426,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
// a timer with a small interval is used to get better performance. // a timer with a small interval is used to get better performance.
QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick); QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &OffscreenQmlSurface::onAboutToQuit); QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &OffscreenQmlSurface::onAboutToQuit);
_updateTimer.setInterval(MIN_TIMER_MS); _updateTimer.setTimerType(Qt::PreciseTimer);
_updateTimer.setInterval(MIN_TIMER_MS); // 5ms, Qt::PreciseTimer required
_updateTimer.start(); _updateTimer.start();
auto rootContext = getRootContext(); auto rootContext = getRootContext();

View file

@ -41,12 +41,12 @@ DomainHandler::DomainHandler(QObject* parent) :
// setup a timeout for failure on settings requests // setup a timeout for failure on settings requests
static const int DOMAIN_SETTINGS_TIMEOUT_MS = 5000; static const int DOMAIN_SETTINGS_TIMEOUT_MS = 5000;
_settingsTimer.setInterval(DOMAIN_SETTINGS_TIMEOUT_MS); _settingsTimer.setInterval(DOMAIN_SETTINGS_TIMEOUT_MS); // 5s, Qt::CoarseTimer acceptable
connect(&_settingsTimer, &QTimer::timeout, this, &DomainHandler::settingsReceiveFail); connect(&_settingsTimer, &QTimer::timeout, this, &DomainHandler::settingsReceiveFail);
// setup the API refresh timer for auto connection information refresh from API when failing to connect // setup the API refresh timer for auto connection information refresh from API when failing to connect
const int API_REFRESH_TIMEOUT_MSEC = 2500; const int API_REFRESH_TIMEOUT_MSEC = 2500;
_apiRefreshTimer.setInterval(API_REFRESH_TIMEOUT_MSEC); _apiRefreshTimer.setInterval(API_REFRESH_TIMEOUT_MSEC); // 2.5s, Qt::CoarseTimer acceptable
auto addressManager = DependencyManager::get<AddressManager>(); auto addressManager = DependencyManager::get<AddressManager>();
connect(&_apiRefreshTimer, &QTimer::timeout, addressManager.data(), &AddressManager::refreshPreviousLookup); connect(&_apiRefreshTimer, &QTimer::timeout, addressManager.data(), &AddressManager::refreshPreviousLookup);

View file

@ -902,7 +902,7 @@ void LimitedNodeList::startSTUNPublicSocketUpdate() {
connect(_initialSTUNTimer.data(), &QTimer::timeout, this, &LimitedNodeList::sendSTUNRequest); connect(_initialSTUNTimer.data(), &QTimer::timeout, this, &LimitedNodeList::sendSTUNRequest);
const int STUN_INITIAL_UPDATE_INTERVAL_MSECS = 250; const int STUN_INITIAL_UPDATE_INTERVAL_MSECS = 250;
_initialSTUNTimer->setInterval(STUN_INITIAL_UPDATE_INTERVAL_MSECS); _initialSTUNTimer->setInterval(STUN_INITIAL_UPDATE_INTERVAL_MSECS); // 250ms, Qt::CoarseTimer acceptable
// if we don't know the STUN IP yet we need to wait until it is known to start STUN requests // if we don't know the STUN IP yet we need to wait until it is known to start STUN requests
if (_stunSockAddr.getAddress().isNull()) { if (_stunSockAddr.getAddress().isNull()) {

View file

@ -102,7 +102,7 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
connect(this, &LimitedNodeList::nodeActivated, this, &NodeList::maybeSendIgnoreSetToNode); connect(this, &LimitedNodeList::nodeActivated, this, &NodeList::maybeSendIgnoreSetToNode);
// setup our timer to send keepalive pings (it's started and stopped on domain connect/disconnect) // setup our timer to send keepalive pings (it's started and stopped on domain connect/disconnect)
_keepAlivePingTimer.setInterval(KEEPALIVE_PING_INTERVAL_MS); _keepAlivePingTimer.setInterval(KEEPALIVE_PING_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable
connect(&_keepAlivePingTimer, &QTimer::timeout, this, &NodeList::sendKeepAlivePings); connect(&_keepAlivePingTimer, &QTimer::timeout, this, &NodeList::sendKeepAlivePings);
connect(&_domainHandler, SIGNAL(connectedToDomain(QString)), &_keepAlivePingTimer, SLOT(start())); connect(&_domainHandler, SIGNAL(connectedToDomain(QString)), &_keepAlivePingTimer, SLOT(start()));
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop); connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop);

View file

@ -27,11 +27,11 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) :
_statsTimer(this) _statsTimer(this)
{ {
static const int STATS_TIMEOUT_MS = 1000; static const int STATS_TIMEOUT_MS = 1000;
_statsTimer.setInterval(STATS_TIMEOUT_MS); _statsTimer.setInterval(STATS_TIMEOUT_MS); // 1s, Qt::CoarseTimer acceptable
connect(&_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); connect(&_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket);
connect(&_domainServerTimer, &QTimer::timeout, this, &ThreadedAssignment::checkInWithDomainServerOrExit); connect(&_domainServerTimer, &QTimer::timeout, this, &ThreadedAssignment::checkInWithDomainServerOrExit);
_domainServerTimer.setInterval(DOMAIN_SERVER_CHECK_IN_MSECS); _domainServerTimer.setInterval(DOMAIN_SERVER_CHECK_IN_MSECS); // 1s, Qt::CoarseTimer acceptable
// if the NL tells us we got a DS response, clear our member variable of queued check-ins // if the NL tells us we got a DS response, clear our member variable of queued check-ins
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();

View file

@ -800,7 +800,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
_registeredHandlers[entityID] = RegisteredEventHandlers(); _registeredHandlers[entityID] = RegisteredEventHandlers();
} }
CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName]; CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName];
CallbackData handlerData = {handler, currentEntityIdentifier, currentSandboxURL}; CallbackData handlerData = { handler, currentEntityIdentifier, currentSandboxURL };
handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler(). handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler().
} }
@ -878,23 +878,48 @@ void ScriptEngine::run() {
// Throttle to SCRIPT_FPS // Throttle to SCRIPT_FPS
// We'd like to try to keep the script at a solid SCRIPT_FPS update rate. And so we will // We'd like to try to keep the script at a solid SCRIPT_FPS update rate. And so we will
// calculate a sleepUntil to be the time from our start time until the original target // calculate a sleepUntil to be the time from our start time until the original target
// sleepUntil for this frame. // sleepUntil for this frame. This approach will allow us to "catch up" in the event
const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); // that some of our script udpates/frames take a little bit longer than the target average
clock::time_point targetSleepUntil(startTime + thisFrame++ * FRAME_DURATION); // to execute.
// NOTE: if we go to variable SCRIPT_FPS, then we will need to reconsider this approach
const std::chrono::microseconds TARGET_SCRIPT_FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1);
clock::time_point targetSleepUntil(startTime + (thisFrame++ * TARGET_SCRIPT_FRAME_DURATION));
// However, if our sleepUntil is not at least our average update time into the future // However, if our sleepUntil is not at least our average update and timer execution time
// it means our script is taking too long in it's updates, and we want to punish the // into the future it means our script is taking too long in its updates, and we want to
// script a little bit. So we will force the sleepUntil to be at least our averageUpdate // punish the script a little bit. So we will force the sleepUntil to be at least our
// time into the future. // averageUpdate + averageTimerPerFrame time into the future.
auto averageUpdate = totalUpdates / thisFrame; auto averageUpdate = totalUpdates / thisFrame;
auto sleepUntil = std::max(targetSleepUntil, beforeSleep + averageUpdate); auto averageTimerPerFrame = _totalTimerExecution / thisFrame;
auto averageTimerAndUpdate = averageUpdate + averageTimerPerFrame;
auto sleepUntil = std::max(targetSleepUntil, beforeSleep + averageTimerAndUpdate);
// We don't want to actually sleep for too long, because it causes our scripts to hang // We don't want to actually sleep for too long, because it causes our scripts to hang
// on shutdown and stop... so we want to loop and sleep until we've spent our time in // on shutdown and stop... so we want to loop and sleep until we've spent our time in
// purgatory, constantly checking to see if our script was asked to end // purgatory, constantly checking to see if our script was asked to end
bool processedEvents = false;
while (!_isFinished && clock::now() < sleepUntil) { while (!_isFinished && clock::now() < sleepUntil) {
QCoreApplication::processEvents(); // before we sleep again, give events a chance to process QCoreApplication::processEvents(); // before we sleep again, give events a chance to process
auto thisSleepUntil = std::min(sleepUntil, clock::now() + FRAME_DURATION); processedEvents = true;
// If after processing events, we're past due, exit asap
if (clock::now() >= sleepUntil) {
break;
}
// determine how long before the next timer should fire, we'd ideally like to sleep just
// that long, so the next processEvents() will allow the timers to fire on time.
const std::chrono::microseconds minTimerTimeRemaining(USECS_PER_MSEC * getTimersRemainingTime());
// However, if we haven't yet slept at least as long as our average timer per frame, then we will
// punish the timers to at least wait as long as the average run time of the timers.
auto untilTimer = std::max(minTimerTimeRemaining, averageTimerPerFrame);
// choose the closest time point, our
auto remainingSleepUntil = std::chrono::duration_cast<std::chrono::microseconds>(sleepUntil - clock::now());
auto closestUntil = std::min(remainingSleepUntil, untilTimer);
auto thisSleepUntil = std::min(sleepUntil, clock::now() + closestUntil);
std::this_thread::sleep_until(thisSleepUntil); std::this_thread::sleep_until(thisSleepUntil);
} }
@ -919,7 +944,10 @@ void ScriptEngine::run() {
break; break;
} }
QCoreApplication::processEvents(); // Only call this if we didn't processEvents as part of waiting for next frame
if (!processedEvents) {
QCoreApplication::processEvents();
}
if (_isFinished) { if (_isFinished) {
break; break;
@ -982,6 +1010,21 @@ void ScriptEngine::run() {
emit doneRunning(); emit doneRunning();
} }
quint64 ScriptEngine::getTimersRemainingTime() {
quint64 minimumTime = USECS_PER_SECOND; // anything larger than this can be ignored
QMutableHashIterator<QTimer*, CallbackData> i(_timerFunctionMap);
while (i.hasNext()) {
i.next();
QTimer* timer = i.key();
int remainingTime = timer->remainingTime();
if (remainingTime >= 0) {
minimumTime = std::min((quint64)remainingTime, minimumTime);
}
}
return minimumTime;
}
// NOTE: This is private because it must be called on the same thread that created the timers, which is why // NOTE: This is private because it must be called on the same thread that created the timers, which is why
// we want to only call it in our own run "shutdown" processing. // we want to only call it in our own run "shutdown" processing.
void ScriptEngine::stopAllTimers() { void ScriptEngine::stopAllTimers() {
@ -1077,7 +1120,12 @@ void ScriptEngine::timerFired() {
// call the associated JS function, if it exists // call the associated JS function, if it exists
if (timerData.function.isValid()) { if (timerData.function.isValid()) {
auto preTimer = p_high_resolution_clock::now();
callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList()); callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList());
auto postTimer = p_high_resolution_clock::now();
auto elapsed = (postTimer - preTimer);
_totalTimerExecution += std::chrono::duration_cast<std::chrono::microseconds>(elapsed);
} }
} }
@ -1087,12 +1135,18 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int
QTimer* newTimer = new QTimer(this); QTimer* newTimer = new QTimer(this);
newTimer->setSingleShot(isSingleShot); newTimer->setSingleShot(isSingleShot);
// The default timer type is not very accurate below about 200ms http://doc.qt.io/qt-5/qt.html#TimerType-enum
static const int MIN_TIMEOUT_FOR_COARSE_TIMER = 200;
if (intervalMS < MIN_TIMEOUT_FOR_COARSE_TIMER) {
newTimer->setTimerType(Qt::PreciseTimer);
}
connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
// make sure the timer stops when the script does // make sure the timer stops when the script does
connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL}; CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL };
_timerFunctionMap.insert(newTimer, timerData); _timerFunctionMap.insert(newTimer, timerData);
newTimer->start(intervalMS); newTimer->start(intervalMS);

View file

@ -218,6 +218,7 @@ protected:
void init(); void init();
bool evaluatePending() const { return _evaluatesPending > 0; } bool evaluatePending() const { return _evaluatesPending > 0; }
quint64 getTimersRemainingTime();
void timerFired(); void timerFired();
void stopAllTimers(); void stopAllTimers();
void stopAllTimersForEntityScript(const EntityItemID& entityID); void stopAllTimersForEntityScript(const EntityItemID& entityID);
@ -252,6 +253,8 @@ protected:
std::function<bool()> _emitScriptUpdates{ [](){ return true; } }; std::function<bool()> _emitScriptUpdates{ [](){ return true; } };
std::recursive_mutex _lock; std::recursive_mutex _lock;
std::chrono::microseconds _totalTimerExecution { 0 };
}; };
#endif // hifi_ScriptEngine_h #endif // hifi_ScriptEngine_h

View file

@ -83,7 +83,7 @@ namespace Setting {
_saveTimer = new QTimer(this); _saveTimer = new QTimer(this);
Q_CHECK_PTR(_saveTimer); Q_CHECK_PTR(_saveTimer);
_saveTimer->setSingleShot(true); // We will restart it once settings are saved. _saveTimer->setSingleShot(true); // We will restart it once settings are saved.
_saveTimer->setInterval(SAVE_INTERVAL_MSEC); _saveTimer->setInterval(SAVE_INTERVAL_MSEC); // 5s, Qt::CoarseTimer acceptable
connect(_saveTimer, SIGNAL(timeout()), this, SLOT(saveAll())); connect(_saveTimer, SIGNAL(timeout()), this, SLOT(saveAll()));
} }
_saveTimer->start(); _saveTimer->start();

View file

@ -363,7 +363,7 @@ void showMinSpecWarning() {
vrOverlay->ShowOverlay(minSpecFailedOverlay); vrOverlay->ShowOverlay(minSpecFailedOverlay);
QTimer* timer = new QTimer(&miniApp); QTimer* timer = new QTimer(&miniApp);
timer->setInterval(FAILED_MIN_SPEC_UPDATE_INTERVAL_MS); timer->setInterval(FAILED_MIN_SPEC_UPDATE_INTERVAL_MS); // Qt::CoarseTimer acceptable, we don't need this to be frame rate accurate
QObject::connect(timer, &QTimer::timeout, [&] { QObject::connect(timer, &QTimer::timeout, [&] {
vr::TrackedDevicePose_t vrPoses[vr::k_unMaxTrackedDeviceCount]; vr::TrackedDevicePose_t vrPoses[vr::k_unMaxTrackedDeviceCount];
vrSystem->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, 0, vrPoses, vr::k_unMaxTrackedDeviceCount); vrSystem->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, 0, vrPoses, vr::k_unMaxTrackedDeviceCount);

View file

@ -34,6 +34,7 @@ TestWindow::TestWindow() {
auto timer = new QTimer(this); auto timer = new QTimer(this);
timer->setTimerType(Qt::PreciseTimer);
timer->setInterval(5); timer->setInterval(5);
connect(timer, &QTimer::timeout, [&] { draw(); }); connect(timer, &QTimer::timeout, [&] { draw(); });
timer->start(); timer->start();

View file

@ -46,7 +46,7 @@ void ResourceTests::downloadFirst() {
const int timeout = 1000; const int timeout = 1000;
QEventLoop loop; QEventLoop loop;
QTimer timer; QTimer timer;
timer.setInterval(timeout); timer.setInterval(timeout); // 1s, Qt::CoarseTimer acceptable
timer.setSingleShot(true); timer.setSingleShot(true);
connect(resource.data(), &Resource::loaded, &loop, &QEventLoop::quit); connect(resource.data(), &Resource::loaded, &loop, &QEventLoop::quit);
@ -69,7 +69,7 @@ void ResourceTests::downloadAgain() {
const int timeout = 1000; const int timeout = 1000;
QEventLoop loop; QEventLoop loop;
QTimer timer; QTimer timer;
timer.setInterval(timeout); timer.setInterval(timeout); // 1s, Qt::CoarseTimer acceptable
timer.setSingleShot(true); timer.setSingleShot(true);
connect(resource.data(), &Resource::loaded, &loop, &QEventLoop::quit); connect(resource.data(), &Resource::loaded, &loop, &QEventLoop::quit);

View file

@ -546,7 +546,7 @@ public:
restorePosition(); restorePosition();
QTimer* timer = new QTimer(this); QTimer* timer = new QTimer(this);
timer->setInterval(0); timer->setInterval(0); // Qt::CoarseTimer acceptable
connect(timer, &QTimer::timeout, this, [this] { connect(timer, &QTimer::timeout, this, [this] {
draw(); draw();
}); });

View file

@ -355,7 +355,7 @@ public:
} }
QTimer* timer = new QTimer(this); QTimer* timer = new QTimer(this);
timer->setInterval(0); timer->setInterval(0); // Qt::CoarseTimer acceptable
connect(timer, &QTimer::timeout, this, [this] { connect(timer, &QTimer::timeout, this, [this] {
draw(); draw();
}); });

View file

@ -201,7 +201,7 @@ int main(int argc, char** argv) {
QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
QTestWindow window; QTestWindow window;
QTimer timer; QTimer timer;
timer.setInterval(1); timer.setInterval(1); // Qt::CoarseTimer acceptable
app.connect(&timer, &QTimer::timeout, &app, [&] { app.connect(&timer, &QTimer::timeout, &app, [&] {
window.draw(); window.draw();
}); });