| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881 |
- /*
- * Copyright 2011-2013 Con Kolivas
- * Copyright 2011-2014 Luke Dashjr
- * Copyright 2010 Jeff Garzik
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version. See COPYING for more details.
- */
- #include "config.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <unistd.h>
- #include <signal.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #ifndef WIN32
- #include <sys/wait.h>
- #include <sys/resource.h>
- #endif
- #include <libgen.h>
- #include "compat.h"
- #include "deviceapi.h"
- #include "miner.h"
- #include "logging.h"
- #include "util.h"
- #include "driver-cpu.h"
- #if defined(unix)
- #include <errno.h>
- #include <fcntl.h>
- #endif
- BFG_REGISTER_DRIVER(cpu_drv)
- #if defined(__linux) && defined(CPU_ZERO) /* Linux specific policy and affinity management */
- #include <sched.h>
- static inline void drop_policy(void)
- {
- struct sched_param param;
- param.sched_priority = 0;
- #ifdef SCHED_BATCH
- #ifdef SCHED_IDLE
- if (unlikely(sched_setscheduler(0, SCHED_IDLE, ¶m) == -1))
- #endif
- sched_setscheduler(0, SCHED_BATCH, ¶m);
- #endif
- }
- static inline void affine_to_cpu(int id, int cpu)
- {
- cpu_set_t set;
- CPU_ZERO(&set);
- CPU_SET(cpu, &set);
- sched_setaffinity(0, sizeof(set), &set);
- applog(LOG_INFO, "Binding cpu mining thread %d to cpu %d", id, cpu);
- }
- #else
- static inline void drop_policy(void)
- {
- }
- static inline void affine_to_cpu(int __maybe_unused id, int __maybe_unused cpu)
- {
- }
- #endif
- /* TODO: resolve externals */
- extern char *set_int_range(const char *arg, int *i, int min, int max);
- extern int dev_from_id(int thr_id);
- /* chipset-optimized hash functions */
- extern bool ScanHash_4WaySSE2(struct thr_info*, const unsigned char *pmidstate,
- unsigned char *pdata, unsigned char *phash1, unsigned char *phash,
- const unsigned char *ptarget,
- uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
- extern bool ScanHash_altivec_4way(struct thr_info*, const unsigned char *pmidstate,
- unsigned char *pdata,
- unsigned char *phash1, unsigned char *phash,
- const unsigned char *ptarget,
- uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
- extern bool scanhash_via(struct thr_info*, const unsigned char *pmidstate,
- unsigned char *pdata,
- unsigned char *phash1, unsigned char *phash,
- const unsigned char *target,
- uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
- extern bool scanhash_c(struct thr_info*, const unsigned char *midstate, unsigned char *data,
- unsigned char *hash1, unsigned char *hash,
- const unsigned char *target,
- uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
- extern bool scanhash_cryptopp(struct thr_info*, const unsigned char *midstate,unsigned char *data,
- unsigned char *hash1, unsigned char *hash,
- const unsigned char *target,
- uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
- extern bool scanhash_asm32(struct thr_info*, const unsigned char *midstate,unsigned char *data,
- unsigned char *hash1, unsigned char *hash,
- const unsigned char *target,
- uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
- extern bool scanhash_sse2_64(struct thr_info*, const unsigned char *pmidstate, unsigned char *pdata,
- unsigned char *phash1, unsigned char *phash,
- const unsigned char *ptarget,
- uint32_t max_nonce, uint32_t *last_nonce,
- uint32_t nonce);
- extern bool scanhash_sse4_64(struct thr_info*, const unsigned char *pmidstate, unsigned char *pdata,
- unsigned char *phash1, unsigned char *phash,
- const unsigned char *ptarget,
- uint32_t max_nonce, uint32_t *last_nonce,
- uint32_t nonce);
- extern bool scanhash_sse2_32(struct thr_info*, const unsigned char *pmidstate, unsigned char *pdata,
- unsigned char *phash1, unsigned char *phash,
- const unsigned char *ptarget,
- uint32_t max_nonce, uint32_t *last_nonce,
- uint32_t nonce);
- extern bool scanhash_scrypt(struct thr_info *, const unsigned char *pmidstate, unsigned char *pdata, unsigned char *phash1, unsigned char __maybe_unused *phash, const unsigned char *ptarget, uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
- #ifdef WANT_CPUMINE
- static size_t max_name_len = 0;
- static char *name_spaces_pad = NULL;
- const char *algo_names[] = {
- [ALGO_C] = "c",
- #ifdef WANT_SSE2_4WAY
- [ALGO_4WAY] = "4way",
- #endif
- #ifdef WANT_VIA_PADLOCK
- [ALGO_VIA] = "via",
- #endif
- [ALGO_CRYPTOPP] = "cryptopp",
- #ifdef WANT_CRYPTOPP_ASM32
- [ALGO_CRYPTOPP_ASM32] = "cryptopp_asm32",
- #endif
- #ifdef WANT_X8632_SSE2
- [ALGO_SSE2_32] = "sse2_32",
- #endif
- #ifdef WANT_X8664_SSE2
- [ALGO_SSE2_64] = "sse2_64",
- #endif
- #ifdef WANT_X8664_SSE4
- [ALGO_SSE4_64] = "sse4_64",
- #endif
- #ifdef WANT_ALTIVEC_4WAY
- [ALGO_ALTIVEC_4WAY] = "altivec_4way",
- #endif
- #ifdef WANT_SCRYPT
- [ALGO_SCRYPT] = "scrypt",
- #endif
- [ALGO_FASTAUTO] = "fastauto",
- [ALGO_AUTO] = "auto",
- };
- static const sha256_func sha256_funcs[] = {
- [ALGO_C] = (sha256_func)scanhash_c,
- #ifdef WANT_SSE2_4WAY
- [ALGO_4WAY] = (sha256_func)ScanHash_4WaySSE2,
- #endif
- #ifdef WANT_ALTIVEC_4WAY
- [ALGO_ALTIVEC_4WAY] = (sha256_func) ScanHash_altivec_4way,
- #endif
- #ifdef WANT_VIA_PADLOCK
- [ALGO_VIA] = (sha256_func)scanhash_via,
- #endif
- [ALGO_CRYPTOPP] = (sha256_func)scanhash_cryptopp,
- #ifdef WANT_CRYPTOPP_ASM32
- [ALGO_CRYPTOPP_ASM32] = (sha256_func)scanhash_asm32,
- #endif
- #ifdef WANT_X8632_SSE2
- [ALGO_SSE2_32] = (sha256_func)scanhash_sse2_32,
- #endif
- #ifdef WANT_X8664_SSE2
- [ALGO_SSE2_64] = (sha256_func)scanhash_sse2_64,
- #endif
- #ifdef WANT_X8664_SSE4
- [ALGO_SSE4_64] = (sha256_func)scanhash_sse4_64,
- #endif
- #ifdef WANT_SCRYPT
- [ALGO_SCRYPT] = (sha256_func)scanhash_scrypt
- #endif
- };
- #endif
- #ifdef WANT_CPUMINE
- enum sha256_algos opt_algo = ALGO_FASTAUTO;
- static bool forced_n_threads;
- #endif
- static const uint32_t hash1_init[] = {
- 0,0,0,0,0,0,0,0,
- 0x80000000,
- 0,0,0,0,0,0,
- 0x100,
- };
- #ifdef WANT_CPUMINE
- // Algo benchmark, crash-prone, system independent stage
- double bench_algo_stage3(
- enum sha256_algos algo
- )
- {
- struct work work __attribute__((aligned(128)));
- unsigned char hash1[64];
- get_benchmark_work(&work, false);
- static struct thr_info dummy;
- struct timeval end;
- struct timeval start;
- uint32_t max_nonce = opt_algo == ALGO_FASTAUTO ? (1<<8) : (1<<22);
- uint32_t last_nonce = 0;
- memcpy(&hash1[0], &hash1_init[0], sizeof(hash1));
- timer_set_now(&start);
- {
- sha256_func func = sha256_funcs[algo];
- (*func)(
- &dummy,
- work.midstate,
- work.data,
- hash1,
- work.hash,
- work.target,
- max_nonce,
- &last_nonce,
- 0
- );
- }
- timer_set_now(&end);
- uint64_t usec_end = ((uint64_t)end.tv_sec)*1000*1000 + end.tv_usec;
- uint64_t usec_start = ((uint64_t)start.tv_sec)*1000*1000 + start.tv_usec;
- uint64_t usec_elapsed = usec_end - usec_start;
- double rate = -1.0;
- if (0<usec_elapsed) {
- rate = (1.0*(last_nonce+1))/usec_elapsed;
- }
- return rate;
- }
- #if defined(unix)
- // Change non-blocking status on a file descriptor
- static void set_non_blocking(
- int fd,
- int yes
- )
- {
- int flags = fcntl(fd, F_GETFL, 0);
- if (flags<0) {
- perror("fcntl(GET) failed");
- exit(1);
- }
- flags = yes ? (flags|O_NONBLOCK) : (flags&~O_NONBLOCK);
- int r = fcntl(fd, F_SETFL, flags);
- if (r<0) {
- perror("fcntl(SET) failed");
- exit(1);
- }
- }
- #endif // defined(unix)
- // Algo benchmark, crash-safe, system-dependent stage
- static double bench_algo_stage2(
- enum sha256_algos algo
- )
- {
- // Here, the gig is to safely run a piece of code that potentially
- // crashes. Unfortunately, the Right Way (tm) to do this is rather
- // heavily platform dependent :(
- double rate = -1.23457;
- #if defined(unix)
- // Make a pipe: [readFD, writeFD]
- int pfd[2];
- int r = pipe(pfd);
- if (r<0) {
- perror("pipe - failed to create pipe for --algo auto");
- exit(1);
- }
- // Make pipe non blocking
- set_non_blocking(pfd[0], 1);
- set_non_blocking(pfd[1], 1);
- // Don't allow a crashing child to kill the main process
- sighandler_t sr0 = signal(SIGPIPE, SIG_IGN);
- sighandler_t sr1 = signal(SIGPIPE, SIG_IGN);
- if (SIG_ERR==sr0 || SIG_ERR==sr1) {
- perror("signal - failed to edit signal mask for --algo auto");
- exit(1);
- }
- // Fork a child to do the actual benchmarking
- pid_t child_pid = fork();
- if (child_pid<0) {
- perror("fork - failed to create a child process for --algo auto");
- exit(1);
- }
- // Do the dangerous work in the child, knowing we might crash
- if (0==child_pid) {
- // TODO: some umask trickery to prevent coredumps
- // Benchmark this algorithm
- double r = bench_algo_stage3(algo);
- // We survived, send result to parent and bail
- int loop_count = 0;
- while (1) {
- ssize_t bytes_written = write(pfd[1], &r, sizeof(r));
- int try_again = (0==bytes_written || (bytes_written<0 && EAGAIN==errno));
- int success = (sizeof(r)==(size_t)bytes_written);
- if (success)
- break;
- if (!try_again) {
- perror("write - child failed to write benchmark result to pipe");
- exit(1);
- }
- if (5<loop_count) {
- applog(LOG_ERR, "child tried %d times to communicate with parent, giving up", loop_count);
- exit(1);
- }
- ++loop_count;
- sleep(1);
- }
- exit(0);
- }
- // Parent waits for a result from child
- int loop_count = 0;
- while (1) {
- // Wait for child to die
- int status;
- int r = waitpid(child_pid, &status, WNOHANG);
- if ((child_pid==r) || (r<0 && ECHILD==errno)) {
- // Child died somehow. Grab result and bail
- double tmp;
- ssize_t bytes_read = read(pfd[0], &tmp, sizeof(tmp));
- if (sizeof(tmp)==(size_t)bytes_read)
- rate = tmp;
- break;
- } else if (r<0) {
- perror("bench_algo: waitpid failed. giving up.");
- exit(1);
- }
- // Give up on child after a ~60s
- if (60<loop_count) {
- kill(child_pid, SIGKILL);
- waitpid(child_pid, &status, 0);
- break;
- }
- // Wait a bit longer
- ++loop_count;
- sleep(1);
- }
- // Close pipe
- r = close(pfd[0]);
- if (r<0) {
- perror("close - failed to close read end of pipe for --algo auto");
- exit(1);
- }
- r = close(pfd[1]);
- if (r<0) {
- perror("close - failed to close read end of pipe for --algo auto");
- exit(1);
- }
- #elif defined(WIN32)
- // Get handle to current exe
- HINSTANCE module = GetModuleHandle(0);
- if (!module) {
- applog(LOG_ERR, "failed to retrieve module handle");
- exit(1);
- }
- // Create a unique name
- char unique_name[33];
- snprintf(
- unique_name,
- sizeof(unique_name)-1,
- "bfgminer-%p",
- (void*)module
- );
- // Create and init a chunked of shared memory
- HANDLE map_handle = CreateFileMapping(
- INVALID_HANDLE_VALUE, // use paging file
- NULL, // default security attributes
- PAGE_READWRITE, // read/write access
- 0, // size: high 32-bits
- 4096, // size: low 32-bits
- unique_name // name of map object
- );
- if (NULL==map_handle) {
- applog(LOG_ERR, "could not create shared memory");
- exit(1);
- }
- void *shared_mem = MapViewOfFile(
- map_handle, // object to map view of
- FILE_MAP_WRITE, // read/write access
- 0, // high offset: map from
- 0, // low offset: beginning
- 0 // default: map entire file
- );
- if (NULL==shared_mem) {
- applog(LOG_ERR, "could not map shared memory");
- exit(1);
- }
- SetEnvironmentVariable("BFGMINER_SHARED_MEM", unique_name);
- CopyMemory(shared_mem, &rate, sizeof(rate));
- // Get path to current exe
- char cmd_line[256 + MAX_PATH];
- const size_t n = sizeof(cmd_line)-200;
- DWORD size = GetModuleFileName(module, cmd_line, n);
- if (0==size) {
- applog(LOG_ERR, "failed to retrieve module path");
- exit(1);
- }
- // Construct new command line based on that
- char buf[0x20];
- snprintf(buf, sizeof(buf), "%d", algo);
- SetEnvironmentVariable("BFGMINER_BENCH_ALGO", buf);
- // Launch a debug copy of BFGMiner
- STARTUPINFO startup_info;
- PROCESS_INFORMATION process_info;
- ZeroMemory(&startup_info, sizeof(startup_info));
- ZeroMemory(&process_info, sizeof(process_info));
- startup_info.cb = sizeof(startup_info);
- BOOL ok = CreateProcess(
- NULL, // No module name (use command line)
- cmd_line, // Command line
- NULL, // Process handle not inheritable
- NULL, // Thread handle not inheritable
- FALSE, // Set handle inheritance to FALSE
- DEBUG_ONLY_THIS_PROCESS,// We're going to debug the child
- NULL, // Use parent's environment block
- NULL, // Use parent's starting directory
- &startup_info, // Pointer to STARTUPINFO structure
- &process_info // Pointer to PROCESS_INFORMATION structure
- );
- if (!ok) {
- applog(LOG_ERR, "CreateProcess failed with error %ld\n", (long)GetLastError() );
- exit(1);
- }
- // Debug the child (only clean way to catch exceptions)
- while (1) {
- // Wait for child to do something
- DEBUG_EVENT debug_event;
- ZeroMemory(&debug_event, sizeof(debug_event));
- BOOL ok = WaitForDebugEvent(&debug_event, 60 * 1000);
- if (!ok)
- break;
- // Decide if event is "normal"
- int go_on =
- CREATE_PROCESS_DEBUG_EVENT== debug_event.dwDebugEventCode ||
- CREATE_THREAD_DEBUG_EVENT == debug_event.dwDebugEventCode ||
- EXIT_THREAD_DEBUG_EVENT == debug_event.dwDebugEventCode ||
- EXCEPTION_DEBUG_EVENT == debug_event.dwDebugEventCode ||
- LOAD_DLL_DEBUG_EVENT == debug_event.dwDebugEventCode ||
- OUTPUT_DEBUG_STRING_EVENT == debug_event.dwDebugEventCode ||
- UNLOAD_DLL_DEBUG_EVENT == debug_event.dwDebugEventCode;
- if (!go_on)
- break;
- // Some exceptions are also "normal", apparently.
- if (EXCEPTION_DEBUG_EVENT== debug_event.dwDebugEventCode) {
- int go_on =
- EXCEPTION_BREAKPOINT== debug_event.u.Exception.ExceptionRecord.ExceptionCode;
- if (!go_on)
- break;
- }
- // If nothing unexpected happened, let child proceed
- ContinueDebugEvent(
- debug_event.dwProcessId,
- debug_event.dwThreadId,
- DBG_CONTINUE
- );
- }
- // Clean up child process
- TerminateProcess(process_info.hProcess, 1);
- CloseHandle(process_info.hProcess);
- CloseHandle(process_info.hThread);
- // Reap return value and cleanup
- CopyMemory(&rate, shared_mem, sizeof(rate));
- (void)UnmapViewOfFile(shared_mem);
- (void)CloseHandle(map_handle);
- #else
- // Not linux, not unix, not WIN32 ... do our best
- rate = bench_algo_stage3(algo);
- #endif // defined(unix)
- // Done
- return rate;
- }
- static void bench_algo(
- double *best_rate,
- enum sha256_algos *best_algo,
- enum sha256_algos algo
- )
- {
- size_t n = max_name_len - strlen(algo_names[algo]);
- memset(name_spaces_pad, ' ', n);
- name_spaces_pad[n] = 0;
- applog(
- LOG_ERR,
- "\"%s\"%s : benchmarking algorithm ...",
- algo_names[algo],
- name_spaces_pad
- );
- double rate = bench_algo_stage2(algo);
- if (rate<0.0) {
- applog(
- LOG_ERR,
- "\"%s\"%s : algorithm fails on this platform",
- algo_names[algo],
- name_spaces_pad
- );
- } else {
- applog(
- LOG_ERR,
- "\"%s\"%s : algorithm runs at %.5f MH/s",
- algo_names[algo],
- name_spaces_pad,
- rate
- );
- if (*best_rate<rate) {
- *best_rate = rate;
- *best_algo = algo;
- }
- }
- }
- // Figure out the longest algorithm name
- void init_max_name_len()
- {
- size_t i;
- size_t nb_names = sizeof(algo_names)/sizeof(algo_names[0]);
- for (i=0; i<nb_names; ++i) {
- const char *p = algo_names[i];
- size_t name_len = p ? strlen(p) : 0;
- if (max_name_len<name_len)
- max_name_len = name_len;
- }
- name_spaces_pad = (char*) malloc(max_name_len+16);
- if (0==name_spaces_pad) {
- perror("malloc failed");
- exit(1);
- }
- }
- // Pick the fastest CPU hasher
- static enum sha256_algos pick_fastest_algo()
- {
- double best_rate = -1.0;
- enum sha256_algos best_algo = 0;
- applog(LOG_ERR, "benchmarking all sha256 algorithms ...");
- bench_algo(&best_rate, &best_algo, ALGO_C);
- #if defined(WANT_SSE2_4WAY)
- bench_algo(&best_rate, &best_algo, ALGO_4WAY);
- #endif
- #if defined(WANT_VIA_PADLOCK)
- bench_algo(&best_rate, &best_algo, ALGO_VIA);
- #endif
- bench_algo(&best_rate, &best_algo, ALGO_CRYPTOPP);
- #if defined(WANT_CRYPTOPP_ASM32)
- bench_algo(&best_rate, &best_algo, ALGO_CRYPTOPP_ASM32);
- #endif
- #if defined(WANT_X8632_SSE2)
- bench_algo(&best_rate, &best_algo, ALGO_SSE2_32);
- #endif
- #if defined(WANT_X8664_SSE2)
- bench_algo(&best_rate, &best_algo, ALGO_SSE2_64);
- #endif
- #if defined(WANT_X8664_SSE4)
- bench_algo(&best_rate, &best_algo, ALGO_SSE4_64);
- #endif
- #if defined(WANT_ALTIVEC_4WAY)
- bench_algo(&best_rate, &best_algo, ALGO_ALTIVEC_4WAY);
- #endif
- size_t n = max_name_len - strlen(algo_names[best_algo]);
- memset(name_spaces_pad, ' ', n);
- name_spaces_pad[n] = 0;
- applog(
- LOG_ERR,
- "\"%s\"%s : is fastest algorithm at %.5f MH/s",
- algo_names[best_algo],
- name_spaces_pad,
- best_rate
- );
- return best_algo;
- }
- /* FIXME: Use asprintf for better errors. */
- char *set_algo(const char *arg, enum sha256_algos *algo)
- {
- enum sha256_algos i;
- if (opt_scrypt)
- return "Can only use scrypt algorithm";
- for (i = 0; i < ARRAY_SIZE(algo_names); i++) {
- if (algo_names[i] && !strcmp(arg, algo_names[i])) {
- *algo = i;
- return NULL;
- }
- }
- return "Unknown algorithm";
- }
- #ifdef WANT_SCRYPT
- void set_scrypt_algo(enum sha256_algos *algo)
- {
- *algo = ALGO_SCRYPT;
- }
- #endif
- void show_algo(char buf[OPT_SHOW_LEN], const enum sha256_algos *algo)
- {
- strncpy(buf, algo_names[*algo], OPT_SHOW_LEN);
- }
- #endif
- #ifdef WANT_CPUMINE
- char *force_nthreads_int(const char *arg, int *i)
- {
- forced_n_threads = true;
- return set_int_range(arg, i, 0, 9999);
- }
- #endif
- #ifdef WANT_CPUMINE
- static int cpu_autodetect()
- {
- RUNONCE(0);
-
- int i;
- // Reckon number of cores in the box
- #if defined(WIN32)
- {
- DWORD_PTR system_am;
- DWORD_PTR process_am;
- BOOL ok = GetProcessAffinityMask(
- GetCurrentProcess(),
- &system_am,
- &process_am
- );
- if (!ok) {
- applog(LOG_ERR, "couldn't figure out number of processors :(");
- num_processors = 1;
- } else {
- size_t n = 32;
- num_processors = 0;
- while (n--)
- if (process_am & (1<<n))
- ++num_processors;
- }
- }
- #elif defined(_SC_NPROCESSORS_ONLN)
- num_processors = sysconf(_SC_NPROCESSORS_ONLN);
- #elif defined(CTL_HW) && defined(HW_NCPU)
- int req[] = { CTL_HW, HW_NCPU };
- size_t len = sizeof(num_processors);
- sysctl(req, 2, &num_processors, &len, NULL, 0);
- #else
- num_processors = 1;
- #endif /* !WIN32 */
- if (opt_n_threads < 0 || !forced_n_threads) {
- opt_n_threads = num_processors;
- }
- if (num_processors < 1)
- return 0;
- cpus = calloc(opt_n_threads, sizeof(struct cgpu_info));
- if (unlikely(!cpus))
- quit(1, "Failed to calloc cpus");
- for (i = 0; i < opt_n_threads; ++i) {
- struct cgpu_info *cgpu;
- cgpu = &cpus[i];
- cgpu->drv = &cpu_drv;
- cgpu->deven = DEV_ENABLED;
- cgpu->threads = 1;
- cgpu->kname = algo_names[opt_algo];
- add_cgpu(cgpu);
- }
- return opt_n_threads;
- }
- static void cpu_detect()
- {
- noserial_detect_manual(&cpu_drv, cpu_autodetect);
- }
- static pthread_mutex_t cpualgo_lock;
- static bool cpu_thread_prepare(struct thr_info *thr)
- {
- struct cgpu_info *cgpu = thr->cgpu;
-
- if (!(cgpu->device_id || thr->device_thread || cgpu->proc_id))
- mutex_init(&cpualgo_lock);
-
- thread_reportin(thr);
- return true;
- }
- static uint64_t cpu_can_limit_work(struct thr_info __maybe_unused *thr)
- {
- return 0xffff;
- }
- static bool cpu_thread_init(struct thr_info *thr)
- {
- const int thr_id = thr->id;
- struct cgpu_info *cgpu = thr->cgpu;
- mutex_lock(&cpualgo_lock);
- switch (opt_algo)
- {
- case ALGO_AUTO:
- case ALGO_FASTAUTO:
- opt_algo = pick_fastest_algo();
- default:
- break;
- }
- mutex_unlock(&cpualgo_lock);
- cgpu->kname = algo_names[opt_algo];
-
- if (opt_algo == ALGO_SCRYPT)
- cgpu->min_nonce_diff = 1./0x10000;
-
- /* Set worker threads to nice 19 and then preferentially to SCHED_IDLE
- * and if that fails, then SCHED_BATCH. No need for this to be an
- * error if it fails */
- setpriority(PRIO_PROCESS, 0, 19);
- drop_policy();
- /* Cpu affinity only makes sense if the number of threads is a multiple
- * of the number of CPUs */
- if (!(opt_n_threads % num_processors))
- affine_to_cpu(dev_from_id(thr_id), dev_from_id(thr_id) % num_processors);
- return true;
- }
- static int64_t cpu_scanhash(struct thr_info *thr, struct work *work, int64_t max_nonce)
- {
- unsigned char hash1[64];
- uint32_t first_nonce = work->blk.nonce;
- uint32_t last_nonce;
- bool rc;
- memcpy(&hash1[0], &hash1_init[0], sizeof(hash1));
- CPUSearch:
- last_nonce = first_nonce;
- rc = false;
- /* scan nonces for a proof-of-work hash */
- {
- sha256_func func = sha256_funcs[opt_algo];
- rc = (*func)(
- thr,
- work->midstate,
- work->data,
- hash1,
- work->hash,
- work->target,
- max_nonce,
- &last_nonce,
- work->blk.nonce
- );
- }
- /* if nonce found, submit work */
- if (unlikely(rc)) {
- applog(LOG_DEBUG, "%"PRIpreprv" found something?", thr->cgpu->proc_repr);
- submit_nonce(thr, work, le32toh(*(uint32_t*)&work->data[76]));
- work->blk.nonce = last_nonce + 1;
- goto CPUSearch;
- }
- else
- if (unlikely(last_nonce == first_nonce))
- return 0;
- work->blk.nonce = last_nonce + 1;
- return last_nonce - first_nonce + 1;
- }
- struct device_drv cpu_drv = {
- .dname = "cpu",
- .name = "CPU",
- .probe_priority = 120,
- .supported_algos = POW_SHA256D | POW_SCRYPT,
- .drv_detect = cpu_detect,
- .thread_prepare = cpu_thread_prepare,
- .can_limit_work = cpu_can_limit_work,
- .thread_init = cpu_thread_init,
- .scanhash = cpu_scanhash,
- };
- #endif
|