Reduce CPU usage from background PC polling

This commit is contained in:
Cameron Gutman
2025-10-19 20:50:29 -05:00
parent 4bbd02fb2d
commit 3f8f4744c5
3 changed files with 34 additions and 25 deletions
+14 -6
View File
@@ -29,9 +29,9 @@ public:
} }
private: private:
bool tryPollComputer(NvAddress address, bool& changed) bool tryPollComputer(QNetworkAccessManager* nam, NvAddress address, bool& changed)
{ {
NvHTTP http(address, 0, m_Computer->serverCert); NvHTTP http(address, 0, m_Computer->serverCert, nam);
QString serverInfo; QString serverInfo;
try { try {
@@ -52,9 +52,9 @@ private:
return true; return true;
} }
bool updateAppList(bool& changed) bool updateAppList(QNetworkAccessManager* nam, bool& changed)
{ {
NvHTTP http(m_Computer); NvHTTP http(m_Computer, nam);
QVector<NvApp> appList; QVector<NvApp> appList;
@@ -81,6 +81,14 @@ private:
setServiceLevel(QThread::QualityOfService::Eco); setServiceLevel(QThread::QualityOfService::Eco);
#endif #endif
// Share the QNetworkAccessManager to conserve resources when polling.
// Each instance creates a worker thread, so sharing them ensures that
// we are not spamming a new thread for every single polling attempt.
//
// Since QThread inherit the priority of the current thread, this also
// ensures that the NAM's worker thread will inherit our lower priority.
QNetworkAccessManager nam;
// Always fetch the applist the first time // Always fetch the applist the first time
int pollsSinceLastAppListFetch = POLLS_PER_APPLIST_FETCH; int pollsSinceLastAppListFetch = POLLS_PER_APPLIST_FETCH;
while (!isInterruptionRequested()) { while (!isInterruptionRequested()) {
@@ -93,7 +101,7 @@ private:
return; return;
} }
if (tryPollComputer(address, stateChanged)) { if (tryPollComputer(&nam, address, stateChanged)) {
if (!wasOnline) { if (!wasOnline) {
qInfo() << m_Computer->name << "is now online at" << m_Computer->activeAddress.toString(); qInfo() << m_Computer->name << "is now online at" << m_Computer->activeAddress.toString();
} }
@@ -124,7 +132,7 @@ private:
stateChanged = false; stateChanged = false;
} }
if (updateAppList(stateChanged)) { if (updateAppList(&nam, stateChanged)) {
pollsSinceLastAppListFetch = 0; pollsSinceLastAppListFetch = 0;
} }
} }
+17 -16
View File
@@ -18,7 +18,8 @@
#define RESUME_TIMEOUT_MS 30000 #define RESUME_TIMEOUT_MS 30000
#define QUIT_TIMEOUT_MS 30000 #define QUIT_TIMEOUT_MS 30000
NvHTTP::NvHTTP(NvAddress address, uint16_t httpsPort, QSslCertificate serverCert) : NvHTTP::NvHTTP(NvAddress address, uint16_t httpsPort, QSslCertificate serverCert, QNetworkAccessManager* nam) :
m_Nam(nam ? nam : new QNetworkAccessManager(this)),
m_ServerCert(serverCert) m_ServerCert(serverCert)
{ {
m_BaseUrlHttp.setScheme("http"); m_BaseUrlHttp.setScheme("http");
@@ -29,13 +30,11 @@ NvHTTP::NvHTTP(NvAddress address, uint16_t httpsPort, QSslCertificate serverCert
// Never use a proxy server // Never use a proxy server
QNetworkProxy noProxy(QNetworkProxy::NoProxy); QNetworkProxy noProxy(QNetworkProxy::NoProxy);
m_Nam.setProxy(noProxy); m_Nam->setProxy(noProxy);
connect(&m_Nam, &QNetworkAccessManager::sslErrors, this, &NvHTTP::handleSslErrors);
} }
NvHTTP::NvHTTP(NvComputer* computer) : NvHTTP::NvHTTP(NvComputer* computer, QNetworkAccessManager* nam) :
NvHTTP(computer->activeAddress, computer->activeHttpsPort, computer->serverCert) NvHTTP(computer->activeAddress, computer->activeHttpsPort, computer->serverCert, nam)
{ {
} }
@@ -492,15 +491,15 @@ NvHTTP::openConnection(QUrl baseUrl,
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false); request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
#endif #endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && QT_VERSION < QT_VERSION_CHECK(5, 15, 1) && !defined(QT_NO_BEARERMANAGEMENT) #if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
// HACK: Set network accessibility to work around QTBUG-80947 (introduced in Qt 5.14.0 and fixed in Qt 5.15.1) // Use fine-grained idle timeouts to avoid calling QNetworkAccessManager::clearAccessCache(),
QT_WARNING_PUSH // which tears down the NAM's global thread each time. We must not keep persistent connections
QT_WARNING_DISABLE_DEPRECATED // or GFE will puke.
m_Nam.setNetworkAccessible(QNetworkAccessManager::Accessible); request.setAttribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute, 0);
QT_WARNING_POP
#endif #endif
QNetworkReply* reply = m_Nam.get(request); auto sslErrorsConnection = connect(m_Nam, &QNetworkAccessManager::sslErrors, this, &NvHTTP::handleSslErrors);
QNetworkReply* reply = m_Nam->get(request);
// Run the request with a timeout if requested // Run the request with a timeout if requested
QEventLoop loop; QEventLoop loop;
@@ -523,9 +522,11 @@ NvHTTP::openConnection(QUrl baseUrl,
reply->abort(); reply->abort();
} }
// We must clear out cached authentication and connections or #if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
// GFE will puke next time // If we couldn't use fine-grained connection idle timeouts, kill them all now
m_Nam.clearAccessCache(); m_Nam->clearAccessCache();
#endif
disconnect(sslErrorsConnection);
// Handle error // Handle error
if (reply->error() != QNetworkReply::NoError) if (reply->error() != QNetworkReply::NoError)
+3 -3
View File
@@ -109,9 +109,9 @@ public:
NVLL_VERBOSE NVLL_VERBOSE
}; };
explicit NvHTTP(NvAddress address, uint16_t httpsPort, QSslCertificate serverCert); explicit NvHTTP(NvAddress address, uint16_t httpsPort, QSslCertificate serverCert, QNetworkAccessManager* nam = nullptr);
explicit NvHTTP(NvComputer* computer); explicit NvHTTP(NvComputer* computer, QNetworkAccessManager* nam = nullptr);
static static
int int
@@ -196,6 +196,6 @@ private:
NvLogLevel logLevel); NvLogLevel logLevel);
NvAddress m_Address; NvAddress m_Address;
QNetworkAccessManager m_Nam; QNetworkAccessManager* m_Nam;
QSslCertificate m_ServerCert; QSslCertificate m_ServerCert;
}; };