Browse Source

Merge pull request #17311 from Chocobo1/memPrio

Work around application stuttering on Windows
adaptive-webui-19844
Chocobo1 2 years ago committed by GitHub
parent
commit
286df8f560
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 73
      src/app/application.cpp
  2. 10
      src/app/application.h
  3. 23
      src/app/upgrade.cpp
  4. 68
      src/base/bittorrent/session.cpp
  5. 23
      src/base/bittorrent/session.h
  6. 25
      src/base/interfaces/iapplication.h
  7. 14
      src/gui/advancedsettings.cpp

73
src/app/application.cpp

@ -129,6 +129,9 @@ Application::Application(int &argc, char **argv)
, m_storeFileLoggerAgeType(FILELOGGER_SETTINGS_KEY(u"AgeType"_qs)) , m_storeFileLoggerAgeType(FILELOGGER_SETTINGS_KEY(u"AgeType"_qs))
, m_storeFileLoggerPath(FILELOGGER_SETTINGS_KEY(u"Path"_qs)) , m_storeFileLoggerPath(FILELOGGER_SETTINGS_KEY(u"Path"_qs))
, m_storeMemoryWorkingSetLimit(SETTINGS_KEY(u"MemoryWorkingSetLimit"_qs)) , m_storeMemoryWorkingSetLimit(SETTINGS_KEY(u"MemoryWorkingSetLimit"_qs))
#ifdef Q_OS_WIN
, m_processMemoryPriority(SETTINGS_KEY(u"ProcessMemoryPriority"_qs))
#endif
{ {
qRegisterMetaType<Log::Msg>("Log::Msg"); qRegisterMetaType<Log::Msg>("Log::Msg");
qRegisterMetaType<Log::Peer>("Log::Peer"); qRegisterMetaType<Log::Peer>("Log::Peer");
@ -607,6 +610,7 @@ int Application::exec(const QStringList &params)
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
applyMemoryPriority();
adjustThreadPriority(); adjustThreadPriority();
#endif #endif
@ -822,6 +826,75 @@ void Application::applyMemoryWorkingSetLimit() const
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
MemoryPriority Application::processMemoryPriority() const
{
return m_processMemoryPriority.get(MemoryPriority::BelowNormal);
}
void Application::setProcessMemoryPriority(const MemoryPriority priority)
{
if (processMemoryPriority() == priority)
return;
m_processMemoryPriority = priority;
applyMemoryPriority();
}
void Application::applyMemoryPriority() const
{
using SETPROCESSINFORMATION = BOOL (WINAPI *)(HANDLE, PROCESS_INFORMATION_CLASS, LPVOID, DWORD);
const auto setProcessInformation = Utils::Misc::loadWinAPI<SETPROCESSINFORMATION>(u"Kernel32.dll"_qs, "SetProcessInformation");
if (!setProcessInformation) // only available on Windows >= 8
return;
using SETTHREADINFORMATION = BOOL (WINAPI *)(HANDLE, THREAD_INFORMATION_CLASS, LPVOID, DWORD);
const auto setThreadInformation = Utils::Misc::loadWinAPI<SETTHREADINFORMATION>(u"Kernel32.dll"_qs, "SetThreadInformation");
if (!setThreadInformation) // only available on Windows >= 8
return;
#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
// this dummy struct is required to compile successfully when targeting older Windows version
struct MEMORY_PRIORITY_INFORMATION
{
ULONG MemoryPriority;
};
#define MEMORY_PRIORITY_LOWEST 0
#define MEMORY_PRIORITY_VERY_LOW 1
#define MEMORY_PRIORITY_LOW 2
#define MEMORY_PRIORITY_MEDIUM 3
#define MEMORY_PRIORITY_BELOW_NORMAL 4
#define MEMORY_PRIORITY_NORMAL 5
#endif
MEMORY_PRIORITY_INFORMATION prioInfo {};
switch (processMemoryPriority())
{
case MemoryPriority::Normal:
default:
prioInfo.MemoryPriority = MEMORY_PRIORITY_NORMAL;
break;
case MemoryPriority::BelowNormal:
prioInfo.MemoryPriority = MEMORY_PRIORITY_BELOW_NORMAL;
break;
case MemoryPriority::Medium:
prioInfo.MemoryPriority = MEMORY_PRIORITY_MEDIUM;
break;
case MemoryPriority::Low:
prioInfo.MemoryPriority = MEMORY_PRIORITY_LOW;
break;
case MemoryPriority::VeryLow:
prioInfo.MemoryPriority = MEMORY_PRIORITY_VERY_LOW;
break;
}
setProcessInformation(::GetCurrentProcess(), ProcessMemoryPriority, &prioInfo, sizeof(prioInfo));
// To avoid thrashing/sluggishness of the app, set "main event loop" thread to normal memory priority
// which is higher/equal than other threads
prioInfo.MemoryPriority = MEMORY_PRIORITY_NORMAL;
setThreadInformation(::GetCurrentThread(), ThreadMemoryPriority, &prioInfo, sizeof(prioInfo));
}
void Application::adjustThreadPriority() const void Application::adjustThreadPriority() const
{ {
// Workaround for improving responsiveness of qbt when CPU resources are scarce. // Workaround for improving responsiveness of qbt when CPU resources are scarce.

10
src/app/application.h

@ -118,6 +118,11 @@ public:
int memoryWorkingSetLimit() const override; int memoryWorkingSetLimit() const override;
void setMemoryWorkingSetLimit(int size) override; void setMemoryWorkingSetLimit(int size) override;
#ifdef Q_OS_WIN
MemoryPriority processMemoryPriority() const override;
void setProcessMemoryPriority(MemoryPriority priority) override;
#endif
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
MainWindow *mainWindow() override; MainWindow *mainWindow() override;
#endif #endif
@ -151,6 +156,7 @@ private:
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
void applyMemoryPriority() const;
void adjustThreadPriority() const; void adjustThreadPriority() const;
#endif #endif
@ -183,6 +189,10 @@ private:
SettingValue<Path> m_storeFileLoggerPath; SettingValue<Path> m_storeFileLoggerPath;
SettingValue<int> m_storeMemoryWorkingSetLimit; SettingValue<int> m_storeMemoryWorkingSetLimit;
#ifdef Q_OS_WIN
SettingValue<MemoryPriority> m_processMemoryPriority;
#endif
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
MainWindow *m_window = nullptr; MainWindow *m_window = nullptr;
#endif #endif

23
src/app/upgrade.cpp

@ -28,6 +28,7 @@
#include "upgrade.h" #include "upgrade.h"
#include <QtGlobal>
#include <QMetaEnum> #include <QMetaEnum>
#include "base/bittorrent/torrentcontentlayout.h" #include "base/bittorrent/torrentcontentlayout.h"
@ -44,7 +45,7 @@
namespace namespace
{ {
const int MIGRATION_VERSION = 3; const int MIGRATION_VERSION = 4;
const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_qs; const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_qs;
void exportWebUIHttpsFiles() void exportWebUIHttpsFiles()
@ -368,6 +369,21 @@ namespace
} }
} }
} }
#ifdef Q_OS_WIN
void migrateMemoryPrioritySettings()
{
auto *settingsStorage = SettingsStorage::instance();
const QString oldKey = u"BitTorrent/OSMemoryPriority"_qs;
const QString newKey = u"Application/ProcessMemoryPriority"_qs;
if (settingsStorage->hasKey(oldKey))
{
const auto value = settingsStorage->loadValue<QVariant>(oldKey);
settingsStorage->storeValue(newKey, value);
}
}
#endif
} }
bool upgrade(const bool /*ask*/) bool upgrade(const bool /*ask*/)
@ -392,6 +408,11 @@ bool upgrade(const bool /*ask*/)
if (version < 3) if (version < 3)
migrateProxySettingsEnum(); migrateProxySettingsEnum();
#ifdef Q_OS_WIN
if (version < 4)
migrateMemoryPrioritySettings();
#endif
version = MIGRATION_VERSION; version = MIGRATION_VERSION;
} }

68
src/base/bittorrent/session.cpp

@ -447,9 +447,6 @@ Session::Session(QObject *parent)
} }
) )
, m_resumeDataStorageType(BITTORRENT_SESSION_KEY(u"ResumeDataStorageType"_qs), ResumeDataStorageType::Legacy) , m_resumeDataStorageType(BITTORRENT_SESSION_KEY(u"ResumeDataStorageType"_qs), ResumeDataStorageType::Legacy)
#if defined(Q_OS_WIN)
, m_OSMemoryPriority(BITTORRENT_KEY(u"OSMemoryPriority"_qs), OSMemoryPriority::BelowNormal)
#endif
, m_seedingLimitTimer {new QTimer {this}} , m_seedingLimitTimer {new QTimer {this}}
, m_resumeDataTimer {new QTimer {this}} , m_resumeDataTimer {new QTimer {this}}
, m_statistics {new Statistics {this}} , m_statistics {new Statistics {this}}
@ -1067,10 +1064,6 @@ void Session::configureComponents()
disableIPFilter(); disableIPFilter();
m_IPFilteringConfigured = true; m_IPFilteringConfigured = true;
} }
#if defined(Q_OS_WIN)
applyOSMemoryPriority();
#endif
} }
void Session::prepareStartup() void Session::prepareStartup()
@ -3512,67 +3505,6 @@ bool Session::isRestored() const
return m_isRestored; return m_isRestored;
} }
#if defined(Q_OS_WIN)
OSMemoryPriority Session::getOSMemoryPriority() const
{
return m_OSMemoryPriority;
}
void Session::setOSMemoryPriority(const OSMemoryPriority priority)
{
if (m_OSMemoryPriority == priority)
return;
m_OSMemoryPriority = priority;
configureDeferred();
}
void Session::applyOSMemoryPriority() const
{
using SETPROCESSINFORMATION = BOOL (WINAPI *)(HANDLE, PROCESS_INFORMATION_CLASS, LPVOID, DWORD);
const auto setProcessInformation = Utils::Misc::loadWinAPI<SETPROCESSINFORMATION>(u"Kernel32.dll"_qs, "SetProcessInformation");
if (!setProcessInformation) // only available on Windows >= 8
return;
#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
// this dummy struct is required to compile successfully when targeting older Windows version
struct MEMORY_PRIORITY_INFORMATION
{
ULONG MemoryPriority;
};
#define MEMORY_PRIORITY_LOWEST 0
#define MEMORY_PRIORITY_VERY_LOW 1
#define MEMORY_PRIORITY_LOW 2
#define MEMORY_PRIORITY_MEDIUM 3
#define MEMORY_PRIORITY_BELOW_NORMAL 4
#define MEMORY_PRIORITY_NORMAL 5
#endif
MEMORY_PRIORITY_INFORMATION prioInfo {};
switch (getOSMemoryPriority())
{
case OSMemoryPriority::Normal:
default:
prioInfo.MemoryPriority = MEMORY_PRIORITY_NORMAL;
break;
case OSMemoryPriority::BelowNormal:
prioInfo.MemoryPriority = MEMORY_PRIORITY_BELOW_NORMAL;
break;
case OSMemoryPriority::Medium:
prioInfo.MemoryPriority = MEMORY_PRIORITY_MEDIUM;
break;
case OSMemoryPriority::Low:
prioInfo.MemoryPriority = MEMORY_PRIORITY_LOW;
break;
case OSMemoryPriority::VeryLow:
prioInfo.MemoryPriority = MEMORY_PRIORITY_VERY_LOW;
break;
}
setProcessInformation(::GetCurrentProcess(), ProcessMemoryPriority, &prioInfo, sizeof(prioInfo));
}
#endif
int Session::maxConnectionsPerTorrent() const int Session::maxConnectionsPerTorrent() const
{ {
return m_maxConnectionsPerTorrent; return m_maxConnectionsPerTorrent;

23
src/base/bittorrent/session.h

@ -29,7 +29,6 @@
#pragma once #pragma once
#include <memory>
#include <variant> #include <variant>
#include <vector> #include <vector>
@ -151,18 +150,6 @@ namespace BitTorrent
SQLite SQLite
}; };
Q_ENUM_NS(ResumeDataStorageType) Q_ENUM_NS(ResumeDataStorageType)
#if defined(Q_OS_WIN)
enum class OSMemoryPriority : int
{
Normal = 0,
BelowNormal = 1,
Medium = 2,
Low = 3,
VeryLow = 4
};
Q_ENUM_NS(OSMemoryPriority)
#endif
} }
struct SessionMetricIndices struct SessionMetricIndices
@ -464,10 +451,6 @@ namespace BitTorrent
void setBannedIPs(const QStringList &newList); void setBannedIPs(const QStringList &newList);
ResumeDataStorageType resumeDataStorageType() const; ResumeDataStorageType resumeDataStorageType() const;
void setResumeDataStorageType(ResumeDataStorageType type); void setResumeDataStorageType(ResumeDataStorageType type);
#if defined(Q_OS_WIN)
OSMemoryPriority getOSMemoryPriority() const;
void setOSMemoryPriority(OSMemoryPriority priority);
#endif
bool isRestored() const; bool isRestored() const;
@ -629,9 +612,6 @@ namespace BitTorrent
void populateAdditionalTrackers(); void populateAdditionalTrackers();
void enableIPFilter(); void enableIPFilter();
void disableIPFilter(); void disableIPFilter();
#if defined(Q_OS_WIN)
void applyOSMemoryPriority() const;
#endif
void processTrackerStatuses(); void processTrackerStatuses();
void populateExcludedFileNamesRegExpList(); void populateExcludedFileNamesRegExpList();
void prepareStartup(); void prepareStartup();
@ -795,9 +775,6 @@ namespace BitTorrent
CachedSettingValue<QStringList> m_excludedFileNames; CachedSettingValue<QStringList> m_excludedFileNames;
CachedSettingValue<QStringList> m_bannedIPs; CachedSettingValue<QStringList> m_bannedIPs;
CachedSettingValue<ResumeDataStorageType> m_resumeDataStorageType; CachedSettingValue<ResumeDataStorageType> m_resumeDataStorageType;
#if defined(Q_OS_WIN)
CachedSettingValue<OSMemoryPriority> m_OSMemoryPriority;
#endif
bool m_isRestored = false; bool m_isRestored = false;

25
src/base/interfaces/iapplication.h

@ -30,11 +30,31 @@
#pragma once #pragma once
#include <QtGlobal>
#include <QMetaObject>
class QString; class QString;
class Path; class Path;
struct QBtCommandLineParameters; struct QBtCommandLineParameters;
#ifdef Q_OS_WIN
inline namespace ApplicationSettingsEnums
{
Q_NAMESPACE
enum class MemoryPriority : int
{
Normal = 0,
BelowNormal = 1,
Medium = 2,
Low = 3,
VeryLow = 4
};
Q_ENUM_NS(MemoryPriority)
}
#endif
class IApplication class IApplication
{ {
public: public:
@ -58,4 +78,9 @@ public:
virtual int memoryWorkingSetLimit() const = 0; virtual int memoryWorkingSetLimit() const = 0;
virtual void setMemoryWorkingSetLimit(int size) = 0; virtual void setMemoryWorkingSetLimit(int size) = 0;
#ifdef Q_OS_WIN
virtual MemoryPriority processMemoryPriority() const = 0;
virtual void setProcessMemoryPriority(MemoryPriority priority) = 0;
#endif
}; };

14
src/gui/advancedsettings.cpp

@ -185,7 +185,7 @@ void AdvancedSettings::saveAdvancedSettings() const
app()->setMemoryWorkingSetLimit(m_spinBoxMemoryWorkingSetLimit.value()); app()->setMemoryWorkingSetLimit(m_spinBoxMemoryWorkingSetLimit.value());
#endif #endif
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
session->setOSMemoryPriority(m_comboBoxOSMemoryPriority.currentData().value<BitTorrent::OSMemoryPriority>()); app()->setProcessMemoryPriority(m_comboBoxOSMemoryPriority.currentData().value<MemoryPriority>());
#endif #endif
// Async IO threads // Async IO threads
session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value()); session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value());
@ -422,12 +422,12 @@ void AdvancedSettings::loadAdvancedSettings()
, &m_spinBoxMemoryWorkingSetLimit); , &m_spinBoxMemoryWorkingSetLimit);
#endif #endif
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
m_comboBoxOSMemoryPriority.addItem(tr("Normal"), QVariant::fromValue(BitTorrent::OSMemoryPriority::Normal)); m_comboBoxOSMemoryPriority.addItem(tr("Normal"), QVariant::fromValue(MemoryPriority::Normal));
m_comboBoxOSMemoryPriority.addItem(tr("Below normal"), QVariant::fromValue(BitTorrent::OSMemoryPriority::BelowNormal)); m_comboBoxOSMemoryPriority.addItem(tr("Below normal"), QVariant::fromValue(MemoryPriority::BelowNormal));
m_comboBoxOSMemoryPriority.addItem(tr("Medium"), QVariant::fromValue(BitTorrent::OSMemoryPriority::Medium)); m_comboBoxOSMemoryPriority.addItem(tr("Medium"), QVariant::fromValue(MemoryPriority::Medium));
m_comboBoxOSMemoryPriority.addItem(tr("Low"), QVariant::fromValue(BitTorrent::OSMemoryPriority::Low)); m_comboBoxOSMemoryPriority.addItem(tr("Low"), QVariant::fromValue(MemoryPriority::Low));
m_comboBoxOSMemoryPriority.addItem(tr("Very low"), QVariant::fromValue(BitTorrent::OSMemoryPriority::VeryLow)); m_comboBoxOSMemoryPriority.addItem(tr("Very low"), QVariant::fromValue(MemoryPriority::VeryLow));
m_comboBoxOSMemoryPriority.setCurrentIndex(m_comboBoxOSMemoryPriority.findData(QVariant::fromValue(session->getOSMemoryPriority()))); m_comboBoxOSMemoryPriority.setCurrentIndex(m_comboBoxOSMemoryPriority.findData(QVariant::fromValue(app()->processMemoryPriority())));
addRow(OS_MEMORY_PRIORITY, (tr("Process memory priority (Windows >= 8 only)") addRow(OS_MEMORY_PRIORITY, (tr("Process memory priority (Windows >= 8 only)")
+ u' ' + makeLink(u"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-memory_priority_information", u"(?)")) + u' ' + makeLink(u"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-memory_priority_information", u"(?)"))
, &m_comboBoxOSMemoryPriority); , &m_comboBoxOSMemoryPriority);

Loading…
Cancel
Save