Browse Source

api: add histo command and difficulty

enhance multi-gpu stats and fix nvapi indexes

change syslog prefix to ccminer (cpuminer remains)

api 1.1 modified - not officially released yet
master
Tanguy Pruvot 10 years ago
parent
commit
3652c708b9
  1. 62
      api.cpp
  2. 31
      api/index.php
  3. 23
      ccminer.cpp
  4. 26
      miner.h
  5. 52
      nvml.cpp
  6. 6
      nvml.h
  7. 52
      stats.cpp
  8. 3
      util.cpp

62
api.cpp

@ -21,7 +21,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <inttypes.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
@ -32,6 +32,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include "compat.h" #include "compat.h"
#include "miner.h" #include "miner.h"
@ -115,21 +116,19 @@ extern uint32_t rejected_count;
static void gpustatus(int thr_id) static void gpustatus(int thr_id)
{ {
char buf[MYBUFSIZ];
if (thr_id >= 0 && thr_id < gpu_threads) { if (thr_id >= 0 && thr_id < gpu_threads) {
struct cgpu_info *cgpu = &thr_info[thr_id].gpu; struct cgpu_info *cgpu = &thr_info[thr_id].gpu;
char buf[512];
char pstate[4];
cgpu->thr_id = thr_id; cgpu->thr_id = thr_id;
#ifdef USE_WRAPNVML #ifdef USE_WRAPNVML
// todo cgpu->has_monitoring = true;
if (1 || cgpu->has_monitoring) {
cgpu->gpu_temp = gpu_temp(cgpu); cgpu->gpu_temp = gpu_temp(cgpu);
cgpu->gpu_fan = gpu_fanpercent(cgpu); cgpu->gpu_fan = gpu_fanpercent(cgpu);
cgpu->gpu_power = gpu_power(cgpu); cgpu->gpu_pstate = gpu_pstate(cgpu);
cgpu->gpu_clock = gpu_clock(cgpu); cgpu->gpu_clock = gpu_clock(cgpu);
}
#endif #endif
// todo: can be 0 if set by algo (auto) // todo: can be 0 if set by algo (auto)
@ -147,38 +146,50 @@ static void gpustatus(int thr_id)
cgpu->accepted = accepted_count; cgpu->accepted = accepted_count;
cgpu->rejected = rejected_count; cgpu->rejected = rejected_count;
cgpu->khashes = stats_get_speed(thr_id) / 1000.0; cgpu->khashes = stats_get_speed(thr_id, 0.0) / 1000.0;
sprintf(pstate, "P%u", cgpu->gpu_pstate);
if (cgpu->gpu_pstate == -1)
sprintf(pstate, "");
sprintf(buf, "GPU=%d;TEMP=%.1f;FAN=%d;FREQ=%d;POWER=%d;KHS=%.2f;" sprintf(buf, "GPU=%d;TEMP=%.1f;FAN=%d;FREQ=%d;PST=%s;KHS=%.2f;"
"HWF=%d;I=%d|", "HWF=%d;I=%d|",
thr_id, cgpu->gpu_temp, cgpu->gpu_fan, thr_id, cgpu->gpu_temp, cgpu->gpu_fan,
cgpu->gpu_clock, cgpu->gpu_power, cgpu->khashes, cgpu->gpu_clock, pstate, cgpu->khashes,
cgpu->hw_errors, cgpu->intensity); cgpu->hw_errors, cgpu->intensity);
// append to buffer for multi gpus
strcat(buffer, buf); strcat(buffer, buf);
} }
} }
/*****************************************************************************/ /*****************************************************************************/
/**
* Returns miner global infos
*/
static char *getsummary(char *params) static char *getsummary(char *params)
{ {
char algo[64] = ""; char algo[64] = "";
double uptime = difftime(time(NULL), startup); time_t ts = time(NULL);
double uptime = difftime(ts, startup);
double accps = (60.0 * accepted_count) / (uptime ? uptime : 1.0); double accps = (60.0 * accepted_count) / (uptime ? uptime : 1.0);
get_currentalgo(algo, sizeof(algo)); get_currentalgo(algo, sizeof(algo));
*buffer = '\0'; *buffer = '\0';
sprintf(buffer, "NAME=%s;VER=%s;API=%s;" sprintf(buffer, "NAME=%s;VER=%s;API=%s;"
"ALGO=%s;KHS=%.2f;ACC=%d;REJ=%d;ACCMN=%.3f;UPTIME=%.0f|", "ALGO=%s;KHS=%.2f;ACC=%d;REJ=%d;ACCMN=%.3f;DIFF=%.6f;UPTIME=%.0f;TS=%u|",
PACKAGE_NAME, PACKAGE_VERSION, APIVERSION, PACKAGE_NAME, PACKAGE_VERSION, APIVERSION,
algo, (double)global_hashrate / 1000.0, algo, (double)global_hashrate / 1000.0,
accepted_count, rejected_count, accepted_count, rejected_count,
accps, uptime); accps, global_diff, uptime, (uint32_t) ts);
return buffer; return buffer;
} }
/**
* Returns gpu/thread specific stats
*/
static char *getstats(char *params) static char *getstats(char *params)
{ {
*buffer = '\0'; *buffer = '\0';
@ -187,6 +198,30 @@ static char *getstats(char *params)
return buffer; return buffer;
} }
/**
* Returns the last 20 scans stats (not the same as shares)
* optional param thread id (default all)
*/
static char *gethistory(char *params)
{
struct stats_data data[20];
int thr = atoi(params ? params : "-1");
char *p = buffer;
if (!thr)
thr = -1;
*buffer = '\0';
int records = stats_get_history(thr, data, ARRAY_SIZE(data));
for (int i = 0; i < records; i++) {
char time[16];
time_t ts = data[i].tm_stat;
time2str(time, ts);
p += sprintf(p, "GPU=%d;KHS=%.2f;DIFF=%.6f;COUNT=%u;FOUND=%u;TS=%u;TIME=%s|",
data[i].gpu_id, data[i].hashrate, data[i].difficulty, data[i].hashcount,
data[i].hashfound, (uint32_t)ts, time);
}
return buffer;
}
static char *gethelp(char *params); static char *gethelp(char *params);
struct CMDS { struct CMDS {
const char *name; const char *name;
@ -194,6 +229,7 @@ struct CMDS {
} cmds[] = { } cmds[] = {
{ "summary", getsummary }, { "summary", getsummary },
{ "stats", getstats }, { "stats", getstats },
{ "histo", gethistory },
/* keep it the last */ /* keep it the last */
{ "help", gethelp }, { "help", gethelp },
}; };

31
api/index.php

@ -20,6 +20,12 @@ function getdataFromPears()
return $data; return $data;
} }
function ignoreField($key)
{
$ignored = array('API','VER');
return in_array($key, $ignored);
}
function translateField($key) function translateField($key)
{ {
$intl = array(); $intl = array();
@ -31,11 +37,14 @@ function translateField($key)
$intl['ACC'] = 'Accepted shares'; $intl['ACC'] = 'Accepted shares';
$intl['ACCMN'] = 'Accepted / mn'; $intl['ACCMN'] = 'Accepted / mn';
$intl['REJ'] = 'Rejected'; $intl['REJ'] = 'Rejected';
$intl['DIFF'] = 'Difficulty';
$intl['UPTIME'] = 'Miner up time'; $intl['UPTIME'] = 'Miner up time';
$intl['TS'] = 'Last update';
$intl['TEMP'] = 'T°c'; $intl['TEMP'] = 'T°c';
$intl['FAN'] = 'Fan %'; $intl['FAN'] = 'Fan %';
$intl['FREQ'] = 'Freq.'; $intl['FREQ'] = 'Freq.';
$intl['PST'] = 'P-State';
if (isset($intl[$key])) if (isset($intl[$key]))
return $intl[$key]; return $intl[$key];
@ -43,12 +52,20 @@ function translateField($key)
return $key; return $key;
} }
function translateValue($key,$val) function translateValue($key,$val,$data=array())
{ {
if ($key == 'UPTIME') { switch ($key) {
case 'UPTIME':
$min = floor(intval($val) / 60); $min = floor(intval($val) / 60);
$sec = intval($val) % 60; $sec = intval($val) % 60;
$val = "${min}mn ${sec}s"; $val = "${min}mn ${sec}s";
break;
case 'NAME':
$val = $data['NAME'].'&nbsp;'.$data['VER'];
break;
case 'TS':
$val = strftime("%H:%M:%S", (int) $val);
break;
} }
return $val; return $val;
} }
@ -63,15 +80,15 @@ function displayData($data)
if (!empty($stats)) { if (!empty($stats)) {
$summary = $stats['summary']; $summary = $stats['summary'];
foreach ($summary as $key=>$val) { foreach ($summary as $key=>$val) {
if (!empty($val)) if (!empty($val) && !ignoreField($key))
$htm .= '<tr><td class="key">'.translateField($key).'</td>'. $htm .= '<tr><td class="key">'.translateField($key).'</td>'.
'<td class="val">'.translateValue($key, $val)."</td></tr>\n"; '<td class="val">'.translateValue($key, $val, $summary)."</td></tr>\n";
} }
$totals[$summary['ALGO']] += floatval($summary['KHS']); $totals[$summary['ALGO']] += floatval($summary['KHS']);
foreach ($stats['stats'] as $g=>$gpu) { foreach ($stats['stats'] as $g=>$gpu) {
$htm .= '<tr><th class="gpu" colspan="2">'.$g."</th></tr>\n"; $htm .= '<tr><th class="gpu" colspan="2">'.$g."</th></tr>\n";
foreach ($gpu as $key=>$val) { foreach ($gpu as $key=>$val) {
if (!empty($val)) if (!empty($val) && !ignoreField($key))
$htm .= '<tr><td class="key">'.translateField($key).'</td>'. $htm .= '<tr><td class="key">'.translateField($key).'</td>'.
'<td class="val">'.translateValue($key, $val)."</td></tr>\n"; '<td class="val">'.translateValue($key, $val)."</td></tr>\n";
} }
@ -137,8 +154,8 @@ div#footer {
table.stats { width: 280px; margin: 4px 16px; display: inline-block; } table.stats { width: 280px; margin: 4px 16px; display: inline-block; }
th.machine { color: darkcyan; padding: 16px 0px 0px 0px; text-align: left; border-bottom: 1px solid gray; } th.machine { color: darkcyan; padding: 16px 0px 0px 0px; text-align: left; border-bottom: 1px solid gray; }
th.gpu { color: white; padding: 3px 3px; font: bolder; text-align: left; background: rgba(65, 65, 65, 0.85); } th.gpu { color: white; padding: 3px 3px; font: bolder; text-align: left; background: rgba(65, 65, 65, 0.85); }
td.key { width: 40px; max-width: 120px; } td.key { width: 99px; max-width: 180px; }
td.val { width: 70px; max-width: 180px; color: white; } td.val { width: 40px; max-width: 100px; color: white; }
div.totals { margin: 16px; } div.totals { margin: 16px; }
div.totals h2 { color: darkcyan; font-size: 16px; margin-bottom: 4px; } div.totals h2 { color: darkcyan; font-size: 16px; margin-bottom: 4px; }

23
ccminer.cpp

@ -233,7 +233,8 @@ uint32_t accepted_count = 0L;
uint32_t rejected_count = 0L; uint32_t rejected_count = 0L;
static double *thr_hashrates; static double *thr_hashrates;
uint64_t global_hashrate = 0; uint64_t global_hashrate = 0;
int opt_statsavg = 20; double global_diff = 0.0;
int opt_statsavg = 30;
int opt_intensity = 0; int opt_intensity = 0;
uint32_t opt_work_size = 0; /* default */ uint32_t opt_work_size = 0; /* default */
@ -517,12 +518,11 @@ static int share_result(int result, const char *reason)
double hashrate = 0.; double hashrate = 0.;
pthread_mutex_lock(&stats_lock); pthread_mutex_lock(&stats_lock);
hashrate = stats_get_speed(-1);
if (hashrate < 0.001) { for (int i = 0; i < opt_n_threads; i++) {
hashrate = 0.; hashrate += stats_get_speed(i, thr_hashrates[i]);
for (int i = 0; i < opt_n_threads; i++)
hashrate += thr_hashrates[i];
} }
result ? accepted_count++ : rejected_count++; result ? accepted_count++ : rejected_count++;
pthread_mutex_unlock(&stats_lock); pthread_mutex_unlock(&stats_lock);
@ -1337,7 +1337,7 @@ continue_scan:
if (rc > 1) if (rc > 1)
thr_hashrates[thr_id] = (rc * hashes_done) / (diff.tv_sec + 1e-6 * diff.tv_usec); thr_hashrates[thr_id] = (rc * hashes_done) / (diff.tv_sec + 1e-6 * diff.tv_usec);
thr_hashrates[thr_id] *= rate_factor; thr_hashrates[thr_id] *= rate_factor;
stats_remember_speed(thr_id, hashes_done, thr_hashrates[thr_id]); stats_remember_speed(thr_id, hashes_done, thr_hashrates[thr_id], (uint8_t) rc);
} }
pthread_mutex_unlock(&stats_lock); pthread_mutex_unlock(&stats_lock);
} }
@ -1350,12 +1350,9 @@ continue_scan:
device_map[thr_id], device_name[device_map[thr_id]], s); device_map[thr_id], device_name[device_map[thr_id]], s);
} }
if (thr_id == opt_n_threads - 1) { if (thr_id == opt_n_threads - 1) {
double hashrate = stats_get_speed(-1); double hashrate = 0.;
if (hashrate < 0.001) {
hashrate = 0.;
for (int i = 0; i < opt_n_threads && thr_hashrates[i]; i++) for (int i = 0; i < opt_n_threads && thr_hashrates[i]; i++)
hashrate += thr_hashrates[i]; hashrate += stats_get_speed(i, thr_hashrates[i]);
}
if (opt_benchmark) { if (opt_benchmark) {
sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", hashrate / 1000.); sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", hashrate / 1000.);
applog(LOG_NOTICE, "Total: %s kH/s", s); applog(LOG_NOTICE, "Total: %s kH/s", s);
@ -2077,7 +2074,7 @@ int main(int argc, char *argv[])
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
if (use_syslog) if (use_syslog)
openlog("cpuminer", LOG_PID, LOG_USER); openlog(PACKAGE_NAME, LOG_PID, LOG_USER);
#endif #endif
work_restart = (struct work_restart *)calloc(opt_n_threads, sizeof(*work_restart)); work_restart = (struct work_restart *)calloc(opt_n_threads, sizeof(*work_restart));

26
miner.h

@ -365,10 +365,10 @@ struct cgpu_info {
#ifdef USE_WRAPNVML #ifdef USE_WRAPNVML
bool has_monitoring; bool has_monitoring;
float gpu_temp; float gpu_temp;
unsigned int gpu_fan; int gpu_fan;
unsigned int gpu_power; int gpu_clock;
unsigned int gpu_clock; int gpu_memclock;
unsigned int gpu_memclock; int gpu_pstate;
double gpu_vddc; double gpu_vddc;
#endif #endif
}; };
@ -416,7 +416,9 @@ extern struct work_restart *work_restart;
extern bool opt_trust_pool; extern bool opt_trust_pool;
extern uint16_t opt_vote; extern uint16_t opt_vote;
extern uint32_t opt_work_size; extern uint32_t opt_work_size;
extern uint64_t global_hashrate; extern uint64_t global_hashrate;
extern double global_diff;
#define CL_N "\x1B[0m" #define CL_N "\x1B[0m"
#define CL_RED "\x1B[31m" #define CL_RED "\x1B[31m"
@ -497,6 +499,17 @@ struct stratum_ctx {
int bloc_height; int bloc_height;
}; };
struct stats_data {
uint32_t tm_stat;
uint32_t hashcount;
double difficulty;
double hashrate;
uint8_t thr_id;
uint8_t gpu_id;
uint8_t hashfound;
uint8_t ignored;
};
bool stratum_socket_full(struct stratum_ctx *sctx, int timeout); bool stratum_socket_full(struct stratum_ctx *sctx, int timeout);
bool stratum_send_line(struct stratum_ctx *sctx, char *s); bool stratum_send_line(struct stratum_ctx *sctx, char *s);
char *stratum_recv_line(struct stratum_ctx *sctx); char *stratum_recv_line(struct stratum_ctx *sctx);
@ -516,8 +529,9 @@ void hashlog_purge_job(char* jobid);
void hashlog_purge_all(void); void hashlog_purge_all(void);
void hashlog_dump_job(char* jobid); void hashlog_dump_job(char* jobid);
void stats_remember_speed(int thr_id, uint32_t hashcount, double hashrate); void stats_remember_speed(int thr_id, uint32_t hashcount, double hashrate, uint8_t found);
double stats_get_speed(int thr_id); double stats_get_speed(int thr_id, double def_speed);
int stats_get_history(int thr_id, struct stats_data *data, int max_records);
void stats_purge_old(void); void stats_purge_old(void);
void stats_purge_all(void); void stats_purge_all(void);

52
nvml.cpp

@ -338,6 +338,7 @@ int wrap_nvml_destroy(wrap_nvml_handle *nvmlh)
#ifdef WIN32 #ifdef WIN32
#include "nvapi/nvapi_ccminer.h" #include "nvapi/nvapi_ccminer.h"
static int nvapi_dev_map[NVAPI_MAX_PHYSICAL_GPUS] = { 0 };
static NvDisplayHandle hDisplay_a[NVAPI_MAX_PHYSICAL_GPUS * 2] = { 0 }; static NvDisplayHandle hDisplay_a[NVAPI_MAX_PHYSICAL_GPUS * 2] = { 0 };
static NvPhysicalGpuHandle phys[NVAPI_MAX_PHYSICAL_GPUS] = { 0 }; static NvPhysicalGpuHandle phys[NVAPI_MAX_PHYSICAL_GPUS] = { 0 };
static NvU32 nvapi_dev_cnt = 0; static NvU32 nvapi_dev_cnt = 0;
@ -412,7 +413,7 @@ int nvapi_getclock(unsigned int devNum, unsigned int *freq)
return 0; return 0;
} }
int nvapi_getpower(unsigned int devNum, unsigned int *power) int nvapi_getpstate(unsigned int devNum, unsigned int *power)
{ {
NvAPI_Status ret; NvAPI_Status ret;
@ -456,6 +457,10 @@ int wrap_nvapi_init()
return -1; return -1;
} }
for (int i = 0; i < 8; i++) {
// to fix
nvapi_dev_map[i] = i;
}
#if 0 #if 0
NvAPI_ShortString ver; NvAPI_ShortString ver;
NvAPI_GetInterfaceVersionString(ver); NvAPI_GetInterfaceVersionString(ver);
@ -479,7 +484,7 @@ int wrap_nvapi_init()
// assume 2500 rpm as default, auto-updated if more // assume 2500 rpm as default, auto-updated if more
static unsigned int fan_speed_max = 2500; static unsigned int fan_speed_max = 2500;
unsigned int gpu_fanpercent(struct cgpu_info *gpu) int gpu_fanpercent(struct cgpu_info *gpu)
{ {
unsigned int pct = 0; unsigned int pct = 0;
if (hnvml) { if (hnvml) {
@ -488,7 +493,7 @@ unsigned int gpu_fanpercent(struct cgpu_info *gpu)
#ifdef WIN32 #ifdef WIN32
else { else {
unsigned int rpm = 0; unsigned int rpm = 0;
nvapi_fanspeed(device_map[gpu->thr_id], &rpm); nvapi_fanspeed(nvapi_dev_map[gpu->thr_id], &rpm);
pct = (rpm * 100) / fan_speed_max; pct = (rpm * 100) / fan_speed_max;
if (pct > 100) { if (pct > 100) {
pct = 100; pct = 100;
@ -496,27 +501,27 @@ unsigned int gpu_fanpercent(struct cgpu_info *gpu)
} }
} }
#endif #endif
return pct; return (int) pct;
} }
double gpu_temp(struct cgpu_info *gpu) float gpu_temp(struct cgpu_info *gpu)
{ {
double tc = 0.0; float tc = 0.0;
unsigned int tmp = 0; unsigned int tmp = 0;
if (hnvml) { if (hnvml) {
wrap_nvml_get_tempC(hnvml, device_map[gpu->thr_id], &tmp); wrap_nvml_get_tempC(hnvml, device_map[gpu->thr_id], &tmp);
tc = (double) tmp; tc = (float)tmp;
} }
#ifdef WIN32 #ifdef WIN32
else { else {
nvapi_temperature(device_map[gpu->thr_id], &tmp); nvapi_temperature(nvapi_dev_map[gpu->thr_id], &tmp);
tc = (double)tmp; tc = (float)tmp;
} }
#endif #endif
return tc; return tc;
} }
unsigned int gpu_clock(struct cgpu_info *gpu) int gpu_clock(struct cgpu_info *gpu)
{ {
unsigned int freq = 0; unsigned int freq = 0;
int support = -1; int support = -1;
@ -525,37 +530,38 @@ unsigned int gpu_clock(struct cgpu_info *gpu)
} }
#ifdef WIN32 #ifdef WIN32
if (support == -1) { if (support == -1) {
nvapi_getclock(device_map[gpu->thr_id], &freq); nvapi_getclock(nvapi_dev_map[gpu->thr_id], &freq);
} }
#endif #endif
return freq; return (int) freq;
} }
unsigned int gpu_power(struct cgpu_info *gpu) int gpu_pstate(struct cgpu_info *gpu)
{ {
unsigned int mw = 0; int pstate = -1;
int support = -1; int support = -1;
if (hnvml) { if (hnvml) {
support = wrap_nvml_get_power_usage(hnvml, device_map[gpu->thr_id], &mw); support = wrap_nvml_get_pstate(hnvml, device_map[gpu->thr_id], &pstate);
} }
#ifdef WIN32 #ifdef WIN32
if (support == -1) { if (support == -1) {
unsigned int pstate = 0; unsigned int pst = 0;
nvapi_getpower(device_map[gpu->thr_id], &pstate); nvapi_getpstate(nvapi_dev_map[gpu->thr_id], &pst);
//todo : convert ? //todo : convert ?
mw = pstate; pstate = (int) pst;
} }
#endif #endif
return mw; return pstate;
} }
int gpu_pstate(struct cgpu_info *gpu) unsigned int gpu_power(struct cgpu_info *gpu)
{ {
int pstate = 0; unsigned int mw = 0;
int support = -1;
if (hnvml) { if (hnvml) {
wrap_nvml_get_pstate(hnvml, device_map[gpu->thr_id], &pstate); support = wrap_nvml_get_power_usage(hnvml, device_map[gpu->thr_id], &mw);
} }
return pstate; return mw;
} }
#if defined(__cplusplus) #if defined(__cplusplus)

6
nvml.h

@ -139,9 +139,9 @@ int wrap_nvapi_init();
#include "miner.h" #include "miner.h"
unsigned int gpu_fanpercent(struct cgpu_info *gpu); int gpu_fanpercent(struct cgpu_info *gpu);
double gpu_temp(struct cgpu_info *gpu); float gpu_temp(struct cgpu_info *gpu);
unsigned int gpu_clock(struct cgpu_info *gpu); int gpu_clock(struct cgpu_info *gpu);
unsigned int gpu_power(struct cgpu_info *gpu); unsigned int gpu_power(struct cgpu_info *gpu);
int gpu_pstate(struct cgpu_info *gpu); int gpu_pstate(struct cgpu_info *gpu);

52
stats.cpp

@ -11,21 +11,11 @@
#include "miner.h" #include "miner.h"
struct stats_data {
uint32_t tm_stat;
uint32_t hashcount;
double hashrate;
uint8_t thr_id;
uint8_t gpu_id;
uint8_t ignored;
uint8_t align; /* to keep size a multiple of 4 */
};
static std::map<uint64_t, stats_data> tlastscans; static std::map<uint64_t, stats_data> tlastscans;
static uint64_t uid = 0; static uint64_t uid = 0;
#define STATS_AVG_SAMPLES 20 #define STATS_AVG_SAMPLES 30
#define STATS_PURGE_TIMEOUT 180*60 /* 180 mn */ #define STATS_PURGE_TIMEOUT 120*60 /* 120 mn */
extern uint64_t global_hashrate; extern uint64_t global_hashrate;
extern int opt_n_threads; extern int opt_n_threads;
@ -35,12 +25,11 @@ extern int device_map[8];
/** /**
* Store speed per thread (todo: compute vardiff ?) * Store speed per thread (todo: compute vardiff ?)
*/ */
extern "C" void stats_remember_speed(int thr_id, uint32_t hashcount, double hashrate) extern "C" void stats_remember_speed(int thr_id, uint32_t hashcount, double hashrate, uint8_t found)
{ {
uint64_t thr = (0xff & thr_id); uint64_t thr = (0xff & thr_id);
uint64_t key = (thr << 56) + (uid++ % UINT_MAX); uint64_t key = (thr << 56) + (uid++ % UINT_MAX);
stats_data data; stats_data data;
// to enough hashes to give right stats // to enough hashes to give right stats
if (hashcount < 1000 || hashrate < 0.01) if (hashcount < 1000 || hashrate < 0.01)
return; return;
@ -50,12 +39,14 @@ extern "C" void stats_remember_speed(int thr_id, uint32_t hashcount, double hash
return; return;
memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(data));
data.thr_id = (uint8_t) thr; data.gpu_id = device_map[thr_id];
data.thr_id = (uint8_t)thr;
data.tm_stat = (uint32_t) time(NULL); data.tm_stat = (uint32_t) time(NULL);
data.hashcount = hashcount; data.hashcount = hashcount;
data.hashfound = found;
data.hashrate = hashrate; data.hashrate = hashrate;
data.gpu_id = device_map[thr_id]; data.difficulty = global_diff;
if (global_hashrate && uid > 10) { if (opt_n_threads == 1 && global_hashrate && uid > 10) {
// prevent stats on too high vardiff (erroneous rates) // prevent stats on too high vardiff (erroneous rates)
double ratio = (hashrate / (1.0 * global_hashrate)); double ratio = (hashrate / (1.0 * global_hashrate));
if (ratio < 0.4 || ratio > 1.6) if (ratio < 0.4 || ratio > 1.6)
@ -68,7 +59,7 @@ extern "C" void stats_remember_speed(int thr_id, uint32_t hashcount, double hash
* Get the computed average speed * Get the computed average speed
* @param thr_id int (-1 for all threads) * @param thr_id int (-1 for all threads)
*/ */
extern "C" double stats_get_speed(int thr_id) extern "C" double stats_get_speed(int thr_id, double def_speed)
{ {
uint64_t thr = (0xff & thr_id); uint64_t thr = (0xff & thr_id);
uint64_t keypfx = (thr << 56); uint64_t keypfx = (thr << 56);
@ -83,18 +74,43 @@ extern "C" double stats_get_speed(int thr_id)
if (i->second.hashcount > 1000) { if (i->second.hashcount > 1000) {
speed += i->second.hashrate; speed += i->second.hashrate;
records++; records++;
// applog(LOG_BLUE, "%d %x %.1f", thr_id, i->second.thr_id, i->second.hashrate);
} }
} }
++i; ++i;
} }
if (records) if (records)
speed /= (double)(records); speed /= (double)(records);
else
speed = def_speed;
if (thr_id == -1) if (thr_id == -1)
speed *= (double)(opt_n_threads); speed *= (double)(opt_n_threads);
return speed; return speed;
} }
extern "C" int stats_get_history(int thr_id, struct stats_data *data, int max_records)
{
uint64_t thr = (0xff & thr_id);
uint64_t keypfx = (thr << 56);
uint64_t keymsk = (0xffULL << 56);
double speed = 0.0;
int records = 0;
std::map<uint64_t, stats_data>::reverse_iterator i = tlastscans.rbegin();
while (i != tlastscans.rend() && records < max_records) {
if (!i->second.ignored)
if (thr_id == -1 || (keymsk & i->first) == keypfx) {
memcpy(&data[records], &(i->second), sizeof(struct stats_data));
records++;
}
++i;
}
return records;
}
/** /**
* Remove old entries to reduce memory usage * Remove old entries to reduce memory usage
*/ */

3
util.cpp

@ -1197,6 +1197,9 @@ static bool stratum_set_difficulty(struct stratum_ctx *sctx, json_t *params)
sctx->next_diff = diff; sctx->next_diff = diff;
pthread_mutex_unlock(&sctx->work_lock); pthread_mutex_unlock(&sctx->work_lock);
/* store for api stats */
global_diff = diff;
applog(LOG_WARNING, "Stratum difficulty set to %g", diff); applog(LOG_WARNING, "Stratum difficulty set to %g", diff);
return true; return true;

Loading…
Cancel
Save