mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-10 23:07:59 +00:00
parent
7377974731
commit
bc937d38a2
@ -39,6 +39,8 @@
|
||||
#include <memory>
|
||||
#include <Windows.h>
|
||||
#include <Shellapi.h>
|
||||
#elif defined(Q_OS_UNIX)
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include <QAtomicInt>
|
||||
@ -127,9 +129,7 @@ Application::Application(int &argc, char **argv)
|
||||
, m_storeFileLoggerAge(FILELOGGER_SETTINGS_KEY(u"Age"_qs))
|
||||
, m_storeFileLoggerAgeType(FILELOGGER_SETTINGS_KEY(u"AgeType"_qs))
|
||||
, m_storeFileLoggerPath(FILELOGGER_SETTINGS_KEY(u"Path"_qs))
|
||||
#ifdef Q_OS_WIN
|
||||
, m_storeMemoryWorkingSetLimit(SETTINGS_KEY(u"MemoryWorkingSetLimit"_qs))
|
||||
#endif
|
||||
{
|
||||
qRegisterMetaType<Log::Msg>("Log::Msg");
|
||||
qRegisterMetaType<Log::Peer>("Log::Peer");
|
||||
@ -206,7 +206,6 @@ const QBtCommandLineParameters &Application::commandLineArgs() const
|
||||
return m_commandLineArgs;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
int Application::memoryWorkingSetLimit() const
|
||||
{
|
||||
return m_storeMemoryWorkingSetLimit.get(512);
|
||||
@ -220,7 +219,6 @@ void Application::setMemoryWorkingSetLimit(const int size)
|
||||
m_storeMemoryWorkingSetLimit = size;
|
||||
applyMemoryWorkingSetLimit();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Application::isFileLoggerEnabled() const
|
||||
{
|
||||
@ -598,9 +596,7 @@ void Application::processParams(const QStringList ¶ms)
|
||||
|
||||
int Application::exec(const QStringList ¶ms)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
applyMemoryWorkingSetLimit();
|
||||
#endif
|
||||
|
||||
Net::ProxyConfigurationManager::initInstance();
|
||||
Net::DownloadManager::initInstance();
|
||||
@ -771,28 +767,43 @@ void Application::shutdownCleanup(QSessionManager &manager)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void Application::applyMemoryWorkingSetLimit()
|
||||
{
|
||||
const SIZE_T UNIT_SIZE = 1024 * 1024; // MiB
|
||||
const SIZE_T maxSize = memoryWorkingSetLimit() * UNIT_SIZE;
|
||||
const SIZE_T minSize = std::min<SIZE_T>((64 * UNIT_SIZE), (maxSize / 2));
|
||||
const size_t MiB = 1024 * 1024;
|
||||
const QString logMessage = tr("Failed to set physical memory (RAM) usage limit. Error code: %1. Error message: \"%2\"");
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
const SIZE_T maxSize = memoryWorkingSetLimit() * MiB;
|
||||
const SIZE_T minSize = std::min((64 * MiB), (maxSize / 2));
|
||||
if (!::SetProcessWorkingSetSizeEx(::GetCurrentProcess(), minSize, maxSize, QUOTA_LIMITS_HARDWS_MAX_ENABLE))
|
||||
{
|
||||
const DWORD errorCode = ::GetLastError();
|
||||
QString message;
|
||||
LPVOID lpMsgBuf = nullptr;
|
||||
if (::FormatMessageW((FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS)
|
||||
, nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&lpMsgBuf), 0, nullptr))
|
||||
const DWORD msgLength = ::FormatMessageW((FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS)
|
||||
, nullptr, errorCode, LANG_USER_DEFAULT, reinterpret_cast<LPWSTR>(&lpMsgBuf), 0, nullptr);
|
||||
if (msgLength > 0)
|
||||
{
|
||||
message = QString::fromWCharArray(reinterpret_cast<LPWSTR>(lpMsgBuf)).trimmed();
|
||||
::LocalFree(lpMsgBuf);
|
||||
}
|
||||
LogMsg(tr("Failed to set physical memory (RAM) usage limit. Error code: %1. Error message: \"%2\"")
|
||||
.arg(QString::number(errorCode), message), Log::WARNING);
|
||||
LogMsg(logMessage.arg(QString::number(errorCode), message), Log::WARNING);
|
||||
}
|
||||
#elif defined(Q_OS_UNIX)
|
||||
// has no effect on linux but it might be meaningful for other OS
|
||||
rlimit limit {};
|
||||
|
||||
if (::getrlimit(RLIMIT_RSS, &limit) != 0)
|
||||
return;
|
||||
|
||||
limit.rlim_cur = memoryWorkingSetLimit() * MiB;
|
||||
if (::setrlimit(RLIMIT_RSS, &limit) != 0)
|
||||
{
|
||||
const auto message = QString::fromLocal8Bit(strerror(errno));
|
||||
LogMsg(logMessage.arg(QString::number(errno), message), Log::WARNING);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::cleanup()
|
||||
{
|
||||
|
@ -113,10 +113,8 @@ public:
|
||||
int fileLoggerAgeType() const override;
|
||||
void setFileLoggerAgeType(int value) override;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
int memoryWorkingSetLimit() const override;
|
||||
void setMemoryWorkingSetLimit(int size) override;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
QPointer<MainWindow> mainWindow() override;
|
||||
@ -137,9 +135,7 @@ private:
|
||||
void processParams(const QStringList ¶ms);
|
||||
void runExternalProgram(const BitTorrent::Torrent *torrent) const;
|
||||
void sendNotificationEmail(const BitTorrent::Torrent *torrent);
|
||||
#ifdef Q_OS_WIN
|
||||
void applyMemoryWorkingSetLimit();
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
#ifdef Q_OS_MACOS
|
||||
@ -166,9 +162,7 @@ private:
|
||||
SettingValue<int> m_storeFileLoggerAge;
|
||||
SettingValue<int> m_storeFileLoggerAgeType;
|
||||
SettingValue<Path> m_storeFileLoggerPath;
|
||||
#ifdef Q_OS_WIN
|
||||
SettingValue<int> m_storeMemoryWorkingSetLimit;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
QPointer<MainWindow> m_window;
|
||||
|
@ -30,8 +30,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
class QString;
|
||||
|
||||
class Path;
|
||||
@ -58,8 +56,6 @@ public:
|
||||
virtual int fileLoggerAgeType() const = 0;
|
||||
virtual void setFileLoggerAgeType(int value) = 0;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
virtual int memoryWorkingSetLimit() const = 0;
|
||||
virtual void setMemoryWorkingSetLimit(int size) = 0;
|
||||
#endif
|
||||
};
|
||||
|
@ -62,9 +62,9 @@ namespace
|
||||
// qBittorrent section
|
||||
QBITTORRENT_HEADER,
|
||||
RESUME_DATA_STORAGE,
|
||||
MEMORY_WORKING_SET_LIMIT,
|
||||
#if defined(Q_OS_WIN)
|
||||
OS_MEMORY_PRIORITY,
|
||||
MEMORY_WORKING_SET_LIMIT,
|
||||
#endif
|
||||
// network interface
|
||||
NETWORK_IFACE,
|
||||
@ -177,6 +177,8 @@ void AdvancedSettings::saveAdvancedSettings()
|
||||
? BitTorrent::ResumeDataStorageType::Legacy
|
||||
: BitTorrent::ResumeDataStorageType::SQLite);
|
||||
|
||||
// Physical memory (RAM) usage limit
|
||||
dynamic_cast<IApplication *>(QCoreApplication::instance())->setMemoryWorkingSetLimit(m_spinBoxMemoryWorkingSetLimit.value());
|
||||
#if defined(Q_OS_WIN)
|
||||
BitTorrent::OSMemoryPriority prio = BitTorrent::OSMemoryPriority::Normal;
|
||||
switch (m_comboBoxOSMemoryPriority.currentIndex())
|
||||
@ -199,8 +201,6 @@ void AdvancedSettings::saveAdvancedSettings()
|
||||
break;
|
||||
}
|
||||
session->setOSMemoryPriority(prio);
|
||||
|
||||
dynamic_cast<IApplication *>(QCoreApplication::instance())->setMemoryWorkingSetLimit(m_spinBoxMemoryWorkingSetLimit.value());
|
||||
#endif
|
||||
// Async IO threads
|
||||
session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value());
|
||||
@ -419,6 +419,14 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
m_comboBoxResumeDataStorage.setCurrentIndex((session->resumeDataStorageType() == BitTorrent::ResumeDataStorageType::Legacy) ? 0 : 1);
|
||||
addRow(RESUME_DATA_STORAGE, tr("Resume data storage type (requires restart)"), &m_comboBoxResumeDataStorage);
|
||||
|
||||
// Physical memory (RAM) usage limit
|
||||
m_spinBoxMemoryWorkingSetLimit.setMinimum(1);
|
||||
m_spinBoxMemoryWorkingSetLimit.setMaximum(std::numeric_limits<int>::max());
|
||||
m_spinBoxMemoryWorkingSetLimit.setSuffix(tr(" MiB"));
|
||||
m_spinBoxMemoryWorkingSetLimit.setToolTip(tr("This option is less effective on Linux"));
|
||||
m_spinBoxMemoryWorkingSetLimit.setValue(dynamic_cast<IApplication *>(QCoreApplication::instance())->memoryWorkingSetLimit());
|
||||
addRow(MEMORY_WORKING_SET_LIMIT, (tr("Physical memory (RAM) usage limit") + u' ' + makeLink(u"https://wikipedia.org/wiki/Working_set", u"(?)"))
|
||||
, &m_spinBoxMemoryWorkingSetLimit);
|
||||
#if defined(Q_OS_WIN)
|
||||
m_comboBoxOSMemoryPriority.addItems({tr("Normal"), tr("Below normal"), tr("Medium"), tr("Low"), tr("Very low")});
|
||||
int OSMemoryPriorityIndex = 0;
|
||||
@ -445,17 +453,7 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
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);
|
||||
|
||||
m_spinBoxMemoryWorkingSetLimit.setMinimum(1);
|
||||
m_spinBoxMemoryWorkingSetLimit.setMaximum(std::numeric_limits<int>::max());
|
||||
m_spinBoxMemoryWorkingSetLimit.setSuffix(tr(" MiB"));
|
||||
m_spinBoxMemoryWorkingSetLimit.setValue(dynamic_cast<IApplication *>(QCoreApplication::instance())->memoryWorkingSetLimit());
|
||||
|
||||
addRow(MEMORY_WORKING_SET_LIMIT, (tr("Physical memory (RAM) usage limit")
|
||||
+ u' ' + makeLink(u"https://wikipedia.org/wiki/Working_set", u"(?)"))
|
||||
, &m_spinBoxMemoryWorkingSetLimit);
|
||||
#endif
|
||||
|
||||
// Async IO threads
|
||||
m_spinBoxAsyncIOThreads.setMinimum(1);
|
||||
m_spinBoxAsyncIOThreads.setMaximum(1024);
|
||||
|
@ -58,7 +58,7 @@ private:
|
||||
void loadAdvancedSettings();
|
||||
template <typename T> void addRow(int row, const QString &text, T *widget);
|
||||
|
||||
QSpinBox m_spinBoxAsyncIOThreads, m_spinBoxFilePoolSize, m_spinBoxCheckingMemUsage, m_spinBoxDiskQueueSize,
|
||||
QSpinBox m_spinBoxMemoryWorkingSetLimit, m_spinBoxAsyncIOThreads, m_spinBoxFilePoolSize, m_spinBoxCheckingMemUsage, m_spinBoxDiskQueueSize,
|
||||
m_spinBoxSaveResumeDataInterval, m_spinBoxOutgoingPortsMin, m_spinBoxOutgoingPortsMax, m_spinBoxUPnPLeaseDuration, m_spinBoxPeerToS,
|
||||
m_spinBoxListRefresh, m_spinBoxTrackerPort, m_spinBoxSendBufferWatermark, m_spinBoxSendBufferLowWatermark,
|
||||
m_spinBoxSendBufferWatermarkFactor, m_spinBoxConnectionSpeed, m_spinBoxSocketBacklogSize, m_spinBoxMaxConcurrentHTTPAnnounces, m_spinBoxStopTrackerTimeout,
|
||||
@ -82,7 +82,6 @@ private:
|
||||
// OS dependent settings
|
||||
#if defined(Q_OS_WIN)
|
||||
QComboBox m_comboBoxOSMemoryPriority;
|
||||
QSpinBox m_spinBoxMemoryWorkingSetLimit;
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
|
@ -45,6 +45,7 @@
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/global.h"
|
||||
#include "base/interfaces/iapplication.h"
|
||||
#include "base/net/portforwarder.h"
|
||||
#include "base/net/proxyconfigurationmanager.h"
|
||||
#include "base/path.h"
|
||||
@ -285,6 +286,8 @@ void AppController::preferencesAction()
|
||||
|
||||
// Advanced settings
|
||||
// qBitorrent preferences
|
||||
// Physical memory (RAM) usage limit
|
||||
data[u"memory_working_set_limit"_qs] = dynamic_cast<IApplication *>(QCoreApplication::instance())->memoryWorkingSetLimit();
|
||||
// Current network interface
|
||||
data[u"current_network_interface"_qs] = session->networkInterface();
|
||||
// Current network interface address
|
||||
@ -738,6 +741,9 @@ void AppController::setPreferencesAction()
|
||||
|
||||
// Advanced settings
|
||||
// qBittorrent preferences
|
||||
// Physical memory (RAM) usage limit
|
||||
if (hasKey(u"memory_working_set_limit"_qs))
|
||||
dynamic_cast<IApplication *>(QCoreApplication::instance())->setMemoryWorkingSetLimit(it.value().toInt());
|
||||
// Current network interface
|
||||
if (hasKey(u"current_network_interface"_qs))
|
||||
{
|
||||
|
@ -48,7 +48,7 @@
|
||||
#include "base/utils/version.h"
|
||||
#include "api/isessionmanager.h"
|
||||
|
||||
inline const Utils::Version<int, 3, 2> API_VERSION {2, 8, 9};
|
||||
inline const Utils::Version<int, 3, 2> API_VERSION {2, 8, 10};
|
||||
|
||||
class APIController;
|
||||
class AuthController;
|
||||
|
@ -903,6 +903,14 @@
|
||||
<fieldset class="settings">
|
||||
<legend>QBT_TR(qBittorrent Section)QBT_TR[CONTEXT=OptionsDialog] (<a href="https://github.com/qbittorrent/qBittorrent/wiki/Explanation-of-Options-in-qBittorrent#Advanced" target="_blank">QBT_TR(Open documentation)QBT_TR[CONTEXT=HttpServer]</a>)</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="memoryWorkingSetLimit">QBT_TR(Physical memory (RAM) usage limit:)QBT_TR[CONTEXT=OptionsDialog] <a href="https://wikipedia.org/wiki/Working_set" target="_blank">(?)</a></label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="memoryWorkingSetLimit" style="width: 15em;" title="QBT_TR(This option is less effective on Linux)QBT_TR[CONTEXT=OptionsDialog]"> QBT_TR(MiB)QBT_TR[CONTEXT=OptionsDialog]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="networkInterface">QBT_TR(Network interface:)QBT_TR[CONTEXT=OptionsDialog]</label>
|
||||
@ -1947,6 +1955,7 @@
|
||||
|
||||
// Advanced settings
|
||||
// qBittorrent section
|
||||
$('memoryWorkingSetLimit').setProperty('value', pref.memory_working_set_limit);
|
||||
updateNetworkInterfaces(pref.current_network_interface);
|
||||
updateInterfaceAddresses(pref.current_network_interface, pref.current_interface_address);
|
||||
$('saveResumeDataInterval').setProperty('value', pref.save_resume_data_interval);
|
||||
@ -2346,6 +2355,7 @@
|
||||
|
||||
// Update advanced settings
|
||||
// qBittorrent section
|
||||
settings.set('memory_working_set_limit', $('memoryWorkingSetLimit').getProperty('value'));
|
||||
settings.set('current_network_interface', $('networkInterface').getProperty('value'));
|
||||
settings.set('current_interface_address', $('optionalIPAddressToBind').getProperty('value'));
|
||||
settings.set('save_resume_data_interval', $('saveResumeDataInterval').getProperty('value'));
|
||||
|
Loading…
Reference in New Issue
Block a user