mirror of https://github.com/GOSTSec/sgminer
Browse Source
This patch is an initial attempt to re-structure cgminer source code from its monolithic design (with nearly all code being concentrated in main.c) to a more modular one. In this first stage, the conditionally compiled functions for GPU and CPU mining were extracted into dedicated files: * device-cpu.h and device-cpu.c covering WANT_CPUMINE functions * device-gpu.h and device-gpu.c covering HAVE_OPENCL functions The main.c file is left untouched as reference, while the remainder without the extracted parts is located in cgminer.c. The Makefile.am has been updated to use the re-structured source files for the build. Above pure re-structuring *NO* functional modifications were made. The sources were tested to compile and run on on a current Linux system with working CPU and GPU mining (Bitforce not tested due to loack of hardware).nfactor-troky
zefir
13 years ago
committed by
ckolivas
6 changed files with 6577 additions and 30 deletions
@ -0,0 +1,788 @@
@@ -0,0 +1,788 @@
|
||||
|
||||
/*
|
||||
* Copyright 2011-2012 Con Kolivas |
||||
* Copyright 2011-2012 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 2 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/resource.h> |
||||
#endif |
||||
#include <libgen.h> |
||||
|
||||
#include "compat.h" |
||||
#include "miner.h" |
||||
#include "bench_block.h" |
||||
#include "device-cpu.h" |
||||
|
||||
#if defined(unix) |
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#endif |
||||
|
||||
#ifdef __linux /* Linux specific policy and affinity management */ |
||||
#include <sched.h> |
||||
static inline void drop_policy(void) |
||||
{ |
||||
struct sched_param param; |
||||
|
||||
#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 id, int cpu) |
||||
{ |
||||
} |
||||
#endif |
||||
|
||||
|
||||
|
||||
/* TODO: resolve externals */ |
||||
extern bool submit_work_sync(struct thr_info *thr, const struct work *work_in); |
||||
extern char *set_int_range(const char *arg, int *i, int min, int max); |
||||
extern int dev_from_id(int thr_id); |
||||
|
||||
|
||||
#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 |
||||
}; |
||||
|
||||
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 |
||||
}; |
||||
#endif |
||||
|
||||
|
||||
|
||||
#ifdef WANT_CPUMINE |
||||
#if defined(WANT_X8664_SSE2) && defined(__SSE2__) |
||||
enum sha256_algos opt_algo = ALGO_SSE2_64; |
||||
#elif defined(WANT_X8632_SSE2) && defined(__SSE2__) |
||||
enum sha256_algos opt_algo = ALGO_SSE2_32; |
||||
#else |
||||
enum sha256_algos opt_algo = ALGO_C; |
||||
#endif |
||||
bool opt_usecpu = false; |
||||
static int cpur_thr_id; |
||||
static bool forced_n_threads; |
||||
#endif |
||||
|
||||
|
||||
|
||||
|
||||
#ifdef WANT_CPUMINE |
||||
// Algo benchmark, crash-prone, system independent stage
|
||||
double bench_algo_stage3( |
||||
enum sha256_algos algo |
||||
) |
||||
{ |
||||
// Use a random work block pulled from a pool
|
||||
static uint8_t bench_block[] = { CGMINER_BENCHMARK_BLOCK }; |
||||
struct work work __attribute__((aligned(128))); |
||||
|
||||
size_t bench_size = sizeof(work); |
||||
size_t work_size = sizeof(bench_block); |
||||
size_t min_size = (work_size < bench_size ? work_size : bench_size); |
||||
memset(&work, 0, sizeof(work)); |
||||
memcpy(&work, &bench_block, min_size); |
||||
|
||||
struct work_restart dummy; |
||||
work_restart = &dummy; |
||||
|
||||
struct timeval end; |
||||
struct timeval start; |
||||
uint32_t max_nonce = (1<<22); |
||||
uint32_t last_nonce = 0; |
||||
|
||||
gettimeofday(&start, 0); |
||||
{ |
||||
sha256_func func = sha256_funcs[algo]; |
||||
(*func)( |
||||
0, |
||||
work.midstate, |
||||
work.data, |
||||
work.hash1, |
||||
work.hash, |
||||
work.target, |
||||
max_nonce, |
||||
&last_nonce, |
||||
work.blk.nonce |
||||
); |
||||
} |
||||
gettimeofday(&end, 0); |
||||
work_restart = NULL; |
||||
|
||||
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[32]; |
||||
snprintf( |
||||
unique_name, |
||||
sizeof(unique_name)-1, |
||||
"cgminer-%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("CGMINER_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 *p = strlen(cmd_line) + cmd_line; |
||||
sprintf(p, " --bench-algo %d", algo); |
||||
SetEnvironmentVariable("CGMINER_BENCH_ALGO", "1"); |
||||
|
||||
// Launch a debug copy of cgminer
|
||||
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 %d\n", 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 (!strcmp(arg, "auto")) { |
||||
*algo = pick_fastest_algo(); |
||||
return NULL; |
||||
} |
||||
|
||||
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"; |
||||
} |
||||
|
||||
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 void cpu_detect() |
||||
{ |
||||
int i; |
||||
|
||||
// Reckon number of cores in the box
|
||||
#if defined(WIN32) |
||||
{ |
||||
DWORD system_am; |
||||
DWORD 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; |
||||
} |
||||
} |
||||
#else |
||||
num_processors = sysconf(_SC_NPROCESSORS_ONLN); |
||||
#endif /* !WIN32 */ |
||||
|
||||
if (opt_n_threads < 0 || !forced_n_threads) { |
||||
if (total_devices && !opt_usecpu) |
||||
opt_n_threads = 0; |
||||
else |
||||
opt_n_threads = num_processors; |
||||
} |
||||
if (num_processors < 1) |
||||
return; |
||||
|
||||
if (total_devices + opt_n_threads > MAX_DEVICES) |
||||
opt_n_threads = MAX_DEVICES - total_devices; |
||||
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 = devices[total_devices + i] = &cpus[i]; |
||||
cgpu->api = &cpu_api; |
||||
cgpu->enabled = true; |
||||
cgpu->device_id = i; |
||||
cgpu->threads = 1; |
||||
} |
||||
total_devices += opt_n_threads; |
||||
} |
||||
|
||||
static void reinit_cpu_device(struct cgpu_info *cpu) |
||||
{ |
||||
tq_push(thr_info[cpur_thr_id].q, cpu); |
||||
} |
||||
|
||||
static bool cpu_thread_prepare(struct thr_info *thr) |
||||
{ |
||||
thread_reportin(thr); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
static uint64_t cpu_can_limit_work(struct thr_info *thr) |
||||
{ |
||||
return 0xfffff; |
||||
} |
||||
|
||||
static bool cpu_thread_init(struct thr_info *thr) |
||||
{ |
||||
const int thr_id = thr->id; |
||||
|
||||
/* 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 uint64_t cpu_scanhash(struct thr_info *thr, struct work *work, uint64_t max_nonce) |
||||
{ |
||||
const int thr_id = thr->id; |
||||
|
||||
uint32_t first_nonce = work->blk.nonce; |
||||
uint32_t last_nonce; |
||||
bool rc; |
||||
|
||||
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_id, |
||||
work->midstate, |
||||
work->data, |
||||
work->hash1, |
||||
work->hash, |
||||
work->target, |
||||
max_nonce, |
||||
&last_nonce, |
||||
work->blk.nonce |
||||
); |
||||
} |
||||
|
||||
/* if nonce found, submit work */ |
||||
if (unlikely(rc)) { |
||||
if (opt_debug) |
||||
applog(LOG_DEBUG, "CPU %d found something?", dev_from_id(thr_id)); |
||||
if (unlikely(!submit_work_sync(thr, work))) { |
||||
applog(LOG_ERR, "Failed to submit_work_sync in miner_thread %d", thr_id); |
||||
} |
||||
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_api cpu_api = { |
||||
.name = "CPU", |
||||
.api_detect = cpu_detect, |
||||
.reinit_device = reinit_cpu_device, |
||||
.thread_prepare = cpu_thread_prepare, |
||||
.can_limit_work = cpu_can_limit_work, |
||||
.thread_init = cpu_thread_init, |
||||
.scanhash = cpu_scanhash, |
||||
}; |
||||
#endif |
||||
|
||||
|
||||
|
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
#ifndef __DEVICE_CPU_H__ |
||||
#define __DEVICE_CPU_H__ |
||||
|
||||
#include "miner.h" |
||||
|
||||
#ifndef OPT_SHOW_LEN |
||||
#define OPT_SHOW_LEN 80 |
||||
#endif |
||||
|
||||
extern const char *algo_names[]; |
||||
extern bool opt_usecpu; |
||||
extern struct device_api cpu_api; |
||||
|
||||
extern char *set_algo(const char *arg, enum sha256_algos *algo); |
||||
extern void show_algo(char buf[OPT_SHOW_LEN], const enum sha256_algos *algo); |
||||
extern char *force_nthreads_int(const char *arg, int *i); |
||||
extern void init_max_name_len(); |
||||
extern double bench_algo_stage3(enum sha256_algos algo); |
||||
|
||||
#endif /* __DEVICE_CPU_H__ */ |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
#ifndef __DEVICE_GPU_H__ |
||||
#define __DEVICE_GPU_H__ |
||||
|
||||
#include "miner.h" |
||||
|
||||
|
||||
extern char *print_ndevs_and_exit(int *ndevs); |
||||
extern void *reinit_gpu(void *userdata); |
||||
extern char *set_gpu_engine(char *arg); |
||||
extern char *set_gpu_fan(char *arg); |
||||
extern char *set_gpu_memclock(char *arg); |
||||
extern char *set_gpu_memdiff(char *arg); |
||||
extern char *set_gpu_powertune(char *arg); |
||||
extern char *set_gpu_vddc(char *arg); |
||||
extern char *set_temp_cutoff(char *arg); |
||||
extern char *set_temp_overheat(char *arg); |
||||
extern char *set_temp_target(char *arg); |
||||
extern char *set_intensity(char *arg); |
||||
extern char *set_vector(const char *arg, int *i); |
||||
void manage_gpu(void); |
||||
extern void pause_dynamic_threads(int gpu); |
||||
|
||||
extern bool have_opencl; |
||||
|
||||
extern struct device_api opencl_api; |
||||
|
||||
#endif /* __DEVICE_GPU_H__ */ |
Loading…
Reference in new issue