From 0f60121b94335c5b5eee604f9e992e6e1135fa30 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 28 Sep 2019 14:21:53 +0800 Subject: [PATCH] Add option to control qBittorrent process memory priority This is to avoid Windows swapping out other application data from OS cache and put in torrent data which hinders other program responsiveness. The default value "Below normal" is choosen because casual users have other higher priority apps (such as browser) running and they don't expect OS to swap out its data. Dedicated seeders most probably will not have other app running on their system and would expect qbt has priority over other background services. The option only has effect on Windows >= 8. --- src/base/bittorrent/session.cpp | 61 +++++++++++++++++++++++++++++++++ src/base/bittorrent/session.h | 22 ++++++++++++ src/gui/advancedsettings.cpp | 52 ++++++++++++++++++++++++++++ src/gui/advancedsettings.h | 2 ++ 4 files changed, 137 insertions(+) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index c4fd93720..cd0b87246 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -35,6 +35,7 @@ #include #ifdef Q_OS_WIN +#include #include #include #endif @@ -344,6 +345,9 @@ Session::Session(QObject *parent) return tmp; } ) +#if defined(Q_OS_WIN) + , m_OSMemoryPriority(BITTORRENT_KEY("OSMemoryPriority"), OSMemoryPriority::BelowNormal) +#endif , m_resumeFolderLock {new QFile {this}} , m_refreshTimer {new QTimer {this}} , m_seedingLimitTimer {new QTimer {this}} @@ -930,6 +934,10 @@ void Session::configureComponents() disableIPFilter(); m_IPFilteringConfigured = true; } + +#if defined(Q_OS_WIN) + applyOSMemoryPriority(); +#endif } void Session::initializeNativeSession() @@ -2753,6 +2761,59 @@ QStringList Session::bannedIPs() const return m_bannedIPs; } +#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("Kernel32.dll", "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; + }; +#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 { return m_maxConnectionsPerTorrent; diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 8b6571666..80586a954 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -132,6 +132,18 @@ namespace BitTorrent AntiLeech = 2 }; Q_ENUM_NS(SeedChokingAlgorithm) + +#if defined(Q_OS_WIN) + enum class OSMemoryPriority : int + { + Normal = 0, + BelowNormal = 1, + Medium = 2, + Low = 3, + VeryLow = 4 + }; + Q_ENUM_NS(OSMemoryPriority) +#endif } using namespace SessionSettingsEnums; @@ -387,6 +399,10 @@ namespace BitTorrent void setTrackerFilteringEnabled(bool enabled); QStringList bannedIPs() const; void setBannedIPs(const QStringList &newList); +#if defined(Q_OS_WIN) + OSMemoryPriority getOSMemoryPriority() const; + void setOSMemoryPriority(OSMemoryPriority priority); +#endif void startUpTorrents(); TorrentHandle *findTorrent(const InfoHash &hash) const; @@ -530,6 +546,9 @@ namespace BitTorrent void populateAdditionalTrackers(); void enableIPFilter(); void disableIPFilter(); +#if defined(Q_OS_WIN) + void applyOSMemoryPriority() const; +#endif bool addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri, TorrentInfo torrentInfo = TorrentInfo(), @@ -661,6 +680,9 @@ namespace BitTorrent CachedSettingValue m_isDisableAutoTMMWhenCategorySavePathChanged; CachedSettingValue m_isTrackerEnabled; CachedSettingValue m_bannedIPs; +#if defined(Q_OS_WIN) + CachedSettingValue m_OSMemoryPriority; +#endif // Order is important. This needs to be declared after its CachedSettingsValue // counterpart, because it uses it for initialization in the constructor diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp index d4d69d52d..b36a7360f 100644 --- a/src/gui/advancedsettings.cpp +++ b/src/gui/advancedsettings.cpp @@ -61,6 +61,9 @@ enum AdvSettingsRows { // qBittorrent section QBITTORRENT_HEADER, +#if defined(Q_OS_WIN) + OS_MEMORY_PRIORITY, +#endif // network interface NETWORK_IFACE, //Optional network address @@ -151,6 +154,28 @@ void AdvancedSettings::saveAdvancedSettings() Preferences *const pref = Preferences::instance(); BitTorrent::Session *const session = BitTorrent::Session::instance(); +#if defined(Q_OS_WIN) + BitTorrent::OSMemoryPriority prio = BitTorrent::OSMemoryPriority::Normal; + switch (m_comboBoxOSMemoryPriority.currentIndex()) { + case 0: + default: + prio = BitTorrent::OSMemoryPriority::Normal; + break; + case 1: + prio = BitTorrent::OSMemoryPriority::BelowNormal; + break; + case 2: + prio = BitTorrent::OSMemoryPriority::Medium; + break; + case 3: + prio = BitTorrent::OSMemoryPriority::Low; + break; + case 4: + prio = BitTorrent::OSMemoryPriority::VeryLow; + break; + } + session->setOSMemoryPriority(prio); +#endif // Async IO threads session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value()); // File pool size @@ -321,6 +346,33 @@ void AdvancedSettings::loadAdvancedSettings() addRow(LIBTORRENT_HEADER, QString("%1").arg(tr("libtorrent Section")), labelLibtorrentLink); static_cast(cellWidget(LIBTORRENT_HEADER, PROPERTY))->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); +#if defined(Q_OS_WIN) + m_comboBoxOSMemoryPriority.addItems({tr("Normal"), tr("Below normal"), tr("Medium"), tr("Low"), tr("Very low")}); + int OSMemoryPriorityIndex = 0; + switch (session->getOSMemoryPriority()) { + default: + case BitTorrent::OSMemoryPriority::Normal: + OSMemoryPriorityIndex = 0; + break; + case BitTorrent::OSMemoryPriority::BelowNormal: + OSMemoryPriorityIndex = 1; + break; + case BitTorrent::OSMemoryPriority::Medium: + OSMemoryPriorityIndex = 2; + break; + case BitTorrent::OSMemoryPriority::Low: + OSMemoryPriorityIndex = 3; + break; + case BitTorrent::OSMemoryPriority::VeryLow: + OSMemoryPriorityIndex = 4; + break; + } + m_comboBoxOSMemoryPriority.setCurrentIndex(OSMemoryPriorityIndex); + addRow(OS_MEMORY_PRIORITY, (tr("Process memory priority (Windows >= 8 only)") + + ' ' + makeLink("https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-memory_priority_information", "(?)")) + , &m_comboBoxOSMemoryPriority); +#endif + // Async IO threads m_spinBoxAsyncIOThreads.setMinimum(1); m_spinBoxAsyncIOThreads.setMaximum(1024); diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h index 0a782a931..502b56320 100644 --- a/src/gui/advancedsettings.h +++ b/src/gui/advancedsettings.h @@ -71,6 +71,8 @@ private: // OS dependent settings #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) QCheckBox m_checkBoxUseIconTheme; +#elif defined(Q_OS_WIN) + QComboBox m_comboBoxOSMemoryPriority; #endif };