mirror of
https://github.com/GOSTSec/ccminer
synced 2025-01-14 16:57:56 +00:00
api: add a basic stats api on port 2068
you can use PHP api-example.php as a json wrapper... to be tested on windows... Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>
This commit is contained in:
parent
e1c84da07f
commit
4958ce6007
@ -17,7 +17,7 @@ ccminer_SOURCES = elist.h miner.h compat.h \
|
||||
compat/inttypes.h compat/stdbool.h compat/unistd.h \
|
||||
compat/sys/time.h compat/getopt/getopt.h \
|
||||
cpu-miner.c util.c crc32.c hefty1.c scrypt.c \
|
||||
hashlog.cpp stats.cpp cuda.cu \
|
||||
api.c hashlog.cpp stats.cpp cuda.cu \
|
||||
heavy/heavy.cu \
|
||||
heavy/cuda_blake512.cu heavy/cuda_blake512.h \
|
||||
heavy/cuda_combine.cu heavy/cuda_combine.h \
|
||||
|
114
api-example.php
Normal file
114
api-example.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* Sample Request API to ccminer
|
||||
*/
|
||||
defined('API_PORT') || define('API_PORT', 4068);
|
||||
|
||||
function getsock($port)
|
||||
{
|
||||
$socket = null;
|
||||
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if ($socket === false || $socket === null) {
|
||||
$error = socket_strerror(socket_last_error());
|
||||
$msg = "socket create($port) failed";
|
||||
echo "ERR: $msg '$error'\n";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$res = socket_connect($socket, '127.0.0.1', $port);
|
||||
if ($res === false) {
|
||||
$error = socket_strerror(socket_last_error());
|
||||
$msg = "socket connect($port) failed";
|
||||
echo "ERR: $msg '$error'\n";
|
||||
socket_close($socket);
|
||||
return NULL;
|
||||
}
|
||||
return $socket;
|
||||
}
|
||||
|
||||
function readsockline($socket)
|
||||
{
|
||||
$line = '';
|
||||
while (true) {
|
||||
$byte = socket_read($socket, 1);
|
||||
if ($byte === false || $byte === '')
|
||||
break;
|
||||
if ($byte === "\0")
|
||||
break;
|
||||
$line .= $byte;
|
||||
}
|
||||
return $line;
|
||||
}
|
||||
|
||||
|
||||
function request($cmd)
|
||||
{
|
||||
$socket = getsock(API_PORT);
|
||||
if ($socket == null)
|
||||
return NULL;
|
||||
|
||||
socket_write($socket, $cmd, strlen($cmd));
|
||||
$line = readsockline($socket);
|
||||
socket_close($socket);
|
||||
|
||||
if (strlen($line) == 0) {
|
||||
echo "WARN: '$cmd' returned nothing\n";
|
||||
return $line;
|
||||
}
|
||||
|
||||
echo "$cmd returned '$line'\n";
|
||||
|
||||
$data = array();
|
||||
|
||||
$objs = explode('|', $line);
|
||||
foreach ($objs as $obj)
|
||||
{
|
||||
if (strlen($obj) > 0)
|
||||
{
|
||||
$items = explode(';', $obj);
|
||||
$item = $items[0];
|
||||
$id = explode('=', $items[0], 2);
|
||||
if (count($id) == 1)
|
||||
$name = $id[0];
|
||||
else
|
||||
$name = $id[0].$id[1];
|
||||
|
||||
if (strlen($name) == 0)
|
||||
$name = 'null';
|
||||
|
||||
if (isset($data[$name])) {
|
||||
$num = 1;
|
||||
while (isset($data[$name.$num]))
|
||||
$num++;
|
||||
$name .= $num;
|
||||
}
|
||||
|
||||
$counter = 0;
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$id = explode('=', $item, 2);
|
||||
if (count($id) == 2)
|
||||
$data[$name][$id[0]] = $id[1];
|
||||
else
|
||||
$data[$name][$counter] = $id[0];
|
||||
|
||||
$counter++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ($cmd == 'summary')
|
||||
return array_pop($data);
|
||||
else
|
||||
return $data;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
$summary = request('summary');
|
||||
$stats = request('stats');
|
||||
ob_end_clean();
|
||||
//echo ob_get_clean()."\n";
|
||||
|
||||
header("Content-Type: application/json");
|
||||
echo json_encode(compact('summary', 'stats'))."\n";
|
||||
?>
|
479
api.c
Normal file
479
api.c
Normal file
@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright 2014 ccminer team
|
||||
*
|
||||
* Implementation by tpruvot (based on cgminer)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#define APIVERSION "1.0"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "miner.h"
|
||||
|
||||
#ifndef WIN32
|
||||
# include <errno.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
# define SOCKETTYPE long
|
||||
# define SOCKETFAIL(a) ((a) < 0)
|
||||
# define INVSOCK -1 /* INVALID_SOCKET */
|
||||
# define INVINETADDR -1 /* INADDR_NONE */
|
||||
# define CLOSESOCKET close
|
||||
# define SOCKETINIT {}
|
||||
# define SOCKERRMSG strerror(errno)
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
# define SOCKETTYPE SOCKET
|
||||
# define SOCKETFAIL(a) ((a) == SOCKET_ERROR)
|
||||
# define INVSOCK INVALID_SOCKET
|
||||
# define INVINETADDR INADDR_NONE
|
||||
# define CLOSESOCKET closesocket
|
||||
#endif
|
||||
|
||||
#define GROUP(g) (toupper(g))
|
||||
#define PRIVGROUP GROUP('W')
|
||||
#define NOPRIVGROUP GROUP('R')
|
||||
#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP)
|
||||
#define GROUPOFFSET(g) (GROUP(g) - GROUP('A'))
|
||||
#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z'))
|
||||
#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands)
|
||||
#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL)
|
||||
struct APIGROUPS {
|
||||
// This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search
|
||||
char *commands;
|
||||
} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs)
|
||||
|
||||
struct IP4ACCESS {
|
||||
in_addr_t ip;
|
||||
in_addr_t mask;
|
||||
char group;
|
||||
};
|
||||
|
||||
static int ips = 1;
|
||||
static struct IP4ACCESS *ipaccess = NULL;
|
||||
|
||||
// Big enough for largest API request
|
||||
// though a PC with 100s of CPUs may exceed the size ...
|
||||
// Current code assumes it can socket send this size also
|
||||
#define MYBUFSIZ 16384
|
||||
|
||||
// Socket is on 127.0.0.1
|
||||
#define QUEUE 10
|
||||
|
||||
#define LOCAL_ADDR_V4 "127.0.0.1"
|
||||
static const char *localaddr = LOCAL_ADDR_V4;
|
||||
static const char *UNAVAILABLE = " - API will not be available";
|
||||
static char *buffer = NULL;
|
||||
|
||||
static int bye = 0;
|
||||
|
||||
extern int opt_intensity;
|
||||
extern int opt_n_threads;
|
||||
extern int opt_api_listen;
|
||||
extern uint64_t global_hashrate;
|
||||
extern uint32_t accepted_count;
|
||||
extern uint32_t rejected_count;
|
||||
|
||||
char *opt_api_allow = LOCAL_ADDR_V4;
|
||||
int opt_api_network = 1;
|
||||
#define gpu_threads opt_n_threads
|
||||
|
||||
extern void get_currentalgo(char* buf, int sz);
|
||||
|
||||
/***************************************************************/
|
||||
|
||||
static void gpustatus(int thr_id)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
float gt;
|
||||
int gf, gp;
|
||||
|
||||
|
||||
if (thr_id >= 0 && thr_id < gpu_threads) {
|
||||
struct cgpu_info *cgpu = &thr_info[thr_id].gpu;
|
||||
|
||||
int total_secs = 1; // todo
|
||||
cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
|
||||
|
||||
#ifdef HAVE_HWMONITORING
|
||||
// todo
|
||||
if (gpu->has_monitoring) {
|
||||
gt = gpu_temp(gpu);
|
||||
gf = gpu_fanspeed(gpu);
|
||||
gp = gpu_fanpercent(gpu);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
gt = gf = gp = 0;
|
||||
|
||||
// todo: can be 0 if set by algo (auto)
|
||||
if (opt_intensity == 0 && opt_work_size) {
|
||||
int i = 0;
|
||||
uint32_t ws = opt_work_size;
|
||||
while (ws > 1 && i++ < 32)
|
||||
ws = ws >> 1;
|
||||
cgpu->intensity = i;
|
||||
} else {
|
||||
cgpu->intensity = opt_intensity;
|
||||
}
|
||||
|
||||
// todo: per gpu
|
||||
cgpu->accepted = accepted_count;
|
||||
cgpu->rejected = rejected_count;
|
||||
|
||||
cgpu->khashes = stats_get_speed(thr_id) / 1000.0;
|
||||
|
||||
sprintf(buf, "GPU=%d;TEMP=%.1f;FAN=%d;FANP=%d;KHS=%.2f;"
|
||||
"ACC=%d;REJ=%d;HWF=%d;U=%.2f;I=%d|",
|
||||
thr_id, gt, gf, gp, cgpu->khashes,
|
||||
cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
|
||||
cgpu->utility, cgpu->intensity);
|
||||
|
||||
strcat(buffer, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static char *getsummary(char *params)
|
||||
{
|
||||
char algo[64] = "";
|
||||
get_currentalgo(algo, sizeof(algo));
|
||||
*buffer = '\0';
|
||||
sprintf(buffer, "NAME=%s;VER=%s;API=%s;"
|
||||
"ALGO=%s;KHS=%.2f|",
|
||||
PACKAGE_NAME, PACKAGE_VERSION, APIVERSION,
|
||||
algo, (double)global_hashrate / 1000.0);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char *getstats(char *params)
|
||||
{
|
||||
*buffer = '\0';
|
||||
for (int i = 0; i < gpu_threads; i++)
|
||||
gpustatus(i);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct CMDS {
|
||||
char *name;
|
||||
char *(*func)(char *);
|
||||
} cmds[] = {
|
||||
{ "summary", getsummary },
|
||||
{ "stats", getstats },
|
||||
};
|
||||
|
||||
#define CMDMAX 2
|
||||
|
||||
static void send_result(int c, char *result)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (result == NULL)
|
||||
result = "";
|
||||
|
||||
// ignore failure - it's closed immediately anyway
|
||||
n = write(c, result, strlen(result)+1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interpret [W:]IP[/Prefix][,[R|W:]IP2[/Prefix2][,...]] --api-allow option
|
||||
* special case of 0/0 allows /0 (means all IP addresses)
|
||||
*/
|
||||
#define ALLIP4 "0/0"
|
||||
/*
|
||||
* N.B. IP4 addresses are by Definition 32bit big endian on all platforms
|
||||
*/
|
||||
static void setup_ipaccess()
|
||||
{
|
||||
char *buf, *ptr, *comma, *slash, *dot;
|
||||
int ipcount, mask, octet, i;
|
||||
char group;
|
||||
|
||||
buf = malloc(strlen(opt_api_allow) + 1);
|
||||
if (unlikely(!buf))
|
||||
proper_exit(1);//, "Failed to malloc ipaccess buf");
|
||||
|
||||
strcpy(buf, opt_api_allow);
|
||||
|
||||
ipcount = 1;
|
||||
ptr = buf;
|
||||
while (*ptr) if (*(ptr++) == ',')
|
||||
ipcount++;
|
||||
|
||||
// possibly more than needed, but never less
|
||||
ipaccess = calloc(ipcount, sizeof(struct IP4ACCESS));
|
||||
if (unlikely(!ipaccess))
|
||||
proper_exit(1);//, "Failed to calloc ipaccess");
|
||||
|
||||
ips = 0;
|
||||
ptr = buf;
|
||||
while (ptr && *ptr) {
|
||||
while (*ptr == ' ' || *ptr == '\t')
|
||||
ptr++;
|
||||
|
||||
if (*ptr == ',') {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
comma = strchr(ptr, ',');
|
||||
if (comma)
|
||||
*(comma++) = '\0';
|
||||
|
||||
group = NOPRIVGROUP;
|
||||
|
||||
if (isalpha(*ptr) && *(ptr+1) == ':') {
|
||||
if (DEFINEDGROUP(*ptr))
|
||||
group = GROUP(*ptr);
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
ipaccess[ips].group = group;
|
||||
|
||||
if (strcmp(ptr, ALLIP4) == 0)
|
||||
ipaccess[ips].ip = ipaccess[ips].mask = 0;
|
||||
else
|
||||
{
|
||||
slash = strchr(ptr, '/');
|
||||
if (!slash)
|
||||
ipaccess[ips].mask = 0xffffffff;
|
||||
else {
|
||||
*(slash++) = '\0';
|
||||
mask = atoi(slash);
|
||||
if (mask < 1 || mask > 32)
|
||||
goto popipo; // skip invalid/zero
|
||||
|
||||
ipaccess[ips].mask = 0;
|
||||
while (mask-- >= 0) {
|
||||
octet = 1 << (mask % 8);
|
||||
ipaccess[ips].mask |= (octet << (24 - (8 * (mask >> 3))));
|
||||
}
|
||||
}
|
||||
|
||||
ipaccess[ips].ip = 0; // missing default to '.0'
|
||||
for (i = 0; ptr && (i < 4); i++) {
|
||||
dot = strchr(ptr, '.');
|
||||
if (dot)
|
||||
*(dot++) = '\0';
|
||||
|
||||
octet = atoi(ptr);
|
||||
if (octet < 0 || octet > 0xff)
|
||||
goto popipo; // skip invalid
|
||||
|
||||
ipaccess[ips].ip |= (octet << (24 - (i * 8)));
|
||||
|
||||
ptr = dot;
|
||||
}
|
||||
|
||||
ipaccess[ips].ip &= ipaccess[ips].mask;
|
||||
}
|
||||
|
||||
ips++;
|
||||
popipo:
|
||||
ptr = comma;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static bool check_connect(struct sockaddr_in *cli, char **connectaddr, char *group)
|
||||
{
|
||||
bool addrok = false;
|
||||
|
||||
*connectaddr = inet_ntoa(cli->sin_addr);
|
||||
|
||||
*group = NOPRIVGROUP;
|
||||
if (opt_api_allow) {
|
||||
int client_ip = htonl(cli->sin_addr.s_addr);
|
||||
for (int i = 0; i < ips; i++) {
|
||||
if ((client_ip & ipaccess[i].mask) == ipaccess[i].ip) {
|
||||
addrok = true;
|
||||
*group = ipaccess[i].group;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (opt_api_network)
|
||||
addrok = true;
|
||||
else
|
||||
addrok = (strcmp(*connectaddr, localaddr) == 0);
|
||||
|
||||
return addrok;
|
||||
}
|
||||
|
||||
static void api()
|
||||
{
|
||||
const char *addr = localaddr;
|
||||
short int port = opt_api_listen; // 4068
|
||||
char buf[BUFSIZ];
|
||||
int c, n, bound;
|
||||
char *connectaddr;
|
||||
char *binderror;
|
||||
char group;
|
||||
time_t bindstart;
|
||||
struct sockaddr_in serv;
|
||||
struct sockaddr_in cli;
|
||||
socklen_t clisiz;
|
||||
bool addrok = false;
|
||||
long long counter;
|
||||
char *result;
|
||||
char *params;
|
||||
int i;
|
||||
|
||||
SOCKETTYPE *apisock;
|
||||
if (!opt_api_listen && opt_debug) {
|
||||
applog(LOG_DEBUG, "API disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (opt_api_allow) {
|
||||
setup_ipaccess();
|
||||
if (ips == 0) {
|
||||
applog(LOG_WARNING, "API not running (no valid IPs specified)%s", UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
|
||||
apisock = calloc(1, sizeof(*apisock));
|
||||
*apisock = INVSOCK;
|
||||
|
||||
sleep(1);
|
||||
|
||||
*apisock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (*apisock == INVSOCK) {
|
||||
applog(LOG_ERR, "API initialisation failed (%s)%s", strerror(errno), UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&serv, 0, sizeof(serv));
|
||||
serv.sin_family = AF_INET;
|
||||
serv.sin_addr.s_addr = inet_addr(localaddr);
|
||||
if (serv.sin_addr.s_addr == (in_addr_t)INVINETADDR) {
|
||||
applog(LOG_ERR, "API initialisation 2 failed (%s)%s", strerror(errno), UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
serv.sin_port = htons(port);
|
||||
|
||||
#ifndef WIN32
|
||||
// On linux with SO_REUSEADDR, bind will get the port if the previous
|
||||
// socket is closed (even if it is still in TIME_WAIT) but fail if
|
||||
// another program has it open - which is what we want
|
||||
int optval = 1;
|
||||
// If it doesn't work, we don't really care - just show a debug message
|
||||
if (SOCKETFAIL(setsockopt(*apisock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval))))
|
||||
applog(LOG_DEBUG, "API setsockopt SO_REUSEADDR failed (ignored): %s", SOCKERRMSG);
|
||||
#else
|
||||
// On windows a 2nd program can bind to a port>1024 already in use unless
|
||||
// SO_EXCLUSIVEADDRUSE is used - however then the bind to a closed port
|
||||
// in TIME_WAIT will fail until the timeout - so we leave the options alone
|
||||
#endif
|
||||
|
||||
// try for 1 minute ... in case the old one hasn't completely gone yet
|
||||
bound = 0;
|
||||
bindstart = time(NULL);
|
||||
while (bound == 0) {
|
||||
if (bind(*apisock, (struct sockaddr *)(&serv), sizeof(serv)) < 0) {
|
||||
binderror = strerror(errno);
|
||||
if ((time(NULL) - bindstart) > 61)
|
||||
break;
|
||||
else {
|
||||
applog(LOG_ERR, "API bind to port %d failed - trying again in 15sec", port);
|
||||
sleep(15);
|
||||
}
|
||||
}
|
||||
else
|
||||
bound = 1;
|
||||
}
|
||||
|
||||
|
||||
if (bound == 0) {
|
||||
applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE);
|
||||
free(apisock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SOCKETFAIL(listen(*apisock, QUEUE))) {
|
||||
applog(LOG_ERR, "API initialisation 3 failed (%s)%s", strerror(errno), UNAVAILABLE);
|
||||
CLOSESOCKET(*apisock);
|
||||
free(apisock);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = malloc(MYBUFSIZ+1);
|
||||
|
||||
counter = 0;
|
||||
while (bye == 0) {
|
||||
counter++;
|
||||
|
||||
clisiz = sizeof(cli);
|
||||
if (SOCKETFAIL(c = accept(*apisock, (struct sockaddr *)(&cli), &clisiz))) {
|
||||
applog(LOG_ERR, "API failed (%s)%s", strerror(errno), UNAVAILABLE);
|
||||
CLOSESOCKET(*apisock);
|
||||
free(apisock);
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
addrok = check_connect(&cli, &connectaddr, &group);
|
||||
if (opt_protocol)
|
||||
applog(LOG_DEBUG, "API: connection from %s - %s",
|
||||
connectaddr, addrok ? "Accepted" : "Ignored");
|
||||
|
||||
if (addrok) {
|
||||
n = read(c, &buf[0], BUFSIZ-1);
|
||||
if (n < 0)
|
||||
close(c);
|
||||
else {
|
||||
buf[n] = '\0';
|
||||
params = strchr(buf, '|');
|
||||
if (params != NULL)
|
||||
*(params++) = '\0';
|
||||
|
||||
for (i = 0; i < CMDMAX; i++) {
|
||||
if (strcmp(buf, cmds[i].name) == 0) {
|
||||
result = (cmds[i].func)(params);
|
||||
send_result(c, result);
|
||||
close(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLOSESOCKET(*apisock);
|
||||
free(apisock);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void *api_thread(void *userdata)
|
||||
{
|
||||
struct thr_info *mythr = (struct thr_info*)userdata;
|
||||
|
||||
api();
|
||||
|
||||
tq_freeze(mythr->q);
|
||||
|
||||
return NULL;
|
||||
}
|
@ -240,6 +240,7 @@
|
||||
<ClCompile Include="groestlcoin.cpp" />
|
||||
<ClCompile Include="hashlog.cpp" />
|
||||
<ClCompile Include="stats.cpp" />
|
||||
<ClCompile Include="api.c" />
|
||||
<ClCompile Include="hefty1.c" />
|
||||
<ClCompile Include="myriadgroestl.cpp" />
|
||||
<ClCompile Include="scrypt.c">
|
||||
|
@ -192,6 +192,9 @@
|
||||
<ClCompile Include="stats.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="api.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="compat.h">
|
||||
|
46
cpu-miner.c
46
cpu-miner.c
@ -129,7 +129,7 @@ struct workio_cmd {
|
||||
} u;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
enum sha_algos {
|
||||
ALGO_ANIME,
|
||||
ALGO_BLAKE,
|
||||
ALGO_BLAKECOIN,
|
||||
@ -156,7 +156,7 @@ typedef enum {
|
||||
ALGO_X15,
|
||||
ALGO_X17,
|
||||
ALGO_DMD_GR,
|
||||
} sha256_algos;
|
||||
};
|
||||
|
||||
static const char *algo_names[] = {
|
||||
"anime",
|
||||
@ -205,12 +205,12 @@ int opt_timeout = 270;
|
||||
static int opt_scantime = 5;
|
||||
static json_t *opt_config;
|
||||
static const bool opt_time = true;
|
||||
static sha256_algos opt_algo = ALGO_X11;
|
||||
static enum sha_algos opt_algo = ALGO_X11;
|
||||
int opt_n_threads = 0;
|
||||
static double opt_difficulty = 1; // CH
|
||||
bool opt_trust_pool = false;
|
||||
uint16_t opt_vote = 9999;
|
||||
static int num_processors;
|
||||
int num_processors;
|
||||
int device_map[8] = {0,1,2,3,4,5,6,7}; // CB
|
||||
char *device_name[8]; // CB
|
||||
int device_sm[8];
|
||||
@ -223,22 +223,26 @@ char *opt_proxy;
|
||||
long opt_proxy_type;
|
||||
struct thr_info *thr_info;
|
||||
static int work_thr_id;
|
||||
struct thr_api *thr_api;
|
||||
int longpoll_thr_id = -1;
|
||||
int stratum_thr_id = -1;
|
||||
int api_thr_id = -1;
|
||||
bool stratum_need_reset = false;
|
||||
struct work_restart *work_restart = NULL;
|
||||
static struct stratum_ctx stratum;
|
||||
|
||||
pthread_mutex_t applog_lock;
|
||||
static pthread_mutex_t stats_lock;
|
||||
static unsigned long accepted_count = 0L;
|
||||
static unsigned long rejected_count = 0L;
|
||||
uint32_t accepted_count = 0L;
|
||||
uint32_t rejected_count = 0L;
|
||||
static double *thr_hashrates;
|
||||
uint64_t global_hashrate = 0;
|
||||
int opt_statsavg = 20;
|
||||
|
||||
int opt_intensity = 0;
|
||||
uint32_t opt_work_size = 0; /* default */
|
||||
|
||||
int opt_api_listen = 4068;
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
#include <getopt.h>
|
||||
#else
|
||||
@ -395,6 +399,11 @@ static struct work _ALIGN(64) g_work;
|
||||
static time_t g_work_time;
|
||||
static pthread_mutex_t g_work_lock;
|
||||
|
||||
void get_currentalgo(char* buf, int sz)
|
||||
{
|
||||
snprintf(buf, sz, "%s", algo_names[opt_algo]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit app
|
||||
*/
|
||||
@ -1605,7 +1614,7 @@ static void parse_arg(int key, char *arg)
|
||||
for (i = 0; i < ARRAY_SIZE(algo_names); i++) {
|
||||
if (algo_names[i] &&
|
||||
!strcmp(arg, algo_names[i])) {
|
||||
opt_algo = (sha256_algos)i;
|
||||
opt_algo = (enum sha_algos)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1634,6 +1643,7 @@ static void parse_arg(int key, char *arg)
|
||||
v = atoi(arg);
|
||||
if (v < 0 || v > 31)
|
||||
show_usage_and_exit(1);
|
||||
opt_intensity = v;
|
||||
if (v > 0) /* 0 = default */
|
||||
opt_work_size = (1 << v);
|
||||
break;
|
||||
@ -2046,10 +2056,10 @@ int main(int argc, char *argv[])
|
||||
if (!work_restart)
|
||||
return 1;
|
||||
|
||||
thr_info = (struct thr_info *)calloc(opt_n_threads + 3, sizeof(*thr));
|
||||
thr_info = (struct thr_info *)calloc(opt_n_threads + 4, sizeof(*thr));
|
||||
if (!thr_info)
|
||||
return 1;
|
||||
|
||||
|
||||
thr_hashrates = (double *) calloc(opt_n_threads, sizeof(double));
|
||||
if (!thr_hashrates)
|
||||
return 1;
|
||||
@ -2103,6 +2113,22 @@ int main(int argc, char *argv[])
|
||||
tq_push(thr_info[stratum_thr_id].q, strdup(rpc_url));
|
||||
}
|
||||
|
||||
if (opt_api_listen) {
|
||||
/* api thread */
|
||||
api_thr_id = opt_n_threads + 3;
|
||||
thr = &thr_info[api_thr_id];
|
||||
thr->id = api_thr_id;
|
||||
thr->q = tq_new();
|
||||
if (!thr->q)
|
||||
return 1;
|
||||
|
||||
/* start stratum thread */
|
||||
if (unlikely(pthread_create(&thr->pth, NULL, api_thread, thr))) {
|
||||
applog(LOG_ERR, "api thread create failed");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* start mining threads */
|
||||
for (i = 0; i < opt_n_threads; i++) {
|
||||
thr = &thr_info[i];
|
||||
|
32
miner.h
32
miner.h
@ -352,10 +352,41 @@ extern int scanhash_x17(int thr_id, uint32_t *pdata,
|
||||
const uint32_t *ptarget, uint32_t max_nonce,
|
||||
unsigned long *hashes_done);
|
||||
|
||||
/* api related */
|
||||
void *api_thread(void *userdata);
|
||||
|
||||
struct cgpu_info {
|
||||
int accepted;
|
||||
int rejected;
|
||||
int hw_errors;
|
||||
double khashes;
|
||||
double utility;
|
||||
int intensity;
|
||||
#ifdef HAVE_HWMONITORING
|
||||
bool has_monitoring;
|
||||
int gpu_engine;
|
||||
int min_engine;
|
||||
int gpu_fan;
|
||||
int min_fan;
|
||||
int gpu_memclock;
|
||||
int gpu_memdiff;
|
||||
int gpu_powertune;
|
||||
float gpu_vddc;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct thr_api {
|
||||
int id;
|
||||
pthread_t pth;
|
||||
struct thread_q *q;
|
||||
};
|
||||
/* end of api */
|
||||
|
||||
struct thr_info {
|
||||
int id;
|
||||
pthread_t pth;
|
||||
struct thread_q *q;
|
||||
struct cgpu_info gpu;
|
||||
};
|
||||
|
||||
struct work_restart {
|
||||
@ -382,6 +413,7 @@ extern pthread_mutex_t applog_lock;
|
||||
extern struct thr_info *thr_info;
|
||||
extern int longpoll_thr_id;
|
||||
extern int stratum_thr_id;
|
||||
extern int api_thr_id;
|
||||
extern struct work_restart *work_restart;
|
||||
extern bool opt_trust_pool;
|
||||
extern uint16_t opt_vote;
|
||||
|
Loading…
Reference in New Issue
Block a user