Added config option "cpu/max-threads-hint" and command line option "--cpu-max-threads-hint".

This commit is contained in:
XMRig 2019-09-28 02:02:20 +07:00
parent daed23422e
commit 7c463849cc
14 changed files with 97 additions and 57 deletions

View file

@ -44,6 +44,7 @@ class Threads
public: public:
inline bool has(const char *profile) const { return m_profiles.count(profile) > 0; } inline bool has(const char *profile) const { return m_profiles.count(profile) > 0; }
inline bool isDisabled(const Algorithm &algo) const { return m_disabled.count(algo) > 0; } inline bool isDisabled(const Algorithm &algo) const { return m_disabled.count(algo) > 0; }
inline bool isEmpty() const { return m_profiles.empty(); }
inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); } inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); }
inline const T &get(const Algorithm &algo, bool strict = false) const { return get(profileName(algo, strict)); } inline const T &get(const Algorithm &algo, bool strict = false) const { return get(profileName(algo, strict)); }
inline void disable(const Algorithm &algo) { m_disabled.insert(algo); } inline void disable(const Algorithm &algo) { m_disabled.insert(algo); }

View file

@ -35,6 +35,7 @@ static const char *kCn = "cn";
static const char *kEnabled = "enabled"; static const char *kEnabled = "enabled";
static const char *kHugePages = "huge-pages"; static const char *kHugePages = "huge-pages";
static const char *kHwAes = "hw-aes"; static const char *kHwAes = "hw-aes";
static const char *kMaxThreadsHint = "max-threads-hint";
static const char *kPriority = "priority"; static const char *kPriority = "priority";
#ifdef XMRIG_FEATURE_ASM #ifdef XMRIG_FEATURE_ASM
@ -72,11 +73,6 @@ extern template class Threads<CpuThreads>;
} }
xmrig::CpuConfig::CpuConfig()
{
}
bool xmrig::CpuConfig::isHwAES() const bool xmrig::CpuConfig::isHwAES() const
{ {
return (m_aes == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aes) == AES_HW; return (m_aes == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aes) == AES_HW;
@ -95,6 +91,10 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const
obj.AddMember(StringRef(kHwAes), m_aes == AES_AUTO ? Value(kNullType) : Value(m_aes == AES_HW), allocator); obj.AddMember(StringRef(kHwAes), m_aes == AES_AUTO ? Value(kNullType) : Value(m_aes == AES_HW), allocator);
obj.AddMember(StringRef(kPriority), priority() != -1 ? Value(priority()) : Value(kNullType), allocator); obj.AddMember(StringRef(kPriority), priority() != -1 ? Value(priority()) : Value(kNullType), allocator);
if (m_threads.isEmpty()) {
obj.AddMember(StringRef(kMaxThreadsHint), m_limit, allocator);
}
# ifdef XMRIG_FEATURE_ASM # ifdef XMRIG_FEATURE_ASM
obj.AddMember(StringRef(kAsm), m_assembly.toJSON(), allocator); obj.AddMember(StringRef(kAsm), m_assembly.toJSON(), allocator);
# endif # endif
@ -133,6 +133,7 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value, uint32_t version)
if (value.IsObject()) { if (value.IsObject()) {
m_enabled = Json::getBool(value, kEnabled, m_enabled); m_enabled = Json::getBool(value, kEnabled, m_enabled);
m_hugePages = Json::getBool(value, kHugePages, m_hugePages); m_hugePages = Json::getBool(value, kHugePages, m_hugePages);
m_limit = Json::getUint(value, kMaxThreadsHint, m_limit);
setAesMode(Json::getValue(value, kHwAes)); setAesMode(Json::getValue(value, kHwAes));
setPriority(Json::getInt(value, kPriority, -1)); setPriority(Json::getInt(value, kPriority, -1));
@ -168,28 +169,28 @@ void xmrig::CpuConfig::generate()
ICpuInfo *cpu = Cpu::info(); ICpuInfo *cpu = Cpu::info();
m_threads.disable(Algorithm::CN_0); m_threads.disable(Algorithm::CN_0);
m_threads.move(kCn, cpu->threads(Algorithm::CN_0)); m_threads.move(kCn, cpu->threads(Algorithm::CN_0, m_limit));
# ifdef XMRIG_ALGO_CN_GPU # ifdef XMRIG_ALGO_CN_GPU
m_threads.move(kCnGPU, cpu->threads(Algorithm::CN_GPU)); m_threads.move(kCnGPU, cpu->threads(Algorithm::CN_GPU, m_limit));
# endif # endif
# ifdef XMRIG_ALGO_CN_LITE # ifdef XMRIG_ALGO_CN_LITE
m_threads.disable(Algorithm::CN_LITE_0); m_threads.disable(Algorithm::CN_LITE_0);
m_threads.move(kCnLite, cpu->threads(Algorithm::CN_LITE_1)); m_threads.move(kCnLite, cpu->threads(Algorithm::CN_LITE_1, m_limit));
# endif # endif
# ifdef XMRIG_ALGO_CN_HEAVY # ifdef XMRIG_ALGO_CN_HEAVY
m_threads.move(kCnHeavy, cpu->threads(Algorithm::CN_HEAVY_0)); m_threads.move(kCnHeavy, cpu->threads(Algorithm::CN_HEAVY_0, m_limit));
# endif # endif
# ifdef XMRIG_ALGO_CN_PICO # ifdef XMRIG_ALGO_CN_PICO
m_threads.move(kCnPico, cpu->threads(Algorithm::CN_PICO_0)); m_threads.move(kCnPico, cpu->threads(Algorithm::CN_PICO_0, m_limit));
# endif # endif
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
m_threads.move(kRx, cpu->threads(Algorithm::RX_0)); m_threads.move(kRx, cpu->threads(Algorithm::RX_0, m_limit));
m_threads.move(kRxWOW, cpu->threads(Algorithm::RX_WOW)); m_threads.move(kRxWOW, cpu->threads(Algorithm::RX_WOW, m_limit));
# endif # endif
generateArgon2(); generateArgon2();
@ -199,7 +200,7 @@ void xmrig::CpuConfig::generate()
void xmrig::CpuConfig::generateArgon2() void xmrig::CpuConfig::generateArgon2()
{ {
# ifdef XMRIG_ALGO_ARGON2 # ifdef XMRIG_ALGO_ARGON2
m_threads.move(kArgon2, Cpu::info()->threads(Algorithm::AR2_CHUKWA)); m_threads.move(kArgon2, Cpu::info()->threads(Algorithm::AR2_CHUKWA, m_limit));
# endif # endif
} }

View file

@ -44,7 +44,7 @@ public:
AES_SOFT AES_SOFT
}; };
CpuConfig(); CpuConfig() = default;
bool isHwAES() const; bool isHwAES() const;
rapidjson::Value toJSON(rapidjson::Document &doc) const; rapidjson::Value toJSON(rapidjson::Document &doc) const;
@ -74,6 +74,7 @@ private:
int m_priority = -1; int m_priority = -1;
String m_argon2Impl; String m_argon2Impl;
Threads<CpuThreads> m_threads; Threads<CpuThreads> m_threads;
uint32_t m_limit = 100;
}; };

View file

@ -50,7 +50,7 @@ public:
virtual bool hasAVX2() const = 0; virtual bool hasAVX2() const = 0;
virtual const char *backend() const = 0; virtual const char *backend() const = 0;
virtual const char *brand() const = 0; virtual const char *brand() const = 0;
virtual CpuThreads threads(const Algorithm &algorithm) const = 0; virtual CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const = 0;
virtual size_t cores() const = 0; virtual size_t cores() const = 0;
virtual size_t L2() const = 0; virtual size_t L2() const = 0;
virtual size_t L3() const = 0; virtual size_t L3() const = 0;

View file

@ -23,10 +23,10 @@
*/ */
#include <algorithm> #include <algorithm>
#include <assert.h> #include <cassert>
#include <math.h> #include <cmath>
#include <stdio.h> #include <cstdio>
#include <string.h> #include <cstring>
#include "3rdparty/libcpuid/libcpuid.h" #include "3rdparty/libcpuid/libcpuid.h"
@ -109,7 +109,7 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() :
} }
xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) const xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const
{ {
if (threads() == 1) { if (threads() == 1) {
return 1; return 1;
@ -153,5 +153,12 @@ xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) co
} }
# endif # endif
return CpuThreads(std::max<size_t>(std::min<size_t>(count, threads()), 1), intensity); if (limit > 0 && limit < 100) {
count = std::min(count, static_cast<size_t>(round(threads() * (limit / 100.0))));
}
else {
count = std::min(count, threads());
}
return CpuThreads(std::max<size_t>(count, 1), intensity);
} }

View file

@ -38,7 +38,7 @@ public:
AdvancedCpuInfo(); AdvancedCpuInfo();
protected: protected:
CpuThreads threads(const Algorithm &algorithm) const override; CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
inline Assembly::Id assembly() const override { return m_assembly; } inline Assembly::Id assembly() const override { return m_assembly; }
inline bool hasAES() const override { return m_aes; } inline bool hasAES() const override { return m_aes; }

View file

@ -179,7 +179,7 @@ const char *xmrig::BasicCpuInfo::backend() const
} }
xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const
{ {
const size_t count = std::thread::hardware_concurrency(); const size_t count = std::thread::hardware_concurrency();

View file

@ -39,7 +39,7 @@ public:
protected: protected:
const char *backend() const override; const char *backend() const override;
CpuThreads threads(const Algorithm &algorithm) const override; CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
inline Assembly::Id assembly() const override { return m_assembly; } inline Assembly::Id assembly() const override { return m_assembly; }
inline bool hasAES() const override { return m_aes; } inline bool hasAES() const override { return m_aes; }

View file

@ -29,6 +29,7 @@
#include <algorithm> #include <algorithm>
#include <cmath>
#include <hwloc.h> #include <hwloc.h>
@ -127,9 +128,7 @@ static inline bool isCacheExclusive(hwloc_obj_t obj)
} // namespace xmrig } // namespace xmrig
xmrig::HwlocCpuInfo::HwlocCpuInfo() : BasicCpuInfo(), xmrig::HwlocCpuInfo::HwlocCpuInfo()
m_backend(),
m_cache()
{ {
m_threads = 0; m_threads = 0;
@ -149,7 +148,7 @@ xmrig::HwlocCpuInfo::HwlocCpuInfo() : BasicCpuInfo(),
# endif # endif
const std::vector<hwloc_obj_t> packages = findByType(hwloc_get_root_obj(m_topology), HWLOC_OBJ_PACKAGE); const std::vector<hwloc_obj_t> packages = findByType(hwloc_get_root_obj(m_topology), HWLOC_OBJ_PACKAGE);
if (packages.size()) { if (!packages.empty()) {
const char *value = hwloc_obj_get_info_by_name(packages[0], "CPUModel"); const char *value = hwloc_obj_get_info_by_name(packages[0], "CPUModel");
if (value) { if (value) {
strncpy(m_brand, value, 64); strncpy(m_brand, value, 64);
@ -202,10 +201,10 @@ xmrig::HwlocCpuInfo::~HwlocCpuInfo()
} }
xmrig::CpuThreads xmrig::HwlocCpuInfo::threads(const Algorithm &algorithm) const xmrig::CpuThreads xmrig::HwlocCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const
{ {
if (L2() == 0 && L3() == 0) { if (L2() == 0 && L3() == 0) {
return BasicCpuInfo::threads(algorithm); return BasicCpuInfo::threads(algorithm, limit);
} }
const unsigned depth = L3() > 0 ? 3 : 2; const unsigned depth = L3() > 0 ? 3 : 2;
@ -218,21 +217,37 @@ xmrig::CpuThreads xmrig::HwlocCpuInfo::threads(const Algorithm &algorithm) const
findCache(hwloc_get_root_obj(m_topology), depth, depth, [&caches](hwloc_obj_t found) { caches.emplace_back(found); }); findCache(hwloc_get_root_obj(m_topology), depth, depth, [&caches](hwloc_obj_t found) { caches.emplace_back(found); });
if (limit > 0 && limit < 100 && !caches.empty()) {
const double maxTotalThreads = round(m_threads * (limit / 100.0));
const auto maxPerCache = std::max(static_cast<int>(round(maxTotalThreads / caches.size())), 1);
int remaining = std::max(static_cast<int>(maxTotalThreads), 1);
for (hwloc_obj_t cache : caches) { for (hwloc_obj_t cache : caches) {
processTopLevelCache(cache, algorithm, threads); processTopLevelCache(cache, algorithm, threads, std::min(maxPerCache, remaining));
remaining -= maxPerCache;
if (remaining <= 0) {
break;
}
}
}
else {
for (hwloc_obj_t cache : caches) {
processTopLevelCache(cache, algorithm, threads, 0);
}
} }
if (threads.isEmpty()) { if (threads.isEmpty()) {
LOG_WARN("hwloc auto configuration for algorithm \"%s\" failed.", algorithm.shortName()); LOG_WARN("hwloc auto configuration for algorithm \"%s\" failed.", algorithm.shortName());
return BasicCpuInfo::threads(algorithm); return BasicCpuInfo::threads(algorithm, limit);
} }
return threads; return threads;
} }
void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorithm &algorithm, CpuThreads &threads) const void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorithm &algorithm, CpuThreads &threads, size_t limit) const
{ {
constexpr size_t oneMiB = 1024u * 1024u; constexpr size_t oneMiB = 1024u * 1024u;
@ -296,6 +311,10 @@ void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorith
} }
# endif # endif
if (limit > 0) {
cacheHashes = std::min(cacheHashes, limit);
}
if (cacheHashes >= PUs) { if (cacheHashes >= PUs) {
for (hwloc_obj_t core : cores) { for (hwloc_obj_t core : cores) {
const std::vector<hwloc_obj_t> units = findByType(core, HWLOC_OBJ_PU); const std::vector<hwloc_obj_t> units = findByType(core, HWLOC_OBJ_PU);

View file

@ -27,10 +27,11 @@
#include "backend/cpu/platform/BasicCpuInfo.h" #include "backend/cpu/platform/BasicCpuInfo.h"
#include "base/tools/Object.h"
typedef struct hwloc_obj *hwloc_obj_t; using hwloc_obj_t = struct hwloc_obj *;
typedef struct hwloc_topology *hwloc_topology_t; using hwloc_topology_t = struct hwloc_topology *;
namespace xmrig { namespace xmrig {
@ -39,6 +40,9 @@ namespace xmrig {
class HwlocCpuInfo : public BasicCpuInfo class HwlocCpuInfo : public BasicCpuInfo
{ {
public: public:
XMRIG_DISABLE_COPY_MOVE(HwlocCpuInfo)
enum Feature : uint32_t { enum Feature : uint32_t {
SET_THISTHREAD_MEMBIND = 1 SET_THISTHREAD_MEMBIND = 1
}; };
@ -51,7 +55,7 @@ public:
static inline const std::vector<uint32_t> &nodeIndexes() { return m_nodeIndexes; } static inline const std::vector<uint32_t> &nodeIndexes() { return m_nodeIndexes; }
protected: protected:
CpuThreads threads(const Algorithm &algorithm) const override; CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
inline const char *backend() const override { return m_backend; } inline const char *backend() const override { return m_backend; }
inline size_t cores() const override { return m_cores; } inline size_t cores() const override { return m_cores; }
@ -61,14 +65,14 @@ protected:
inline size_t packages() const override { return m_packages; } inline size_t packages() const override { return m_packages; }
private: private:
void processTopLevelCache(hwloc_obj_t obj, const Algorithm &algorithm, CpuThreads &threads) const; void processTopLevelCache(hwloc_obj_t obj, const Algorithm &algorithm, CpuThreads &threads, size_t limit) const;
static std::vector<uint32_t> m_nodeIndexes; static std::vector<uint32_t> m_nodeIndexes;
static uint32_t m_features; static uint32_t m_features;
char m_backend[20]; char m_backend[20] = { 0 };
hwloc_topology_t m_topology; hwloc_topology_t m_topology = nullptr;
size_t m_cache[5]; size_t m_cache[5] = { 0 };
size_t m_cores = 0; size_t m_cores = 0;
size_t m_nodes = 0; size_t m_nodes = 0;
size_t m_packages = 0; size_t m_packages = 0;

View file

@ -88,6 +88,7 @@ public:
AssemblyKey = 1015, AssemblyKey = 1015,
RandomXInitKey = 1022, RandomXInitKey = 1022,
RandomXNumaKey = 1023, RandomXNumaKey = 1023,
CPUMaxThreadsKey = 1026,
// xmrig amd // xmrig amd
OclPlatformKey = 1400, OclPlatformKey = 1400,

View file

@ -138,6 +138,9 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const
return transformUint64(doc, key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10)); return transformUint64(doc, key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10));
} }
case IConfig::CPUMaxThreadsKey: /* --cpu-max-threads-hint */
return set(doc, kCpu, "max-threads-hint", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
# ifdef XMRIG_FEATURE_ASM # ifdef XMRIG_FEATURE_ASM
case IConfig::AssemblyKey: /* --asm */ case IConfig::AssemblyKey: /* --asm */
return set(doc, kCpu, "asm", arg); return set(doc, kCpu, "asm", arg);

View file

@ -82,6 +82,8 @@ static const option options[] = {
{ "userpass", 1, nullptr, IConfig::UserpassKey }, { "userpass", 1, nullptr, IConfig::UserpassKey },
{ "rig-id", 1, nullptr, IConfig::RigIdKey }, { "rig-id", 1, nullptr, IConfig::RigIdKey },
{ "no-cpu", 0, nullptr, IConfig::CPUKey }, { "no-cpu", 0, nullptr, IConfig::CPUKey },
{ "max-cpu-usage", 1, nullptr, IConfig::CPUMaxThreadsKey },
{ "cpu-max-threads-hint", 1, nullptr, IConfig::CPUMaxThreadsKey },
# ifdef XMRIG_FEATURE_TLS # ifdef XMRIG_FEATURE_TLS
{ "tls", 0, nullptr, IConfig::TlsKey }, { "tls", 0, nullptr, IConfig::TlsKey },
{ "tls-fingerprint", 1, nullptr, IConfig::FingerprintKey }, { "tls-fingerprint", 1, nullptr, IConfig::FingerprintKey },

View file

@ -76,6 +76,7 @@ static inline const std::string &usage()
u += " -v, --av=N algorithm variation, 0 auto select\n"; u += " -v, --av=N algorithm variation, 0 auto select\n";
u += " --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n"; u += " --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n";
u += " --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n"; u += " --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n";
u += " --cpu-max-threads-hint=N maximum CPU threads count (in percentage) hint for autoconfig\n";
u += " --no-huge-pages disable huge pages support\n"; u += " --no-huge-pages disable huge pages support\n";
u += " --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer\n"; u += " --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer\n";