Browse Source

Merge pull request #17311 from Chocobo1/memPrio

Work around application stuttering on Windows
adaptive-webui-19844
Chocobo1 3 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) @@ -129,6 +129,9 @@ Application::Application(int &argc, char **argv)
, m_storeFileLoggerAgeType(FILELOGGER_SETTINGS_KEY(u"AgeType"_qs))
, m_storeFileLoggerPath(FILELOGGER_SETTINGS_KEY(u"Path"_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::Peer>("Log::Peer");
@ -607,6 +610,7 @@ int Application::exec(const QStringList &params) @@ -607,6 +610,7 @@ int Application::exec(const QStringList &params)
#endif
#ifdef Q_OS_WIN
applyMemoryPriority();
adjustThreadPriority();
#endif
@ -822,6 +826,75 @@ void Application::applyMemoryWorkingSetLimit() const @@ -822,6 +826,75 @@ void Application::applyMemoryWorkingSetLimit() const
#endif
#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
{
// Workaround for improving responsiveness of qbt when CPU resources are scarce.

10
src/app/application.h

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

23
src/app/upgrade.cpp

@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
#include "upgrade.h"
#include <QtGlobal>
#include <QMetaEnum>
#include "base/bittorrent/torrentcontentlayout.h"
@ -44,7 +45,7 @@ @@ -44,7 +45,7 @@
namespace
{
const int MIGRATION_VERSION = 3;
const int MIGRATION_VERSION = 4;
const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_qs;
void exportWebUIHttpsFiles()
@ -368,6 +369,21 @@ namespace @@ -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*/)
@ -392,6 +408,11 @@ bool upgrade(const bool /*ask*/) @@ -392,6 +408,11 @@ bool upgrade(const bool /*ask*/)
if (version < 3)
migrateProxySettingsEnum();
#ifdef Q_OS_WIN
if (version < 4)
migrateMemoryPrioritySettings();
#endif
version = MIGRATION_VERSION;
}

68
src/base/bittorrent/session.cpp

@ -447,9 +447,6 @@ Session::Session(QObject *parent) @@ -447,9 +447,6 @@ Session::Session(QObject *parent)
}
)
, 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_resumeDataTimer {new QTimer {this}}
, m_statistics {new Statistics {this}}
@ -1067,10 +1064,6 @@ void Session::configureComponents() @@ -1067,10 +1064,6 @@ void Session::configureComponents()
disableIPFilter();
m_IPFilteringConfigured = true;
}
#if defined(Q_OS_WIN)
applyOSMemoryPriority();
#endif
}
void Session::prepareStartup()
@ -3512,67 +3505,6 @@ bool Session::isRestored() const @@ -3512,67 +3505,6 @@ bool Session::isRestored() const
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
{
return m_maxConnectionsPerTorrent;

23
src/base/bittorrent/session.h

@ -29,7 +29,6 @@ @@ -29,7 +29,6 @@
#pragma once
#include <memory>
#include <variant>
#include <vector>
@ -151,18 +150,6 @@ namespace BitTorrent @@ -151,18 +150,6 @@ namespace BitTorrent
SQLite
};
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
@ -464,10 +451,6 @@ namespace BitTorrent @@ -464,10 +451,6 @@ namespace BitTorrent
void setBannedIPs(const QStringList &newList);
ResumeDataStorageType resumeDataStorageType() const;
void setResumeDataStorageType(ResumeDataStorageType type);
#if defined(Q_OS_WIN)
OSMemoryPriority getOSMemoryPriority() const;
void setOSMemoryPriority(OSMemoryPriority priority);
#endif
bool isRestored() const;
@ -629,9 +612,6 @@ namespace BitTorrent @@ -629,9 +612,6 @@ namespace BitTorrent
void populateAdditionalTrackers();
void enableIPFilter();
void disableIPFilter();
#if defined(Q_OS_WIN)
void applyOSMemoryPriority() const;
#endif
void processTrackerStatuses();
void populateExcludedFileNamesRegExpList();
void prepareStartup();
@ -795,9 +775,6 @@ namespace BitTorrent @@ -795,9 +775,6 @@ namespace BitTorrent
CachedSettingValue<QStringList> m_excludedFileNames;
CachedSettingValue<QStringList> m_bannedIPs;
CachedSettingValue<ResumeDataStorageType> m_resumeDataStorageType;
#if defined(Q_OS_WIN)
CachedSettingValue<OSMemoryPriority> m_OSMemoryPriority;
#endif
bool m_isRestored = false;

25
src/base/interfaces/iapplication.h

@ -30,11 +30,31 @@ @@ -30,11 +30,31 @@
#pragma once
#include <QtGlobal>
#include <QMetaObject>
class QString;
class Path;
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
{
public:
@ -58,4 +78,9 @@ public: @@ -58,4 +78,9 @@ public:
virtual int memoryWorkingSetLimit() const = 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 @@ -185,7 +185,7 @@ void AdvancedSettings::saveAdvancedSettings() const
app()->setMemoryWorkingSetLimit(m_spinBoxMemoryWorkingSetLimit.value());
#endif
#if defined(Q_OS_WIN)
session->setOSMemoryPriority(m_comboBoxOSMemoryPriority.currentData().value<BitTorrent::OSMemoryPriority>());
app()->setProcessMemoryPriority(m_comboBoxOSMemoryPriority.currentData().value<MemoryPriority>());
#endif
// Async IO threads
session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value());
@ -422,12 +422,12 @@ void AdvancedSettings::loadAdvancedSettings() @@ -422,12 +422,12 @@ void AdvancedSettings::loadAdvancedSettings()
, &m_spinBoxMemoryWorkingSetLimit);
#endif
#if defined(Q_OS_WIN)
m_comboBoxOSMemoryPriority.addItem(tr("Normal"), QVariant::fromValue(BitTorrent::OSMemoryPriority::Normal));
m_comboBoxOSMemoryPriority.addItem(tr("Below normal"), QVariant::fromValue(BitTorrent::OSMemoryPriority::BelowNormal));
m_comboBoxOSMemoryPriority.addItem(tr("Medium"), QVariant::fromValue(BitTorrent::OSMemoryPriority::Medium));
m_comboBoxOSMemoryPriority.addItem(tr("Low"), QVariant::fromValue(BitTorrent::OSMemoryPriority::Low));
m_comboBoxOSMemoryPriority.addItem(tr("Very low"), QVariant::fromValue(BitTorrent::OSMemoryPriority::VeryLow));
m_comboBoxOSMemoryPriority.setCurrentIndex(m_comboBoxOSMemoryPriority.findData(QVariant::fromValue(session->getOSMemoryPriority())));
m_comboBoxOSMemoryPriority.addItem(tr("Normal"), QVariant::fromValue(MemoryPriority::Normal));
m_comboBoxOSMemoryPriority.addItem(tr("Below normal"), QVariant::fromValue(MemoryPriority::BelowNormal));
m_comboBoxOSMemoryPriority.addItem(tr("Medium"), QVariant::fromValue(MemoryPriority::Medium));
m_comboBoxOSMemoryPriority.addItem(tr("Low"), QVariant::fromValue(MemoryPriority::Low));
m_comboBoxOSMemoryPriority.addItem(tr("Very low"), QVariant::fromValue(MemoryPriority::VeryLow));
m_comboBoxOSMemoryPriority.setCurrentIndex(m_comboBoxOSMemoryPriority.findData(QVariant::fromValue(app()->processMemoryPriority())));
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"(?)"))
, &m_comboBoxOSMemoryPriority);

Loading…
Cancel
Save