Reduce present traffic on main thread event queue.

In an effort to diagnose the root cause of several deadlocks,
it seems possible that the main thread event queue can grow
to a size where it can take many seconds to drain.

This PR attempts to address this in two ways:
  * Change the connection between the DisplayPlugin::presented signal and
    the Application::onPresent slot to be a DirectConnection.  This should
    prevent the main thread from filling up with signal events.
  * Within Applicaiton::onPresent use an atomic counter to prevent the main
    thread from filling up with repeated Idle events.
This commit is contained in:
Anthony J. Thibault 2017-10-13 14:28:23 -07:00
parent 4dcce6ef45
commit a2a6cd0c7a
3 changed files with 61 additions and 8 deletions

View file

@ -207,6 +207,17 @@
#if defined(Q_OS_WIN)
#include <VersionHelpers.h>
#ifdef DEBUG_EVENT_QUEUE
// This is a HACK that uses private headers included with the qt source distrubution.
// To use this feature you need to add these directores to your include path:
// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1/QtCore
// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1
#define QT_BOOTSTRAPPED
#include <private/qthread_p.h>
#include <private/qobject_p.h>
#undef QT_BOOTSTRAPPED
#endif
extern "C" {
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}
@ -264,9 +275,7 @@ private:
switch ((int)event->type()) {
case ApplicationEvent::Render:
render();
// Ensure we never back up the render events. Each render should be triggered only in response
// to the NEXT render event after the last render occured
QCoreApplication::removePostedEvents(this, ApplicationEvent::Render);
qApp->_pendingRenderEventCount--;
return true;
default:
@ -2712,9 +2721,15 @@ bool Application::importFromZIP(const QString& filePath) {
return true;
}
// thread-safe
void Application::onPresent(quint32 frameCount) {
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
if (_renderEventHandler && !isAboutToQuit()) {
if (_pendingIdleEventCount.load() == 0) {
_pendingIdleEventCount++;
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
}
if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEventCount.load() == 0) {
_pendingRenderEventCount++;
postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
}
}
@ -2781,7 +2796,26 @@ bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) {
return false;
}
#ifdef DEBUG_EVENT_QUEUE
static int getEventQueueSize(QThread* thread) {
auto threadData = QThreadData::get2(thread);
QMutexLocker locker(&threadData->postEventList.mutex);
return threadData->postEventList.size();
}
static void dumpEventQueue(QThread* thread) {
auto threadData = QThreadData::get2(thread);
QMutexLocker locker(&threadData->postEventList.mutex);
qDebug() << "AJT: event list, size =" << threadData->postEventList.size();
for (auto& postEvent : threadData->postEventList) {
QEvent::Type type = (postEvent.event ? postEvent.event->type() : QEvent::None);
qDebug() << "AJT: " << type;
}
}
#endif // DEBUG_EVENT_QUEUE
bool Application::event(QEvent* event) {
if (!Menu::getInstance()) {
return false;
}
@ -2801,8 +2835,18 @@ bool Application::event(QEvent* event) {
// see (windowMinimizedChanged)
case ApplicationEvent::Idle:
idle();
// Don't process extra idle events that arrived in the event queue while we were doing this idle
QCoreApplication::removePostedEvents(this, ApplicationEvent::Idle);
#ifdef DEBUG_EVENT_QUEUE
{
int count = getEventQueueSize(QThread::currentThread());
if (count > 400) {
dumpEventQueue(QThread::currentThread());
}
}
#endif // DEBUG_EVENT_QUEUE
_pendingIdleEventCount--;
return true;
case QEvent::MouseMove:
@ -7203,7 +7247,7 @@ void Application::updateDisplayMode() {
_offscreenContext->makeCurrent();
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
_displayPlugin = newDisplayPlugin;
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection);
auto desktop = offscreenUi->getDesktop();
if (desktop) {
desktop->setProperty("repositionLocked", wasRepositionLocked);

View file

@ -717,5 +717,8 @@ private:
LaserPointerManager _laserPointerManager;
friend class RenderEventHandler;
std::atomic<int> _pendingIdleEventCount { 0 };
std::atomic<int> _pendingRenderEventCount { 0 };
};
#endif // hifi_Application_h

View file

@ -72,6 +72,12 @@ void Application::paintGL() {
{
QMutexLocker viewLocker(&_renderArgsMutex);
renderArgs = _appRenderArgs._renderArgs;
// don't render if there is no context.
if (!_appRenderArgs._renderArgs._context) {
return;
}
HMDSensorPose = _appRenderArgs._headPose;
eyeToWorld = _appRenderArgs._eyeToWorld;
sensorToWorld = _appRenderArgs._sensorToWorld;