Browse Source

Implement a completely curses based display and don't output to stderr when log is enabled unless it's redirected away from the terminal.

nfactor-troky
Con Kolivas 13 years ago
parent
commit
90839cdf5a
  1. 2
      Makefile.am
  2. 1
      README
  3. 2
      configure.ac
  4. 161
      main.c
  5. 3
      miner.h
  6. 16
      util.c

2
Makefile.am

@ -22,7 +22,7 @@ cgminer_SOURCES = elist.h miner.h compat.h \
sha256_cryptopp.c sha256_sse2_amd64.c sha256_cryptopp.c sha256_sse2_amd64.c
cgminer_LDFLAGS = $(PTHREAD_FLAGS) cgminer_LDFLAGS = $(PTHREAD_FLAGS)
cgminer_LDADD = @LIBCURL@ @JANSSON_LIBS@ @PTHREAD_LIBS@ @OPENCL_LIBS@ lib/libgnu.a ccan/libccan.a cgminer_LDADD = @LIBCURL@ @JANSSON_LIBS@ @PTHREAD_LIBS@ @OPENCL_LIBS@ @NCURSES_LIBS@ lib/libgnu.a ccan/libccan.a
cgminer_CPPFLAGS = @LIBCURL_CPPFLAGS@ -I$(top_builddir)/lib -I$(top_srcdir)/lib cgminer_CPPFLAGS = @LIBCURL_CPPFLAGS@ -I$(top_builddir)/lib -I$(top_srcdir)/lib
if HAVE_x86_64 if HAVE_x86_64

1
README

@ -7,6 +7,7 @@ Dependencies:
libcurl http://curl.haxx.se/libcurl/ libcurl http://curl.haxx.se/libcurl/
jansson http://www.digip.org/jansson/ jansson http://www.digip.org/jansson/
(jansson is included in-tree and an installed one may conflict) (jansson is included in-tree and an installed one may conflict)
libncurses5-dev (or libpdcurses on WIN32)
Basic *nix build instructions: Basic *nix build instructions:
To build with GPU mining support: To build with GPU mining support:

2
configure.ac

@ -60,6 +60,7 @@ LIBS=$SAVED_LIBS
AC_CHECK_LIB(jansson, json_loads, request_jansson=false, request_jansson=true) AC_CHECK_LIB(jansson, json_loads, request_jansson=false, request_jansson=true)
AC_CHECK_LIB(pthread, pthread_create, PTHREAD_LIBS=-lpthread) AC_CHECK_LIB(pthread, pthread_create, PTHREAD_LIBS=-lpthread)
AC_CHECK_LIB(ncurses, addstr, NCURSES_LIBS=-lncurses)
AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue]) AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue])
AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
@ -148,6 +149,7 @@ AC_SUBST(OPENCL_LIBS)
AC_SUBST(JANSSON_LIBS) AC_SUBST(JANSSON_LIBS)
AC_SUBST(PTHREAD_FLAGS) AC_SUBST(PTHREAD_FLAGS)
AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_LIBS)
AC_SUBST(NCURSES_LIBS)
AC_CONFIG_FILES([ AC_CONFIG_FILES([
Makefile Makefile

161
main.c

@ -28,6 +28,7 @@
#include <ccan/opt/opt.h> #include <ccan/opt/opt.h>
#include <jansson.h> #include <jansson.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <curses.h>
#include "compat.h" #include "compat.h"
#include "miner.h" #include "miner.h"
#include "findnonce.h" #include "findnonce.h"
@ -507,13 +508,108 @@ err_out:
return false; return false;
} }
static double total_secs; static inline int gpu_from_thr_id(int thr_id)
{
return thr_id % nDevs;
}
static inline int cpu_from_thr_id(int thr_id)
{
return (thr_id - gpu_threads) % num_processors;
}
static WINDOW * mainwin;
static double total_secs = 0.1;
static char statusline[256]; static char statusline[256];
static int cpucursor, gpucursor, logstart, logcursor;
static bool curses_active = false;
static struct cgpu_info *gpus, *cpus;
static inline void print_status(int thr_id)
{
int x;
if (unlikely(!curses_active))
return;
getyx(mainwin, logcursor, x);
move(2,0);
printw("Totals: %s", statusline);
clrtoeol();
if (thr_id && thr_id < gpu_threads) {
int gpu = gpu_from_thr_id(thr_id);
struct cgpu_info *cgpu = &gpus[gpu];
move(gpucursor + gpu, 0);
printw("GPU %d: [%.1f Mh/s] [Q:%d A:%d R:%d HW:%d E:%.0f%% U:%.2f/m] ",
gpu, cgpu->total_mhashes / total_secs,
cgpu->getworks, cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
cgpu->efficiency, cgpu->utility);
clrtoeol();
} else if (thr_id && thr_id >= gpu_threads) {
int cpu = cpu_from_thr_id(thr_id);
struct cgpu_info *cgpu = &cpus[cpu];
move(cpucursor + cpu, 0);
printw("CPU %d: [%.1f Mh/s] [Q:%d A:%d R:%d HW:%d E:%.0f%% U:%.2f/m]",
cpu, cgpu->total_mhashes / total_secs,
cgpu->getworks, cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
cgpu->efficiency, cgpu->utility);
clrtoeol();
}
move(logcursor, 0);
refresh();
}
static void refresh_display(void)
{
int i, x, maxy;
if (unlikely(!curses_active))
return;
getyx(mainwin, logcursor, x);
move(0,0);
attron(A_BOLD);
printw(PROGRAM_NAME " version " VERSION);
attroff(A_BOLD);
clrtoeol();
move(1, 0);
clrtoeol();
hline('-', 80);
move(3, 0);
clrtoeol();
hline('-', 80);
move(logstart, 0);
clrtoeol();
hline('-', 80);
move(logcursor, 0);
for (i = 0; i < mining_threads; i++)
print_status(i);
static inline void print_status(void) move(logcursor, 0);
redrawwin(mainwin);
}
void log_curses(const char *f, va_list ap)
{ {
printf("%s\r", statusline); int i, x, maxy;
fflush(stdout);
if (unlikely(!curses_active))
return;
vwprintw(mainwin, f, ap);
clrtoeol();
getyx(mainwin, logcursor, x);
/* Scroll log output downwards */
getmaxyx(mainwin, maxy, x);
if (logcursor >= maxy - 1)
refresh_display();
else
refresh();
} }
static bool submit_fail = false; static bool submit_fail = false;
@ -526,7 +622,6 @@ static bool submit_upstream_work(const struct work *work)
bool rc = false; bool rc = false;
struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu; struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu;
CURL *curl = curl_easy_init(); CURL *curl = curl_easy_init();
double utility, efficiency;
if (unlikely(!curl)) { if (unlikely(!curl)) {
applog(LOG_ERR, "CURL initialisation failed"); applog(LOG_ERR, "CURL initialisation failed");
@ -573,29 +668,26 @@ static bool submit_upstream_work(const struct work *work)
if (opt_debug) if (opt_debug)
applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)"); applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)");
if (!opt_quiet) if (!opt_quiet)
printf("[Accepted] "); applog(LOG_WARNING, "Share accepted from %sPU %d",
cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu);
} else { } else {
cgpu->rejected++; cgpu->rejected++;
rejected++; rejected++;
if (opt_debug) if (opt_debug)
applog(LOG_DEBUG, "PROOF OF WORK RESULT: false (booooo)"); applog(LOG_DEBUG, "PROOF OF WORK RESULT: false (booooo)");
if (!opt_quiet) if (!opt_quiet)
printf("[Rejected] "); applog(LOG_WARNING, "Share rejected from %sPU %d",
cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu);
} }
utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60; cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
efficiency = cgpu->getworks ? cgpu->accepted * 100.0 / cgpu->getworks : 0.0; cgpu->efficiency = cgpu->getworks ? cgpu->accepted * 100.0 / cgpu->getworks : 0.0;
if (!opt_quiet) { if (!opt_quiet)
printf("[%sPU %d] [%.1f Mh/s] [Q:%d A:%d R:%d HW:%d E:%.0f%% U:%.2f/m] \n", print_status(work->thr_id);
cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu, cgpu->total_mhashes / total_secs,
cgpu->getworks, cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
efficiency, utility);
print_status();
}
applog(LOG_INFO, "%sPU %d Requested:%d Accepted:%d Rejected:%d HW errors:%d Efficiency:%.0f%% Utility:%.2f/m", applog(LOG_INFO, "%sPU %d Requested:%d Accepted:%d Rejected:%d HW errors:%d Efficiency:%.0f%% Utility:%.2f/m",
cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu, cgpu->getworks, cgpu->accepted, cgpu->rejected, cgpu->hw_errors, efficiency, utility cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu, cgpu->getworks, cgpu->accepted,
); cgpu->rejected, cgpu->hw_errors, cgpu->efficiency, cgpu->utility);
json_decref(val); json_decref(val);
@ -960,7 +1052,7 @@ static void hashmeter(int thr_id, struct timeval *diff,
sprintf(statusline, "[(%ds):%.1f (avg):%.1f Mh/s] [Q:%d A:%d R:%d HW:%d E:%.0f%% U:%.2f/m] ", sprintf(statusline, "[(%ds):%.1f (avg):%.1f Mh/s] [Q:%d A:%d R:%d HW:%d E:%.0f%% U:%.2f/m] ",
opt_log_interval, rolling_local / local_secs, total_mhashes_done / total_secs, opt_log_interval, rolling_local / local_secs, total_mhashes_done / total_secs,
getwork_requested, accepted, rejected, hw_errors, efficiency, utility); getwork_requested, accepted, rejected, hw_errors, efficiency, utility);
print_status(); print_status(thr_id);
applog(LOG_INFO, "[Rate (%ds):%.1f (avg):%.2f Mhash/s] [Requested:%d Accepted:%d Rejected:%d HW errors:%d Efficiency:%.0f%% Utility:%.2f/m]", applog(LOG_INFO, "[Rate (%ds):%.1f (avg):%.2f Mhash/s] [Requested:%d Accepted:%d Rejected:%d HW errors:%d Efficiency:%.0f%% Utility:%.2f/m]",
opt_log_interval, rolling_local / local_secs, total_mhashes_done / total_secs, opt_log_interval, rolling_local / local_secs, total_mhashes_done / total_secs,
getwork_requested, accepted, rejected, hw_errors, efficiency, utility); getwork_requested, accepted, rejected, hw_errors, efficiency, utility);
@ -1183,11 +1275,6 @@ bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
return submit_work_sync(thr, work); return submit_work_sync(thr, work);
} }
static inline int cpu_from_thr_id(int thr_id)
{
return (thr_id - gpu_threads) % num_processors;
}
static void *miner_thread(void *userdata) static void *miner_thread(void *userdata)
{ {
struct thr_info *mythr = userdata; struct thr_info *mythr = userdata;
@ -1404,11 +1491,6 @@ static inline cl_int queue_kernel_parameters(_clState *clState, dev_blk_ctx *blk
return status; return status;
} }
static inline int gpu_from_thr_id(int thr_id)
{
return thr_id % nDevs;
}
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;
@ -1661,7 +1743,6 @@ int main (int argc, char *argv[])
struct thr_info *thr; struct thr_info *thr;
unsigned int i, j = 0; unsigned int i, j = 0;
char name[32]; char name[32];
struct cgpu_info *gpus = NULL, *cpus = NULL;
if (unlikely(pthread_mutex_init(&time_lock, NULL))) if (unlikely(pthread_mutex_init(&time_lock, NULL)))
return 1; return 1;
@ -1726,7 +1807,12 @@ int main (int argc, char *argv[])
opt_n_threads = num_processors; opt_n_threads = num_processors;
} }
logcursor = 4;
mining_threads = opt_n_threads + gpu_threads; mining_threads = opt_n_threads + gpu_threads;
gpucursor = logcursor;
cpucursor = gpucursor + total_devices + 1;
logstart = cpucursor + (opt_n_threads ? num_processors : 0);
logcursor = logstart + 1;
if (!rpc_userpass) { if (!rpc_userpass) {
if (!rpc_user || !rpc_pass) { if (!rpc_user || !rpc_pass) {
@ -1907,6 +1993,17 @@ int main (int argc, char *argv[])
total_mhashes_done = 0; total_mhashes_done = 0;
pthread_mutex_unlock(&hash_lock); pthread_mutex_unlock(&hash_lock);
/* Set up the ncurses interface */
if ((mainwin = initscr()) == NULL) {
applog(LOG_ERR, "Failed to initscr");
return 1;
}
idlok(mainwin, true);
scrollok(mainwin, true);
curses_active = true;
move(logcursor, 0);
refresh_display();
/* main loop - simply wait for workio thread to exit */ /* main loop - simply wait for workio thread to exit */
pthread_join(thr_info[work_thr_id].pth, NULL); pthread_join(thr_info[work_thr_id].pth, NULL);
curl_global_cleanup(); curl_global_cleanup();
@ -1917,6 +2014,10 @@ int main (int argc, char *argv[])
applog(LOG_INFO, "workio thread dead, exiting."); applog(LOG_INFO, "workio thread dead, exiting.");
delwin(mainwin);
endwin();
refresh();
return 0; return 0;
} }

3
miner.h

@ -135,6 +135,8 @@ struct cgpu_info {
double local_mhashes; double local_mhashes;
double total_mhashes; double total_mhashes;
unsigned int getworks; unsigned int getworks;
double efficiency;
double utility;
}; };
struct thr_info { struct thr_info {
@ -267,6 +269,7 @@ struct work {
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce); bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
extern void log_curses(const char *f, va_list ap);
extern void vapplog(int prio, const char *fmt, va_list ap); extern void vapplog(int prio, const char *fmt, va_list ap);
extern void applog(int prio, const char *fmt, ...); extern void applog(int prio, const char *fmt, ...);
extern struct thread_q *tq_new(void); extern struct thread_q *tq_new(void);

16
util.c

@ -20,6 +20,7 @@
#include <jansson.h> #include <jansson.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <time.h> #include <time.h>
#include <curses.h>
#include "miner.h" #include "miner.h"
#include "elist.h" #include "elist.h"
@ -68,7 +69,7 @@ void vapplog(int prio, const char *fmt, va_list ap)
#endif #endif
else if (opt_log_output || prio == LOG_WARNING || prio == LOG_ERR) { else if (opt_log_output || prio == LOG_WARNING || prio == LOG_ERR) {
char *f; char *f;
int len, i, extra = 0; int len;
struct timeval tv = { }; struct timeval tv = { };
struct tm tm, *tm_p; struct tm tm, *tm_p;
@ -80,10 +81,8 @@ void vapplog(int prio, const char *fmt, va_list ap)
pthread_mutex_unlock(&time_lock); pthread_mutex_unlock(&time_lock);
len = 40 + strlen(fmt) + 2; len = 40 + strlen(fmt) + 2;
if (len < 80) f = alloca(len);
extra = 80 - len; sprintf(f, "[%d-%02d-%02d %02d:%02d:%02d] %s\n",
f = alloca(len + extra);
sprintf(f, "[%d-%02d-%02d %02d:%02d:%02d] %s",
tm.tm_year + 1900, tm.tm_year + 1900,
tm.tm_mon + 1, tm.tm_mon + 1,
tm.tm_mday, tm.tm_mday,
@ -91,12 +90,13 @@ void vapplog(int prio, const char *fmt, va_list ap)
tm.tm_min, tm.tm_min,
tm.tm_sec, tm.tm_sec,
fmt); fmt);
/* Only output to stderr if it's not going to the screen as well */
if (opt_log_output && !isatty(fileno((FILE *)stderr))) {
vfprintf(stderr, f, ap); /* atomic write to stderr */ vfprintf(stderr, f, ap); /* atomic write to stderr */
for (i = 0; i < extra; i++)
fprintf(stderr, " ");
fprintf(stderr, "\n");
fflush(stderr); fflush(stderr);
} }
log_curses(f, ap);
}
} }
void applog(int prio, const char *fmt, ...) void applog(int prio, const char *fmt, ...)

Loading…
Cancel
Save