Skip to content

Commit c4bccf4

Browse files
author
XMRig
committed
* Implement --max-cpu-usage.
* Fix L2 cache size detect. * Add test for get_optimal_threads_count.
1 parent 719601f commit c4bccf4

File tree

8 files changed

+201
-14
lines changed

8 files changed

+201
-14
lines changed

cpu.c

+21-5
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,17 @@
2424
#include <cpuid.h>
2525
#include <string.h>
2626
#include <stdbool.h>
27-
#include <libcpuid.h>
27+
#include <math.h>
28+
29+
#ifndef BUILD_TEST
30+
# include <libcpuid.h>
31+
#endif
2832

2933
#include "cpu.h"
34+
#include "utils/applog.h"
3035

3136

37+
#ifndef BUILD_TEST
3238
void cpu_init_common() {
3339
struct cpu_raw_data_t raw = { 0 };
3440
struct cpu_id_t data = { 0 };
@@ -41,7 +47,7 @@ void cpu_init_common() {
4147
cpu_info.total_logical_cpus = data.total_logical_cpus;
4248
cpu_info.sockets = data.total_logical_cpus / data.num_logical_cpus;
4349
cpu_info.total_cores = data.num_cores * cpu_info.sockets;
44-
cpu_info.l2_cache = data.l2_cache > 0 ? data.l2_cache * cpu_info.sockets : 0;
50+
cpu_info.l2_cache = data.l2_cache > 0 ? data.l2_cache * cpu_info.total_cores * cpu_info.sockets : 0;
4551
cpu_info.l3_cache = data.l3_cache > 0 ? data.l3_cache * cpu_info.sockets : 0;
4652

4753
# ifdef __x86_64__
@@ -56,21 +62,31 @@ void cpu_init_common() {
5662
cpu_info.flags |= CPU_FLAG_BMI2;
5763
}
5864
}
65+
#endif
66+
5967

68+
int get_optimal_threads_count(int algo, bool double_hash, int max_cpu_usage) {
69+
if (cpu_info.total_logical_cpus == 1) {
70+
return 1;
71+
}
6072

61-
int get_optimal_threads_count() {
6273
int cache = cpu_info.l3_cache ? cpu_info.l3_cache : cpu_info.l2_cache;
6374
int count = 0;
75+
const int size = (algo ? 1024 : 2048) * (double_hash ? 2 : 1);
6476

6577
if (cache) {
66-
count = cache / 2048;
78+
count = cache / size;
6779
}
6880
else {
6981
count = cpu_info.total_logical_cpus / 2;
7082
}
7183

7284
if (count > cpu_info.total_logical_cpus) {
73-
return cpu_info.total_logical_cpus;
85+
count = cpu_info.total_logical_cpus;
86+
}
87+
88+
if (((float) count / cpu_info.total_logical_cpus * 100) > max_cpu_usage) {
89+
count = ceil((float) cpu_info.total_logical_cpus * (max_cpu_usage / 100.0));
7490
}
7591

7692
return count < 1 ? 1 : count;

cpu.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#ifndef __CPU_H__
2525
#define __CPU_H__
2626

27+
#include <stdbool.h>
28+
2729
struct cpu_info {
2830
int total_cores;
2931
int total_logical_cpus;
@@ -45,7 +47,7 @@ enum cpu_flags {
4547

4648

4749
void cpu_init();
48-
int get_optimal_threads_count();
50+
int get_optimal_threads_count(int algo, bool double_hash, int max_cpu_usage);
4951
int affine_to_cpu_mask(int id, unsigned long mask);
5052

5153
#endif /* __CPU_H__ */

cpu_stub.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ void cpu_init_common() {
101101
}
102102

103103

104-
int get_optimal_threads_count() {
104+
int get_optimal_threads_count(int algo, bool double_hash, int max_cpu_usage) {
105105
int count = cpu_info.total_logical_cpus / 2;
106106
return count < 1 ? 1 : count;
107107
}

options.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -447,16 +447,16 @@ void parse_cmdline(int argc, char *argv[]) {
447447
sprintf(opt_userpass, "%s:%s", opt_user, opt_pass);
448448
}
449449

450-
if (!opt_n_threads) {
451-
opt_n_threads = get_optimal_threads_count();
452-
}
453-
454450
opt_algo_variant = get_algo_variant(opt_algo, opt_algo_variant);
455451

456452
if (!cryptonight_init(opt_algo_variant)) {
457453
applog(LOG_ERR, "Cryptonight hash self-test failed. This might be caused by bad compiler optimizations.");
458454
proper_exit(1);
459455
}
456+
457+
if (!opt_n_threads) {
458+
opt_n_threads = get_optimal_threads_count(opt_algo, opt_double_hash, opt_max_cpu_usage);
459+
}
460460
}
461461

462462

test/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ include(CTest)
55

66
add_subdirectory(unity)
77
add_subdirectory(cryptonight)
8-
add_subdirectory(cryptonight_lite)
8+
add_subdirectory(cryptonight_lite)
9+
add_subdirectory(autoconf)

test/autoconf/CMakeLists.txt

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
set(SOURCES
2+
autoconf.c
3+
../../cpu.h
4+
../../cpu.c
5+
)
6+
7+
add_executable(autoconf_app ${SOURCES})
8+
target_link_libraries(autoconf_app unity)
9+
10+
include_directories(../..)
11+
12+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
13+
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
14+
add_definitions(-DBUILD_TEST)
15+
16+
add_test(autoconf_test autoconf_app)

test/autoconf/autoconf.c

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#include <unity.h>
2+
3+
#include "cpu.h"
4+
#include "options.h"
5+
6+
struct cpu_info cpu_info = { 0 };
7+
8+
9+
static void set_cpu_info(int total_logical_cpus, int l2_cache, int l3_cache) {
10+
cpu_info.total_cores = total_logical_cpus;
11+
cpu_info.total_logical_cpus = total_logical_cpus;
12+
cpu_info.l2_cache = l2_cache;
13+
cpu_info.l3_cache = l3_cache;
14+
}
15+
16+
17+
void test_autoconf_should_GetOptimalThreadsCounti7(void) {
18+
set_cpu_info(8, 1024, 8192); // 4C/8T 8 MB (Generic i7 CPU)
19+
20+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100));
21+
TEST_ASSERT_EQUAL_INT(2, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100));
22+
23+
TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100));
24+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100));
25+
26+
TEST_ASSERT_EQUAL_INT(6, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75));
27+
TEST_ASSERT_EQUAL_INT(5, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 60));
28+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 50));
29+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 35));
30+
TEST_ASSERT_EQUAL_INT(2, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 20));
31+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 5));
32+
}
33+
34+
35+
void test_autoconf_should_GetOptimalThreadsCounti5(void) {
36+
set_cpu_info(4, 1024, 6144); // 2C/4T 6 MB (Generic i5 CPU)
37+
38+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100));
39+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100));
40+
41+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75));
42+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75));
43+
44+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100));
45+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100));
46+
47+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75));
48+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75));
49+
}
50+
51+
52+
void test_autoconf_should_GetOptimalThreadsCounti3(void) {
53+
set_cpu_info(4, 512, 3072); // 2C/4T 3 MB (Generic i3 CPU)
54+
55+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100));
56+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100));
57+
58+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75));
59+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75));
60+
61+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100));
62+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100));
63+
64+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75));
65+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75));
66+
}
67+
68+
69+
void test_autoconf_should_GetOptimalThreadsCountR7(void) {
70+
set_cpu_info(16, 4096, 16384); // 8C/16T 16 MB (AMD Ryzen 7)
71+
72+
TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100));
73+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100));
74+
75+
TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75));
76+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75));
77+
78+
TEST_ASSERT_EQUAL_INT(16, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100));
79+
TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100));
80+
81+
TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75));
82+
TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75));
83+
}
84+
85+
86+
void test_autoconf_should_GetOptimalThreadsCountTwoE5620(void) {
87+
set_cpu_info(16, 2048, 24576); // 8C/16T 24 MB (Two E5620)
88+
89+
TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100));
90+
TEST_ASSERT_EQUAL_INT(6, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100));
91+
92+
TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75));
93+
TEST_ASSERT_EQUAL_INT(6, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75));
94+
95+
TEST_ASSERT_EQUAL_INT(16, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100));
96+
TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100));
97+
98+
TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75));
99+
TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75));
100+
}
101+
102+
103+
void test_autoconf_should_GetOptimalThreadsCountVCPU(void) {
104+
set_cpu_info(1, 1024, 15360); // 1C/1T 15 MB (Single core Virtual CPU)
105+
106+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100));
107+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100));
108+
109+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75));
110+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75));
111+
112+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100));
113+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100));
114+
115+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75));
116+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75));
117+
}
118+
119+
120+
void test_autoconf_should_GetOptimalThreadsCountNoL3(void) {
121+
set_cpu_info(8, 8192, 0); // 4C/8T (Multi core Virtual CPU without L3 cache)
122+
123+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100));
124+
TEST_ASSERT_EQUAL_INT(2, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100));
125+
126+
TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100));
127+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100));
128+
129+
TEST_ASSERT_EQUAL_INT(6, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75));
130+
TEST_ASSERT_EQUAL_INT(5, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 60));
131+
TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 50));
132+
TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 35));
133+
TEST_ASSERT_EQUAL_INT(2, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 20));
134+
TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 5));
135+
}
136+
137+
138+
int main(void)
139+
{
140+
UNITY_BEGIN();
141+
142+
RUN_TEST(test_autoconf_should_GetOptimalThreadsCounti7);
143+
RUN_TEST(test_autoconf_should_GetOptimalThreadsCounti5);
144+
RUN_TEST(test_autoconf_should_GetOptimalThreadsCounti3);
145+
RUN_TEST(test_autoconf_should_GetOptimalThreadsCountR7);
146+
RUN_TEST(test_autoconf_should_GetOptimalThreadsCountR7);
147+
RUN_TEST(test_autoconf_should_GetOptimalThreadsCountTwoE5620);
148+
RUN_TEST(test_autoconf_should_GetOptimalThreadsCountVCPU);
149+
RUN_TEST(test_autoconf_should_GetOptimalThreadsCountNoL3);
150+
151+
return UNITY_END();
152+
}

utils/summary.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ static void print_cpu() {
5454

5555
# ifndef XMRIG_NO_LIBCPUID
5656
if (opt_colors) {
57-
applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "CPU L2/L3: %dK/%dK", cpu_info.l2_cache, cpu_info.l3_cache);
57+
applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "CPU L2/L3: %.1f MB/%.1f MB", cpu_info.l2_cache / 1024.0, cpu_info.l3_cache / 1024.0);
5858
}
5959
else {
60-
applog_notime(LOG_INFO, " * CPU L2/L3: %dK/%dK", cpu_info.l2_cache, cpu_info.l3_cache);
60+
applog_notime(LOG_INFO, " * CPU L2/L3: %.1f MB/%.1f MB", cpu_info.l2_cache / 1024.0, cpu_info.l3_cache / 1024.0);
6161
}
6262
# endif
6363

0 commit comments

Comments
 (0)