@@ -8,6 +8,8 @@ use crossbeam::atomic::AtomicCell;
88use crossbeam:: channel:: RecvTimeoutError ;
99use enumset:: { EnumSet , EnumSetType } ;
1010use itertools:: Itertools ;
11+ use raw_cpuid:: CpuId ;
12+ use std:: cmp:: max;
1113use std:: fmt:: { self , Display , Formatter } ;
1214use std:: num:: Wrapping ;
1315use std:: str:: FromStr ;
@@ -68,7 +70,9 @@ impl Display for KernelType {
6870
6971#[ derive( Debug ) ]
7072pub struct CpuInfo {
73+ cores : usize ,
7174 threads : usize ,
75+ default_miner_threads : usize ,
7276 supported : EnumSet < KernelType > ,
7377}
7478
@@ -77,10 +81,13 @@ impl Display for CpuInfo {
7781 write ! (
7882 f,
7983 "CPU:\n \
80- \t Threads: {threads}\n \
84+ \t Cores/threads: {cores}/{threads}\n \
85+ \t Default miner threads: {miner_threads}\n \
8186 \t Supported kernels: {supported}\n \
8287 \t Unsupported kernels: {available}",
88+ cores = self . cores,
8389 threads = self . threads,
90+ miner_threads = self . default_miner_threads,
8491 supported = self . supported. iter( ) . join( ", " ) ,
8592 available = ( !self . supported) . iter( ) . join( ", " ) ,
8693 )
@@ -101,11 +108,33 @@ fn get_best_kernel() -> KernelType {
101108 Iterator :: max ( get_supported_kernels ( ) . iter ( ) ) . unwrap_or_default ( )
102109}
103110
111+ /// Some CPUs seem to really struggle when every thread is in use, to the point
112+ /// of making the miner entirely unusable. This is particularly prevalent on
113+ /// Intel CPUs, presumably due to the impact of spectre mitigations on
114+ /// hyperthreading. Thus, we choose a lower default number of threads on Intel
115+ /// hardware.
116+ fn get_best_thread_count ( ) -> usize {
117+ let cores = num_cpus:: get_physical ( ) ;
118+ let threads = num_cpus:: get ( ) ;
119+
120+ match CpuId :: new ( ) . get_vendor_info ( ) {
121+ Some ( v) if v. as_string ( ) . to_lowercase ( ) . contains ( "intel" ) => max ( threads - 2 , cores) ,
122+ _ => threads,
123+ }
124+ }
125+
104126pub fn get_cpu_info ( ) -> CpuInfo {
127+ let cores = num_cpus:: get_physical ( ) ;
105128 let threads = num_cpus:: get ( ) ;
129+ let default_miner_threads = get_best_thread_count ( ) ;
106130 let supported = get_supported_kernels ( ) ;
107131
108- CpuInfo { threads, supported }
132+ CpuInfo {
133+ cores,
134+ threads,
135+ default_miner_threads,
136+ supported,
137+ }
109138}
110139
111140pub struct CpuMiner {
@@ -122,7 +151,7 @@ impl CpuMiner {
122151 } : & MinerConfig ,
123152 ) -> CpuMiner {
124153 CpuMiner {
125- threads : cpu_threads. unwrap_or_else ( num_cpus :: get ) ,
154+ threads : cpu_threads. unwrap_or_else ( get_best_thread_count ) ,
126155 kernel_type : cpu_kernel. unwrap_or_else ( get_best_kernel) ,
127156 }
128157 }
0 commit comments