mirror of
https://github.com/GOSTSec/sgminer
synced 2025-03-13 06:01:03 +00:00
Modularize code: main.c -> device-cpu + device-gpu
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).
This commit is contained in:
parent
55f693a80c
commit
e0b0a6c030
69
Makefile.am
69
Makefile.am
@ -17,27 +17,7 @@ INCLUDES = $(PTHREAD_FLAGS) -fno-strict-aliasing $(JANSSON_INCLUDES)
|
||||
|
||||
bin_PROGRAMS = cgminer
|
||||
|
||||
bin_SCRIPTS = phatk110817.cl poclbm110817.cl
|
||||
|
||||
if HAS_CPUMINE
|
||||
cgminer_SOURCES = elist.h miner.h compat.h bench_block.h \
|
||||
main.c util.c uthash.h \
|
||||
ocl.c ocl.h findnonce.c findnonce.h \
|
||||
sha256_generic.c sha256_4way.c sha256_via.c \
|
||||
sha256_cryptopp.c sha256_sse2_amd64.c \
|
||||
sha256_sse4_amd64.c sha256_sse2_i386.c \
|
||||
sha256_altivec_4way.c \
|
||||
adl.c adl.h adl_functions.h \
|
||||
phatk110817.cl poclbm110817.cl \
|
||||
sha2.c sha2.h api.c
|
||||
else
|
||||
cgminer_SOURCES = elist.h miner.h compat.h bench_block.h \
|
||||
main.c util.c uthash.h \
|
||||
ocl.c ocl.h findnonce.c findnonce.h \
|
||||
adl.c adl.h adl_functions.h \
|
||||
phatk110817.cl poclbm110817.cl \
|
||||
sha2.c sha2.h api.c
|
||||
endif
|
||||
bin_SCRIPTS = phatk120203.cl poclbm120203.cl
|
||||
|
||||
cgminer_LDFLAGS = $(PTHREAD_FLAGS)
|
||||
cgminer_LDADD = $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
|
||||
@ -45,22 +25,51 @@ cgminer_LDADD = $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
|
||||
@MATH_LIBS@ lib/libgnu.a ccan/libccan.a
|
||||
cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@
|
||||
|
||||
# common sources
|
||||
|
||||
# this is the original monolithic main.c, kept as reference
|
||||
# cgminer_SOURCES := main.c
|
||||
|
||||
# this is the original main.c without extracted CPU and GPU code
|
||||
cgminer_SOURCES := cgminer.c
|
||||
|
||||
cgminer_SOURCES += elist.h miner.h compat.h bench_block.h \
|
||||
util.c uthash.h \
|
||||
sha2.c sha2.h api.c
|
||||
|
||||
# GPU sources, TODO: make them selectable
|
||||
# the GPU portion extracted from original main.c
|
||||
cgminer_SOURCES += device-gpu.h device-gpu.c
|
||||
|
||||
# the original GPU related sources, unchanged
|
||||
cgminer_SOURCES += ocl.c ocl.h findnonce.c findnonce.h
|
||||
cgminer_SOURCES += adl.c adl.h adl_functions.h
|
||||
cgminer_SOURCES += phatk120203.cl poclbm120203.cl
|
||||
|
||||
if HAS_CPUMINE
|
||||
if HAVE_x86_64
|
||||
# original CPU related sources, unchanged
|
||||
cgminer_SOURCES += \
|
||||
sha256_generic.c sha256_4way.c sha256_via.c \
|
||||
sha256_cryptopp.c sha256_sse2_amd64.c \
|
||||
sha256_sse4_amd64.c sha256_sse2_i386.c \
|
||||
sha256_altivec_4way.c
|
||||
|
||||
# the CPU portion extracted from original main.c
|
||||
cgminer_SOURCES += device-cpu.h device-cpu.c
|
||||
|
||||
if HAS_YASM
|
||||
AM_CFLAGS = -DHAS_YASM
|
||||
if HAVE_x86_64
|
||||
SUBDIRS += x86_64
|
||||
cgminer_LDADD += x86_64/libx8664.a
|
||||
AM_CFLAGS = -DHAS_YASM
|
||||
endif
|
||||
else
|
||||
if HAS_YASM
|
||||
else # HAVE_x86_64
|
||||
SUBDIRS += x86_32
|
||||
cgminer_LDADD += x86_32/libx8632.a
|
||||
AM_CFLAGS = -DHAS_YASM
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif # HAVE_x86_64
|
||||
endif # HAS_YASM
|
||||
endif # HAS_CPUMINE
|
||||
|
||||
if HAS_BITFORCE
|
||||
cgminer_SOURCES += bitforce.c
|
||||
endif
|
||||
|
||||
|
788
device-cpu.c
Normal file
788
device-cpu.c
Normal file
@ -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
|
||||
|
||||
|
||||
|
20
device-cpu.h
Normal file
20
device-cpu.h
Normal file
@ -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__ */
|
1206
device-gpu.c
Normal file
1206
device-gpu.c
Normal file
File diff suppressed because it is too large
Load Diff
27
device-gpu.h
Normal file
27
device-gpu.h
Normal file
@ -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…
x
Reference in New Issue
Block a user