@ -713,10 +713,20 @@ static bool queue_request(void)
return true ;
return true ;
}
}
static void flush_requests ( void )
static bool discard_request ( void )
{
{
struct thr_info * thr = & thr_info [ 0 ] ;
struct thr_info * thr = & thr_info [ 0 ] ;
struct work * work_heap ;
struct work * work_heap ;
work_heap = tq_pop ( thr - > q , NULL ) ;
if ( unlikely ( ! work_heap ) )
return false ;
free ( work_heap ) ;
return true ;
}
static void flush_requests ( void )
{
unsigned int i ;
unsigned int i ;
/* Queue a whole batch of new requests */
/* Queue a whole batch of new requests */
@ -731,25 +741,21 @@ static void flush_requests(void)
/* Pop off the old requests. Cancelling the requests would be better
/* Pop off the old requests. Cancelling the requests would be better
* but is tricky */
* but is tricky */
for ( i = 0 ; i < opt_queue ; i + + ) {
for ( i = 0 ; i < opt_queue ; i + + ) {
work_heap = tq_pop ( thr - > q , NULL ) ;
if ( unlikely ( ! discard_request ( ) ) ) {
if ( unlikely ( ! work_heap ) ) {
applog ( LOG_ERR , " Failed to discard requests in flush_requests " ) ;
applog ( LOG_ERR , " Failed to pop requests in flush_requests " ) ;
kill_work ( ) ;
kill_work ( ) ;
return ;
return ;
}
}
free ( work_heap ) ;
}
}
}
}
static bool get_work ( struct work * work )
static bool get_work ( struct work * work , bool queued )
{
{
struct thr_info * thr = & thr_info [ 0 ] ;
struct thr_info * thr = & thr_info [ 0 ] ;
static bool first_work = true ;
struct work * work_heap ;
struct work * work_heap ;
bool ret = false ;
bool ret = false ;
unsigned int i ;
if ( unlikely ( ! queue_request ( ) ) )
if ( unlikely ( ! queued & & ! queue _request ( ) ) )
goto out ;
goto out ;
/* wait for 1st response, or get cached response */
/* wait for 1st response, or get cached response */
@ -757,20 +763,9 @@ static bool get_work(struct work *work)
if ( unlikely ( ! work_heap ) )
if ( unlikely ( ! work_heap ) )
goto out ;
goto out ;
if ( unlikely ( first_work ) ) {
first_work = false ;
/* send for extra work requests for the next time get_work
* is called . */
for ( i = 1 ; i < opt_queue ; i + + ) {
if ( unlikely ( ! queue_request ( ) ) )
goto out_free ;
}
}
memcpy ( work , work_heap , sizeof ( * work ) ) ;
memcpy ( work , work_heap , sizeof ( * work ) ) ;
memcpy ( current_block , work - > data , 36 ) ;
memcpy ( current_block , work - > data , 36 ) ;
ret = true ;
ret = true ;
out_free :
free ( work_heap ) ;
free ( work_heap ) ;
out :
out :
return ret ;
return ret ;
@ -831,6 +826,10 @@ static void *miner_thread(void *userdata)
bool needs_work = true ;
bool needs_work = true ;
/* Try to cycle approximately 5 times before each log update */
/* Try to cycle approximately 5 times before each log update */
const unsigned long cycle = opt_log_interval / 5 ? : 1 ;
const unsigned long cycle = opt_log_interval / 5 ? : 1 ;
/* Request the next work item at 2/3 of the scantime */
unsigned const int request_interval = opt_scantime * 2 / 3 ? : 1 ;
unsigned const long request_nonce = MAXTHREADS / 3 * 2 ;
bool requested = false ;
/* Set worker threads to nice 19 and then preferentially to SCHED_IDLE
/* 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
* and if that fails , then SCHED_BATCH . No need for this to be an
@ -851,15 +850,25 @@ static void *miner_thread(void *userdata)
bool rc ;
bool rc ;
if ( needs_work ) {
if ( needs_work ) {
if ( work_restart [ thr_id ] . restart ) {
if ( requested ) {
/* We have one extra request than desired now */
if ( unlikely ( ! discard_request ( ) ) ) {
applog ( LOG_ERR , " Failed to discard request in uminer thread " ) ;
goto out ;
}
} else
requested = true ;
}
gettimeofday ( & tv_workstart , NULL ) ;
gettimeofday ( & tv_workstart , NULL ) ;
/* obtain new work from internal workio thread */
/* obtain new work from internal workio thread */
if ( unlikely ( ! get_work ( & work ) ) ) {
if ( unlikely ( ! get_work ( & work , requested ) ) ) {
applog ( LOG_ERR , " work retrieval failed, exiting "
applog ( LOG_ERR , " work retrieval failed, exiting "
" mining thread %d " , mythr - > id ) ;
" mining thread %d " , mythr - > id ) ;
goto out ;
goto out ;
}
}
work . thr_id = thr_id ;
work . thr_id = thr_id ;
needs_work = false ;
needs_work = requested = false ;
work . blk . nonce = 0 ;
work . blk . nonce = 0 ;
}
}
hashes_done = 0 ;
hashes_done = 0 ;
@ -958,6 +967,12 @@ static void *miner_thread(void *userdata)
}
}
timeval_subtract ( & diff , & tv_end , & tv_workstart ) ;
timeval_subtract ( & diff , & tv_end , & tv_workstart ) ;
if ( ! requested & & ( diff . tv_sec > request_interval | | work . blk . nonce > request_nonce ) ) {
if ( unlikely ( ! queue_request ( ) ) )
goto out ;
requested = true ;
}
if ( diff . tv_sec > opt_scantime | | work_restart [ thr_id ] . restart | |
if ( diff . tv_sec > opt_scantime | | work_restart [ thr_id ] . restart | |
work . blk . nonce > = MAXTHREADS - hashes_done )
work . blk . nonce > = MAXTHREADS - hashes_done )
needs_work = true ;
needs_work = true ;
@ -1031,8 +1046,8 @@ static inline int gpu_from_thr_id(int thr_id)
static void * gpuminer_thread ( void * userdata )
static void * gpuminer_thread ( void * userdata )
{
{
const unsigned long cycle = opt_log_interval / 5 ? : 1 ;
const unsigned long cycle = opt_log_interval / 5 ? : 1 ;
struct timeval tv_start , tv_end , diff ;
struct thr_info * mythr = userdata ;
struct thr_info * mythr = userdata ;
struct timeval tv_start , diff ;
const int thr_id = mythr - > id ;
const int thr_id = mythr - > id ;
uint32_t * res , * blank_res ;
uint32_t * res , * blank_res ;
@ -1050,6 +1065,11 @@ static void *gpuminer_thread(void *userdata)
unsigned const int hashes = threads * vectors ;
unsigned const int hashes = threads * vectors ;
unsigned int hashes_done = 0 ;
unsigned int hashes_done = 0 ;
/* Request the next work item at 2/3 of the scantime */
unsigned const int request_interval = opt_scantime * 2 / 3 ? : 1 ;
unsigned const long request_nonce = MAXTHREADS / 3 * 2 ;
bool requested = false ;
res = calloc ( BUFFERSIZE , 1 ) ;
res = calloc ( BUFFERSIZE , 1 ) ;
blank_res = calloc ( BUFFERSIZE , 1 ) ;
blank_res = calloc ( BUFFERSIZE , 1 ) ;
@ -1061,11 +1081,11 @@ static void *gpuminer_thread(void *userdata)
gettimeofday ( & tv_start , NULL ) ;
gettimeofday ( & tv_start , NULL ) ;
globalThreads [ 0 ] = threads ;
globalThreads [ 0 ] = threads ;
localThreads [ 0 ] = clState - > work_size ;
localThreads [ 0 ] = clState - > work_size ;
work_restart [ thr_id ] . restart = 1 ;
diff . tv_sec = ~ 0UL ;
diff . tv_sec = 0 ;
gettimeofday ( & tv_end , NULL ) ;
while ( 1 ) {
while ( 1 ) {
struct timeval tv_end , tv_ workstart ;
struct timeval tv_workstart ;
/* This finish flushes the readbuffer set with CL_FALSE later */
/* This finish flushes the readbuffer set with CL_FALSE later */
clFinish ( clState - > commandQueue ) ;
clFinish ( clState - > commandQueue ) ;
@ -1078,13 +1098,24 @@ static void *gpuminer_thread(void *userdata)
memset ( res , 0 , BUFFERSIZE ) ;
memset ( res , 0 , BUFFERSIZE ) ;
gettimeofday ( & tv_workstart , NULL ) ;
gettimeofday ( & tv_workstart , NULL ) ;
if ( work_restart [ thr_id ] . restart ) {
if ( requested ) {
/* We have one extra request than desired now */
if ( unlikely ( ! discard_request ( ) ) ) {
applog ( LOG_ERR , " Failed to discard request in gpuminer thread " ) ;
goto out ;
}
} else
requested = true ;
}
/* obtain new work from internal workio thread */
/* obtain new work from internal workio thread */
if ( unlikely ( ! get_work ( work ) ) ) {
if ( unlikely ( ! get_work ( work , requested ) ) ) {
applog ( LOG_ERR , " work retrieval failed, exiting "
applog ( LOG_ERR , " work retrieval failed, exiting "
" gpu mining thread %d " , mythr - > id ) ;
" gpu mining thread %d " , mythr - > id ) ;
goto out ;
goto out ;
}
}
work - > thr_id = thr_id ;
work - > thr_id = thr_id ;
requested = false ;
precalc_hash ( & work - > blk , ( uint32_t * ) ( work - > midstate ) , ( uint32_t * ) ( work - > data + 64 ) ) ;
precalc_hash ( & work - > blk , ( uint32_t * ) ( work - > midstate ) , ( uint32_t * ) ( work - > data + 64 ) ) ;
work - > blk . nonce = 0 ;
work - > blk . nonce = 0 ;
@ -1136,6 +1167,11 @@ static void *gpuminer_thread(void *userdata)
}
}
timeval_subtract ( & diff , & tv_end , & tv_workstart ) ;
timeval_subtract ( & diff , & tv_end , & tv_workstart ) ;
if ( ! requested & & ( diff . tv_sec > request_interval | | work - > blk . nonce > request_nonce ) ) {
if ( unlikely ( ! queue_request ( ) ) )
goto out ;
requested = true ;
}
}
}
out :
out :
tq_freeze ( mythr - > q ) ;
tq_freeze ( mythr - > q ) ;
@ -1149,9 +1185,19 @@ static void restart_threads(void)
/* Discard old queued requests and get new ones */
/* Discard old queued requests and get new ones */
flush_requests ( ) ;
flush_requests ( ) ;
for ( i = 0 ; i < opt_n_threads + gpu_threads ; i + + )
/* Queue extra requests for each worker thread since they'll all need
* new work . Each worker will set their " requested " flag to true
* should they receive a . restart */
for ( i = 0 ; i < opt_n_threads + gpu_threads ; i + + ) {
if ( unlikely ( ! queue_request ( ) ) ) {
applog ( LOG_ERR , " Failed to queue requests in flush_requests " ) ;
kill_work ( ) ;
return ;
}
work_restart [ i ] . restart = 1 ;
work_restart [ i ] . restart = 1 ;
}
}
}
static void * longpoll_thread ( void * userdata )
static void * longpoll_thread ( void * userdata )
{
{
@ -1545,6 +1591,14 @@ int main (int argc, char *argv[])
}
}
}
}
/* Put the extra work in the queue */
for ( i = 1 ; i < opt_queue ; i + + ) {
if ( unlikely ( ! queue_request ( ) ) ) {
applog ( LOG_ERR , " Failed to queue_request in main " ) ;
return 1 ;
}
}
/* start GPU mining threads */
/* start GPU mining threads */
for ( i = 0 ; i < gpu_threads ; i + + ) {
for ( i = 0 ; i < gpu_threads ; i + + ) {
int gpu = gpu_from_thr_id ( i ) ;
int gpu = gpu_from_thr_id ( i ) ;