diff options
-rw-r--r-- | autoAdjust.hpp | 138 | ||||
-rw-r--r-- | cli-miner.cpp | 9 | ||||
-rw-r--r-- | config.txt | 22 | ||||
-rw-r--r-- | jconf.cpp | 88 | ||||
-rw-r--r-- | jconf.h | 3 |
5 files changed, 210 insertions, 50 deletions
diff --git a/autoAdjust.hpp b/autoAdjust.hpp new file mode 100644 index 0000000..8414b3e --- /dev/null +++ b/autoAdjust.hpp @@ -0,0 +1,138 @@ +#pragma once +#include "jconf.h" +#include "console.h" + +#ifdef _WIN32 +#include <windows.h> +#else +#include <unistd.h> +#endif // _WIN32 + +int32_t get_masked(int32_t val, int32_t h, int32_t l) +{ + val &= (0x7FFFFFFF >> (31-(h-l))) << l; + return val >> l; +} + +class autoAdjust +{ +public: + + autoAdjust() + { + } + + void printConfig() + { + printer::inst()->print_str("The configuration for 'cpu_threads_conf' in your config file is 'null'.\n"); + printer::inst()->print_str("The miner evaluates your system and prints a suggestion for the section `cpu_threads_conf` to the terminal.\n"); + printer::inst()->print_str("The values are not optimal, please try to tweak the values based on notes in config.txt.\n"); + printer::inst()->print_str("Please copy & paste the block within the asterisks to your config.\n\n"); + + int32_t L3KB_size = 0; + + if(!detectL3Size(L3KB_size)) + return; + + if(L3KB_size < 1024 || L3KB_size > 102400) + { + printer::inst()->print_msg(L0, "Autoconf failed: L3 size sanity check failed %u.", L3KB_size); + return; + } + + printer::inst()->print_msg(L0, "Autoconf L3 size detected at %u.", L3KB_size); + + uint32_t corecnt; + bool linux_layout; + + detectCPUConf(corecnt, linux_layout); + + printer::inst()->print_msg(L0, "Autoconf cores detected at %u on %s.", corecnt, + linux_layout ? "Linux" : "Windows"); + + printer::inst()->print_str("\n**************** Copy&Paste ****************\n\n"); + printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n"); + + uint32_t aff_id = 0; + char strbuf[256]; + for(uint32_t i=0; i < corecnt; i++) + { + bool double_mode; + + if(L3KB_size < 0) + break; + + double_mode = L3KB_size / 2048 > (int32_t)(corecnt-i); + + snprintf(strbuf, sizeof(strbuf), " { \"low_power_mode\" : %s, \"no_prefetch\" : true, \"affine_to_cpu\" : %u },\n", + double_mode ? "true" : "false", aff_id); + printer::inst()->print_str(strbuf); + + if(linux_layout) + aff_id++; + else + aff_id += 2; + + if(double_mode) + L3KB_size -= 4096; + else + L3KB_size -= 2048; + } + + printer::inst()->print_str("]\n\n**************** Copy&Paste ****************\n"); + } + +private: + bool detectL3Size(int32_t &l3kb) + { + int32_t cpu_info[4]; + char cpustr[13] = {0}; + + jconf::cpuid(0, 0, cpu_info); + memcpy(cpustr, &cpu_info[1], 4); + memcpy(cpustr+4, &cpu_info[3], 4); + memcpy(cpustr+8, &cpu_info[2], 4); + + if(strcmp(cpustr, "GenuineIntel") == 0) + { + jconf::cpuid(4, 3, cpu_info); + + if(get_masked(cpu_info[0], 7, 5) != 3) + { + printer::inst()->print_msg(L0, "Autoconf failed: Couln't find L3 cache page."); + return false; + } + + l3kb = ((get_masked(cpu_info[1], 31, 22) + 1) * (get_masked(cpu_info[1], 21, 12) + 1) * + (get_masked(cpu_info[1], 11, 0) + 1) * (cpu_info[2] + 1)) / 1024; + + return true; + } + else if(strcmp(cpustr, "AuthenticAMD") == 0) + { + jconf::cpuid(0x80000006, 0, cpu_info); + + l3kb = get_masked(cpu_info[3], 31, 18) * 512; + + return true; + } + else + { + printer::inst()->print_msg(L0, "Autoconf failed: Unknown CPU type: %s.", cpustr); + return false; + } + } + + void detectCPUConf(uint32_t &corecnt, bool &linux_layout) + { +#ifdef _WIN32 + SYSTEM_INFO info; + GetSystemInfo(&info); + corecnt = info.dwNumberOfProcessors; + linux_layout = false; +#else + corecnt = sysconf(_SC_NPROCESSORS_ONLN); + linux_layout = true; +#endif // _WIN32 + } +}; diff --git a/cli-miner.cpp b/cli-miner.cpp index deb462e..38fb720 100644 --- a/cli-miner.cpp +++ b/cli-miner.cpp @@ -26,6 +26,7 @@ #include "jconf.h" #include "console.h" #include "donate-level.h" +#include "autoAdjust.hpp" #ifndef CONF_NO_HTTPD # include "httpd.h" @@ -99,6 +100,14 @@ int main(int argc, char *argv[]) return 0; } + if(jconf::inst()->NeedsAutoconf()) + { + autoAdjust adjust; + adjust.printConfig(); + win_exit(); + return 0; + } + if (!minethd::self_test()) { win_exit(); @@ -1,10 +1,3 @@ -/*
- * Number of threads. You can configure them below. Cryptonight uses 2MB of memory, so the optimal setting
- * here is the size of your L3 cache divided by 2. Intel mid-to-high end desktop processors have 2MB of L3
- * cache per physical core. Low end cpus can have 1.5 or 1 MB while Xeons can have 2, 2.5 or 3MB per core.
- */
-"cpu_thread_num" : 2,
-
/*
* Thread configuration for each thread. Make sure it matches the number above.
* low_power_mode - This mode will double the cache usage, and double the single thread performance. It will
@@ -19,11 +12,18 @@ * even or odd numbered cpu numbers. For Linux it will be usually the lower CPU numbers, so for a 4
* physical core CPU you should select cpu numbers 0-3.
*
+ * On the first run the miner will look at your system and suggest a basic configuration that will work,
+ * you can try to tweak it from there to get the best performance.
+ *
+ * A filled out configuration should look like this:
+ * "cpu_threads_conf" :
+ * [
+ * { "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 0 },
+ * { "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 1 },
+ * ],
*/
-"cpu_threads_conf" : [
- { "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 0 },
- { "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 1 },
-],
+"cpu_threads_conf" :
+null,
/*
* LARGE PAGE SUPPORT
@@ -45,7 +45,7 @@ using namespace rapidjson; /* * This enum needs to match index in oConfigValues, otherwise we will get a runtime error */ -enum configEnum { iCpuThreadNum, aCpuThreadsConf, sUseSlowMem, bNiceHashMode, +enum configEnum { aCpuThreadsConf, sUseSlowMem, bNiceHashMode, bTlsMode, bTlsSecureAlgo, sTlsFingerprint, sPoolAddr, sWalletAddr, sPoolPwd, iCallTimeout, iNetRetry, iGiveUpLimit, iVerboseLevel, iAutohashTime, sOutputFile, iHttpdPort, bPreferIpv4 }; @@ -56,10 +56,10 @@ struct configVal { Type iType; }; -//Same order as in configEnum, as per comment above +// Same order as in configEnum, as per comment above +// kNullType means any type configVal oConfigValues[] = { - { iCpuThreadNum, "cpu_thread_num", kNumberType }, - { aCpuThreadsConf, "cpu_threads_conf", kArrayType }, + { aCpuThreadsConf, "cpu_threads_conf", kNullType }, { sUseSlowMem, "use_slow_memory", kStringType }, { bNiceHashMode, "nicehash_nonce", kTrueType }, { bTlsMode, "use_tls", kTrueType }, @@ -84,6 +84,8 @@ inline bool checkType(Type have, Type want) { if(want == have) return true; + else if(want == kNullType) + return true; else if(want == kTrueType && have == kFalseType) return true; else if(want == kFalseType && have == kTrueType) @@ -111,6 +113,9 @@ jconf::jconf() bool jconf::GetThreadConfig(size_t id, thd_cfg &cfg) { + if(!prv->configValues[aCpuThreadsConf]->IsArray()) + return false; + if(id >= prv->configValues[aCpuThreadsConf]->Size()) return false; @@ -206,7 +211,15 @@ bool jconf::PreferIpv4() size_t jconf::GetThreadCount() { - return prv->configValues[aCpuThreadsConf]->Size(); + if(prv->configValues[aCpuThreadsConf]->IsArray()) + return prv->configValues[aCpuThreadsConf]->Size(); + else + return 0; +} + +bool jconf::NeedsAutoconf() +{ + return !prv->configValues[aCpuThreadsConf]->IsArray(); } uint64_t jconf::GetCallTimeout() @@ -249,38 +262,34 @@ const char* jconf::GetOutputFile() return prv->configValues[sOutputFile]->GetString(); } +void jconf::cpuid(uint32_t eax, int32_t ecx, int32_t val[4]) +{ + memset(val, 0, sizeof(int32_t)*4); + +#ifdef _WIN32 + __cpuidex(val, eax, ecx); +#else + __cpuid_count(eax, ecx, val[0], val[1], val[2], val[3]); +#endif +} + bool jconf::check_cpu_features() { constexpr int AESNI_BIT = 1 << 25; constexpr int SSE2_BIT = 1 << 26; constexpr int BMI2_BIT = 1 << 8; - - int cpu_info[4]; + int32_t cpu_info[4]; bool bHaveSse2; -#ifdef _WIN32 - __cpuid(cpu_info, 1); -#else - __cpuid(1, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); -#endif + cpuid(1, 0, cpu_info); bHaveAes = (cpu_info[2] & AESNI_BIT) != 0; bHaveSse2 = (cpu_info[3] & SSE2_BIT) != 0; -#ifdef _WIN32 - __cpuidex(cpu_info, 7, 0); -#else - __cpuid_count(7, 0, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); -#endif + cpuid(7, 0, cpu_info); bHaveBmi2 = (cpu_info[1] & BMI2_BIT) != 0; - if(!bHaveAes) - printer::inst()->print_msg(L0, "Your CPU doesn't support hardware AES. Don't expect high hashrates."); - - if(bHaveBmi2) - printer::inst()->print_msg(L0, "CPU supports BMI2 instructions. Faster multiplication enabled."); - return bHaveSse2; } @@ -384,23 +393,8 @@ bool jconf::parse_config(const char* sFilename) } } - size_t n_thd = prv->configValues[aCpuThreadsConf]->Size(); - if(prv->configValues[iCpuThreadNum]->GetUint64() != n_thd) - { - printer::inst()->print_msg(L0, - "Invalid config file. Your CPU config array has %llu members, while you want to use %llu threads.", - int_port(n_thd), int_port(prv->configValues[iCpuThreadNum]->GetUint64())); - return false; - } - - if(NiceHashMode() && n_thd >= 32) - { - printer::inst()->print_msg(L0, "You need to use less than 32 threads in NiceHash mode."); - return false; - } - thd_cfg c; - for(size_t i=0; i < n_thd; i++) + for(size_t i=0; i < GetThreadCount(); i++) { if(!GetThreadConfig(i, c)) { @@ -409,6 +403,12 @@ bool jconf::parse_config(const char* sFilename) } } + if(NiceHashMode() && GetThreadCount() >= 32) + { + printer::inst()->print_msg(L0, "You need to use less than 32 threads in NiceHash mode."); + return false; + } + if(GetSlowMemSetting() == unknown_value) { printer::inst()->print_msg(L0, @@ -457,5 +457,15 @@ bool jconf::parse_config(const char* sFilename) #endif // _WIN32 printer::inst()->set_verbose_level(prv->configValues[iVerboseLevel]->GetUint64()); + + if(!NeedsAutoconf()) + { + if(!bHaveAes) + printer::inst()->print_msg(L0, "Your CPU doesn't support hardware AES. Don't expect high hashrates."); + + if(bHaveBmi2) + printer::inst()->print_msg(L0, "CPU supports BMI2 instructions. Faster multiplication enabled."); + } + return true; } @@ -29,6 +29,7 @@ public: size_t GetThreadCount(); bool GetThreadConfig(size_t id, thd_cfg &cfg); + bool NeedsAutoconf(); slow_mem_cfg GetSlowMemSetting(); @@ -58,6 +59,8 @@ public: inline bool HaveHardwareAes() { return bHaveAes; } inline bool HaveMulx() { return bHaveBmi2; } + static void cpuid(uint32_t eax, int32_t ecx, int32_t val[4]); + private: jconf(); static jconf* oInst; |