/* * 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 3 of the License, or (at your option) * any later version. See COPYING for more details. */ #include "config.h" #include #include #include #include #include #include #include #include #include #ifndef WIN32 #include #include #endif #include #include "compat.h" #include "miner.h" #include "bench_block.h" #include "driver-cpu.h" #if defined(unix) #include #include #endif #if defined(__linux) && defined(cpu_set_t) /* Linux specific policy and affinity management */ #include 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 __maybe_unused id, int __maybe_unused cpu) { } #endif /* TODO: resolve externals */ extern void submit_work_async(const struct work *work_in, struct timeval *tv); 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 *thr, int thr_id, unsigned char *pdata, unsigned char *scratchbuf, const unsigned char *ptarget, uint32_t max_nonce, unsigned long *hashes_done); #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 }; 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 #if defined(WANT_X8664_SSE4) && defined(__SSE4_1__) enum sha256_algos opt_algo = ALGO_SSE4_64; #elif 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))); unsigned char hash1[64]; 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 thr_info dummy = {0}; struct timeval end; struct timeval start; uint32_t max_nonce = (1<<22); uint32_t last_nonce = 0; hex2bin(hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000", 64); gettimeofday(&start, 0); { sha256_func func = sha256_funcs[algo]; (*func)( &dummy, work.midstate, work.data, hash1, work.hash, work.target, max_nonce, &last_nonce, work.blk.nonce ); } gettimeofday(&end, 0); 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 (0drv = &cpu_drv; cgpu->deven = DEV_ENABLED; cgpu->threads = 1; cgpu->kname = algo_names[opt_algo]; add_cgpu(cgpu); } } static void reinit_cpu_device(struct cgpu_info *cpu) { tq_push(control_thr[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 __maybe_unused *thr) { return 0xffff; } 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 int64_t cpu_scanhash(struct thr_info *thr, struct work *work, int64_t max_nonce) { const int thr_id = thr->id; unsigned char hash1[64]; uint32_t first_nonce = work->blk.nonce; uint32_t last_nonce; bool rc; hex2bin(hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000", 64); 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, "CPU %d found something?", dev_from_id(thr_id)); submit_work_async(work, NULL); 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 = { .drv_id = DRIVER_CPU, .dname = "cpu", .name = "CPU", .drv_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