Skip to content

Commit ec789ab

Browse files
authored
Merge pull request fireice-uk#84 from fireice-uk/topic-autoconfig
CPU autoconfig
2 parents 37065f4 + 5b4f5c1 commit ec789ab

File tree

6 files changed

+223
-50
lines changed

6 files changed

+223
-50
lines changed

autoAdjust.hpp

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#pragma once
2+
#include "jconf.h"
3+
#include "console.h"
4+
5+
#ifdef _WIN32
6+
#include <windows.h>
7+
#else
8+
#include <unistd.h>
9+
#endif // _WIN32
10+
11+
// Mask bits between h and l and return the value
12+
// This enables us to put in values exactly like in the manual
13+
// For example EBX[31:22] is get_masked(cpu_info[1], 31, 22)
14+
inline int32_t get_masked(int32_t val, int32_t h, int32_t l)
15+
{
16+
val &= (0x7FFFFFFF >> (31-(h-l))) << l;
17+
return val >> l;
18+
}
19+
20+
class autoAdjust
21+
{
22+
public:
23+
24+
autoAdjust()
25+
{
26+
}
27+
28+
void printConfig()
29+
{
30+
printer::inst()->print_str("The configuration for 'cpu_threads_conf' in your config file is 'null'.\n");
31+
printer::inst()->print_str("The miner evaluates your system and prints a suggestion for the section `cpu_threads_conf` to the terminal.\n");
32+
printer::inst()->print_str("The values are not optimal, please try to tweak the values based on notes in config.txt.\n");
33+
printer::inst()->print_str("Please copy & paste the block within the asterisks to your config.\n\n");
34+
35+
if(!detectL3Size())
36+
return;
37+
38+
if(L3KB_size < 1024 || L3KB_size > 102400)
39+
{
40+
printer::inst()->print_msg(L0, "Autoconf failed: L3 size sanity check failed - %u KB.", L3KB_size);
41+
return;
42+
}
43+
44+
printer::inst()->print_msg(L0, "Autoconf L3 size detected at %u KB.", L3KB_size);
45+
46+
detectCPUConf();
47+
48+
printer::inst()->print_msg(L0, "Autoconf core count detected as %u on %s.", corecnt,
49+
linux_layout ? "Linux" : "Windows");
50+
51+
printer::inst()->print_str("\n**************** Copy&Paste ****************\n\n");
52+
printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n");
53+
54+
uint32_t aff_id = 0;
55+
char strbuf[256];
56+
for(uint32_t i=0; i < corecnt; i++)
57+
{
58+
bool double_mode;
59+
60+
if(L3KB_size <= 0)
61+
break;
62+
63+
double_mode = L3KB_size / 2048 > (int32_t)(corecnt-i);
64+
65+
snprintf(strbuf, sizeof(strbuf), " { \"low_power_mode\" : %s, \"no_prefetch\" : true, \"affine_to_cpu\" : %u },\n",
66+
double_mode ? "true" : "false", aff_id);
67+
printer::inst()->print_str(strbuf);
68+
69+
if(!linux_layout || old_amd)
70+
{
71+
aff_id += 2;
72+
73+
if(aff_id >= corecnt)
74+
aff_id = 1;
75+
}
76+
else
77+
aff_id++;
78+
79+
if(double_mode)
80+
L3KB_size -= 4096;
81+
else
82+
L3KB_size -= 2048;
83+
}
84+
85+
printer::inst()->print_str("]\n\n**************** Copy&Paste ****************\n");
86+
}
87+
88+
private:
89+
bool detectL3Size()
90+
{
91+
int32_t cpu_info[4];
92+
char cpustr[13] = {0};
93+
94+
jconf::cpuid(0, 0, cpu_info);
95+
memcpy(cpustr, &cpu_info[1], 4);
96+
memcpy(cpustr+4, &cpu_info[3], 4);
97+
memcpy(cpustr+8, &cpu_info[2], 4);
98+
99+
if(strcmp(cpustr, "GenuineIntel") == 0)
100+
{
101+
jconf::cpuid(4, 3, cpu_info);
102+
103+
if(get_masked(cpu_info[0], 7, 5) != 3)
104+
{
105+
printer::inst()->print_msg(L0, "Autoconf failed: Couln't find L3 cache page.");
106+
return false;
107+
}
108+
109+
L3KB_size = ((get_masked(cpu_info[1], 31, 22) + 1) * (get_masked(cpu_info[1], 21, 12) + 1) *
110+
(get_masked(cpu_info[1], 11, 0) + 1) * (cpu_info[2] + 1)) / 1024;
111+
112+
return true;
113+
}
114+
else if(strcmp(cpustr, "AuthenticAMD") == 0)
115+
{
116+
jconf::cpuid(0x80000006, 0, cpu_info);
117+
118+
L3KB_size = get_masked(cpu_info[3], 31, 18) * 512;
119+
120+
jconf::cpuid(1, 0, cpu_info);
121+
if(get_masked(cpu_info[0], 11, 8) < 0x17) //0x17h is Zen
122+
old_amd = true;
123+
124+
return true;
125+
}
126+
else
127+
{
128+
printer::inst()->print_msg(L0, "Autoconf failed: Unknown CPU type: %s.", cpustr);
129+
return false;
130+
}
131+
}
132+
133+
void detectCPUConf()
134+
{
135+
#ifdef _WIN32
136+
SYSTEM_INFO info;
137+
GetSystemInfo(&info);
138+
corecnt = info.dwNumberOfProcessors;
139+
linux_layout = false;
140+
#else
141+
corecnt = sysconf(_SC_NPROCESSORS_ONLN);
142+
linux_layout = true;
143+
#endif // _WIN32
144+
}
145+
146+
int32_t L3KB_size = 0;
147+
uint32_t corecnt;
148+
bool old_amd = false;
149+
bool linux_layout;
150+
};

cli-miner.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "jconf.h"
2727
#include "console.h"
2828
#include "donate-level.h"
29+
#include "autoAdjust.hpp"
2930

3031
#ifndef CONF_NO_HTTPD
3132
# include "httpd.h"
@@ -99,6 +100,14 @@ int main(int argc, char *argv[])
99100
return 0;
100101
}
101102

103+
if(jconf::inst()->NeedsAutoconf())
104+
{
105+
autoAdjust adjust;
106+
adjust.printConfig();
107+
win_exit();
108+
return 0;
109+
}
110+
102111
if (!minethd::self_test())
103112
{
104113
win_exit();

config.txt

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
/*
2-
* Number of threads. You can configure them below. Cryptonight uses 2MB of memory, so the optimal setting
3-
* here is the size of your L3 cache divided by 2. Intel mid-to-high end desktop processors have 2MB of L3
4-
* 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.
5-
*/
6-
"cpu_thread_num" : 2,
7-
81
/*
92
* Thread configuration for each thread. Make sure it matches the number above.
103
* low_power_mode - This mode will double the cache usage, and double the single thread performance. It will
@@ -19,11 +12,18 @@
1912
* even or odd numbered cpu numbers. For Linux it will be usually the lower CPU numbers, so for a 4
2013
* physical core CPU you should select cpu numbers 0-3.
2114
*
15+
* On the first run the miner will look at your system and suggest a basic configuration that will work,
16+
* you can try to tweak it from there to get the best performance.
17+
*
18+
* A filled out configuration should look like this:
19+
* "cpu_threads_conf" :
20+
* [
21+
* { "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 0 },
22+
* { "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 1 },
23+
* ],
2224
*/
23-
"cpu_threads_conf" : [
24-
{ "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 0 },
25-
{ "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 1 },
26-
],
25+
"cpu_threads_conf" :
26+
null,
2727

2828
/*
2929
* LARGE PAGE SUPPORT

jconf.cpp

+49-39
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ using namespace rapidjson;
4545
/*
4646
* This enum needs to match index in oConfigValues, otherwise we will get a runtime error
4747
*/
48-
enum configEnum { iCpuThreadNum, aCpuThreadsConf, sUseSlowMem, bNiceHashMode,
48+
enum configEnum { aCpuThreadsConf, sUseSlowMem, bNiceHashMode,
4949
bTlsMode, bTlsSecureAlgo, sTlsFingerprint, sPoolAddr, sWalletAddr, sPoolPwd,
5050
iCallTimeout, iNetRetry, iGiveUpLimit, iVerboseLevel, iAutohashTime,
5151
sOutputFile, iHttpdPort, bPreferIpv4 };
@@ -56,10 +56,10 @@ struct configVal {
5656
Type iType;
5757
};
5858

59-
//Same order as in configEnum, as per comment above
59+
// Same order as in configEnum, as per comment above
60+
// kNullType means any type
6061
configVal oConfigValues[] = {
61-
{ iCpuThreadNum, "cpu_thread_num", kNumberType },
62-
{ aCpuThreadsConf, "cpu_threads_conf", kArrayType },
62+
{ aCpuThreadsConf, "cpu_threads_conf", kNullType },
6363
{ sUseSlowMem, "use_slow_memory", kStringType },
6464
{ bNiceHashMode, "nicehash_nonce", kTrueType },
6565
{ bTlsMode, "use_tls", kTrueType },
@@ -84,6 +84,8 @@ inline bool checkType(Type have, Type want)
8484
{
8585
if(want == have)
8686
return true;
87+
else if(want == kNullType)
88+
return true;
8789
else if(want == kTrueType && have == kFalseType)
8890
return true;
8991
else if(want == kFalseType && have == kTrueType)
@@ -111,6 +113,9 @@ jconf::jconf()
111113

112114
bool jconf::GetThreadConfig(size_t id, thd_cfg &cfg)
113115
{
116+
if(!prv->configValues[aCpuThreadsConf]->IsArray())
117+
return false;
118+
114119
if(id >= prv->configValues[aCpuThreadsConf]->Size())
115120
return false;
116121

@@ -206,7 +211,15 @@ bool jconf::PreferIpv4()
206211

207212
size_t jconf::GetThreadCount()
208213
{
209-
return prv->configValues[aCpuThreadsConf]->Size();
214+
if(prv->configValues[aCpuThreadsConf]->IsArray())
215+
return prv->configValues[aCpuThreadsConf]->Size();
216+
else
217+
return 0;
218+
}
219+
220+
bool jconf::NeedsAutoconf()
221+
{
222+
return !prv->configValues[aCpuThreadsConf]->IsArray();
210223
}
211224

212225
uint64_t jconf::GetCallTimeout()
@@ -249,38 +262,34 @@ const char* jconf::GetOutputFile()
249262
return prv->configValues[sOutputFile]->GetString();
250263
}
251264

265+
void jconf::cpuid(uint32_t eax, int32_t ecx, int32_t val[4])
266+
{
267+
memset(val, 0, sizeof(int32_t)*4);
268+
269+
#ifdef _WIN32
270+
__cpuidex(val, eax, ecx);
271+
#else
272+
__cpuid_count(eax, ecx, val[0], val[1], val[2], val[3]);
273+
#endif
274+
}
275+
252276
bool jconf::check_cpu_features()
253277
{
254278
constexpr int AESNI_BIT = 1 << 25;
255279
constexpr int SSE2_BIT = 1 << 26;
256280
constexpr int BMI2_BIT = 1 << 8;
257-
258-
int cpu_info[4];
281+
int32_t cpu_info[4];
259282
bool bHaveSse2;
260283

261-
#ifdef _WIN32
262-
__cpuid(cpu_info, 1);
263-
#else
264-
__cpuid(1, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
265-
#endif
284+
cpuid(1, 0, cpu_info);
266285

267286
bHaveAes = (cpu_info[2] & AESNI_BIT) != 0;
268287
bHaveSse2 = (cpu_info[3] & SSE2_BIT) != 0;
269288

270-
#ifdef _WIN32
271-
__cpuidex(cpu_info, 7, 0);
272-
#else
273-
__cpuid_count(7, 0, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
274-
#endif
289+
cpuid(7, 0, cpu_info);
275290

276291
bHaveBmi2 = (cpu_info[1] & BMI2_BIT) != 0;
277292

278-
if(!bHaveAes)
279-
printer::inst()->print_msg(L0, "Your CPU doesn't support hardware AES. Don't expect high hashrates.");
280-
281-
if(bHaveBmi2)
282-
printer::inst()->print_msg(L0, "CPU supports BMI2 instructions. Faster multiplication enabled.");
283-
284293
return bHaveSse2;
285294
}
286295

@@ -384,23 +393,8 @@ bool jconf::parse_config(const char* sFilename)
384393
}
385394
}
386395

387-
size_t n_thd = prv->configValues[aCpuThreadsConf]->Size();
388-
if(prv->configValues[iCpuThreadNum]->GetUint64() != n_thd)
389-
{
390-
printer::inst()->print_msg(L0,
391-
"Invalid config file. Your CPU config array has %llu members, while you want to use %llu threads.",
392-
int_port(n_thd), int_port(prv->configValues[iCpuThreadNum]->GetUint64()));
393-
return false;
394-
}
395-
396-
if(NiceHashMode() && n_thd >= 32)
397-
{
398-
printer::inst()->print_msg(L0, "You need to use less than 32 threads in NiceHash mode.");
399-
return false;
400-
}
401-
402396
thd_cfg c;
403-
for(size_t i=0; i < n_thd; i++)
397+
for(size_t i=0; i < GetThreadCount(); i++)
404398
{
405399
if(!GetThreadConfig(i, c))
406400
{
@@ -409,6 +403,12 @@ bool jconf::parse_config(const char* sFilename)
409403
}
410404
}
411405

406+
if(NiceHashMode() && GetThreadCount() >= 32)
407+
{
408+
printer::inst()->print_msg(L0, "You need to use less than 32 threads in NiceHash mode.");
409+
return false;
410+
}
411+
412412
if(GetSlowMemSetting() == unknown_value)
413413
{
414414
printer::inst()->print_msg(L0,
@@ -457,5 +457,15 @@ bool jconf::parse_config(const char* sFilename)
457457
#endif // _WIN32
458458

459459
printer::inst()->set_verbose_level(prv->configValues[iVerboseLevel]->GetUint64());
460+
461+
if(!NeedsAutoconf())
462+
{
463+
if(!bHaveAes)
464+
printer::inst()->print_msg(L0, "Your CPU doesn't support hardware AES. Don't expect high hashrates.");
465+
466+
if(bHaveBmi2)
467+
printer::inst()->print_msg(L0, "CPU supports BMI2 instructions. Faster multiplication enabled.");
468+
}
469+
460470
return true;
461471
}

jconf.h

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class jconf
2929

3030
size_t GetThreadCount();
3131
bool GetThreadConfig(size_t id, thd_cfg &cfg);
32+
bool NeedsAutoconf();
3233

3334
slow_mem_cfg GetSlowMemSetting();
3435

@@ -58,6 +59,8 @@ class jconf
5859
inline bool HaveHardwareAes() { return bHaveAes; }
5960
inline bool HaveMulx() { return bHaveBmi2; }
6061

62+
static void cpuid(uint32_t eax, int32_t ecx, int32_t val[4]);
63+
6164
private:
6265
jconf();
6366
static jconf* oInst;

xmr-stak-cpu.cbp

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
<Add library="crypto" />
6969
<Add library="ssl" />
7070
</Linker>
71+
<Unit filename="autoAdjust.hpp" />
7172
<Unit filename="cli-miner.cpp" />
7273
<Unit filename="console.cpp" />
7374
<Unit filename="console.h" />

0 commit comments

Comments
 (0)