Merge pull request #84 from fireice-uk/topic-autoconfig

CPU autoconfig
This commit is contained in:
fireice-uk
2017-04-26 11:48:57 +01:00
committed by GitHub
6 changed files with 223 additions and 50 deletions
+150
View File
@@ -0,0 +1,150 @@
#pragma once
#include "jconf.h"
#include "console.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif // _WIN32
// Mask bits between h and l and return the value
// This enables us to put in values exactly like in the manual
// For example EBX[31:22] is get_masked(cpu_info[1], 31, 22)
inline 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");
if(!detectL3Size())
return;
if(L3KB_size < 1024 || L3KB_size > 102400)
{
printer::inst()->print_msg(L0, "Autoconf failed: L3 size sanity check failed - %u KB.", L3KB_size);
return;
}
printer::inst()->print_msg(L0, "Autoconf L3 size detected at %u KB.", L3KB_size);
detectCPUConf();
printer::inst()->print_msg(L0, "Autoconf core count detected as %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 || old_amd)
{
aff_id += 2;
if(aff_id >= corecnt)
aff_id = 1;
}
else
aff_id++;
if(double_mode)
L3KB_size -= 4096;
else
L3KB_size -= 2048;
}
printer::inst()->print_str("]\n\n**************** Copy&Paste ****************\n");
}
private:
bool detectL3Size()
{
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_size = ((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_size = get_masked(cpu_info[3], 31, 18) * 512;
jconf::cpuid(1, 0, cpu_info);
if(get_masked(cpu_info[0], 11, 8) < 0x17) //0x17h is Zen
old_amd = true;
return true;
}
else
{
printer::inst()->print_msg(L0, "Autoconf failed: Unknown CPU type: %s.", cpustr);
return false;
}
}
void detectCPUConf()
{
#ifdef _WIN32
SYSTEM_INFO info;
GetSystemInfo(&info);
corecnt = info.dwNumberOfProcessors;
linux_layout = false;
#else
corecnt = sysconf(_SC_NPROCESSORS_ONLN);
linux_layout = true;
#endif // _WIN32
}
int32_t L3KB_size = 0;
uint32_t corecnt;
bool old_amd = false;
bool linux_layout;
};
+9
View File
@@ -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();
+11 -11
View File
@@ -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
+49 -39
View File
@@ -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;
}
+3
View File
@@ -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;
+1
View File
@@ -68,6 +68,7 @@
<Add library="crypto" />
<Add library="ssl" />
</Linker>
<Unit filename="autoAdjust.hpp" />
<Unit filename="cli-miner.cpp" />
<Unit filename="console.cpp" />
<Unit filename="console.h" />