Merge branch '1.7.0_beta1'

This commit is contained in:
Ben Gräf 2018-08-17 21:26:34 +02:00
commit d38c4968f1
27 changed files with 638 additions and 194 deletions

View file

@ -1,3 +1,13 @@
# 1.7.0
- First official Release of XMRigCC-amd #33 #3
- Full integration of xmrigCC-amd into XMRigCCServer/Dashboard with GPUInfo / remote logging
- Config property to enable/disable config upload on startup (--cc-upload-config-on-startup) #80
- Refactoring of remote logging feature: #143
- Only deltas will be send to the XMRigCCServer
- Fetching miner log on dashboard upon need
- Maximum lines of log history kept per miner can be configured on XMRigCCServer
- Fix correct hugepages status on Dashboard
- Fix cpu affinity for single thread usage
# 1.6.5 # 1.6.5
- Hashrate improve -> add autodetection mode for cpu-affinity - Hashrate improve -> add autodetection mode for cpu-affinity
- Hashrate improve, more stable hashrates -> refactor memory allocation - Hashrate improve, more stable hashrates -> refactor memory allocation

View file

@ -211,7 +211,8 @@ endif()
if (WITH_CC_SERVER OR WITH_CC_CLIENT) if (WITH_CC_SERVER OR WITH_CC_CLIENT)
set(SOURCES_CC_COMMON set(SOURCES_CC_COMMON
src/cc/ControlCommand.cpp src/cc/ControlCommand.cpp
src/cc/ClientStatus.cpp) src/cc/ClientStatus.cpp
src/cc/GPUInfo.cpp)
else() else()
add_definitions(/DXMRIG_NO_CC) add_definitions(/DXMRIG_NO_CC)
endif() endif()

View file

@ -1,7 +1,7 @@
FROM ubuntu:latest FROM ubuntu:latest
RUN apt-get update && \ RUN apt-get update && \
apt install software-properties-common git build-essential libbz2-dev cmake libuv1-dev libssl-dev wget gcc g++ -y && \ apt install git build-essential libbz2-dev cmake libuv1-dev libssl-dev wget gcc g++ -y && \
apt clean && \ apt clean && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*

View file

@ -105,6 +105,7 @@ xmrigCCServer --cc-port=3344 --cc-user=admin --cc-pass=pass --cc-access-token=SE
--cc-key-file=FILE when tls is turned on, use this to point to the right key file (default: server.key) --cc-key-file=FILE when tls is turned on, use this to point to the right key file (default: server.key)
--cc-client-config-folder=FOLDER Folder contains the client config files --cc-client-config-folder=FOLDER Folder contains the client config files
--cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/' --cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/'
--cc-client-log-lines-history=N maximum lines of log history kept per miner (default: 100)
--no-color disable colored output --no-color disable colored output
-S, --syslog use system log for output messages -S, --syslog use system log for output messages
-B, --background run the miner in the background -B, --background run the miner in the background
@ -157,7 +158,7 @@ xmrigDaemon -o pool.minemonero.pro:5555 -u YOUR_WALLET -p x -k --cc-url=IP_OF_CC
--cc-worker-id=ID custom worker-id for CC Server --cc-worker-id=ID custom worker-id for CC Server
--cc-update-interval-s=N status update interval in seconds (default: 10 min: 1) --cc-update-interval-s=N status update interval in seconds (default: 10 min: 1)
--cc-use-remote-logging enable remote logging on CC Server --cc-use-remote-logging enable remote logging on CC Server
--cc-remote-logging-max-rows=N maximum last n-log rows to send CC Server --cc-upload-config-on-startup upload current miner config to CC Server on startup
--no-color disable colored output --no-color disable colored output
-S, --syslog use system log for output messages -S, --syslog use system log for output messages
-B, --background run the miner in the background -B, --background run the miner in the background

View file

@ -1,5 +1,5 @@
# version format # version format
version: 1.6.{build} version: 1.7.{build}
# build only tags # build only tags
skip_non_tags: true skip_non_tags: true

View file

@ -411,15 +411,24 @@
var data = table.row( $(this).parents('tr') ).data(); var data = table.row( $(this).parents('tr') ).data();
var clientId = data['client_status']['client_id']; var clientId = data['client_status']['client_id'];
var clientIp = data['client_status']['external_ip']; var clientIp = data['client_status']['external_ip'];
var log = data['client_status']['log'];
var htmlContent = "<div class='form-group' id='viewer' data-value='" + clientId + "'>" + $.ajax({
"<label for='config'>Log of: " + clientId + " (" + clientIp + ")</label>"+ type: "GET",
"<textarea class='form-control' rows='20' id='log'>" + log + "</textarea>" + url: "/admin/getClientLog?clientId=" + clientId,
"</div>"; dataType:"json",
success: function(data) {
var htmlContent = "<div class='form-group' id='viewer' data-value='" + clientId + "'>" +
"<label for='config'>Log of: " + clientId + " (" + clientIp + ")</label>"+
"<textarea class='form-control' rows='20' id='log'>" + data.client_log + "</textarea>" +
"</div>";
$('#minerLog').find('.modal-body').html(htmlContent); $('#minerLog').find('.modal-body').html(htmlContent);
$('#minerLog').modal('show'); $('#minerLog').modal('show');
},
error: function (data) {
setError('<strong>Unable to fetch ' + clientId + ' log.</strong> - Please make sure it is enabled on the miner!');
}
});
}); });
$('#minerLogRefresh').click(function(event) { $('#minerLogRefresh').click(function(event) {
@ -429,9 +438,17 @@
var row = table.row(index); var row = table.row(index);
var data = row.data(); var data = row.data();
if (clientId === data.client_status.client_id) { $.ajax({
$('#log').val(data.client_status.log); type: "GET",
} url: "/admin/getClientLog?clientId=" + clientId,
dataType:"json",
success: function(data) {
$('#log').val(data.client_log);
},
error: function (data) {
setError('<strong>Unable to fetch ' + clientId + ' log.</strong> - Please make sure it is enabled on the miner!');
}
});
}); });
}); });
@ -573,6 +590,18 @@
tooltip += "Used Threads: " + row.client_status.current_threads; tooltip += "Used Threads: " + row.client_status.current_threads;
tooltip += (row.client_status.hash_factor > 1 ? " [" + row.client_status.hash_factor + "x multi hash mode]" :""); tooltip += (row.client_status.hash_factor > 1 ? " [" + row.client_status.hash_factor + "x multi hash mode]" :"");
tooltip += '\n'; tooltip += '\n';
if (row.client_status.gpu_info_list) {
for (var id in row.client_status.gpu_info_list) {
tooltip += "GPU #" + row.client_status.gpu_info_list[id].gpu_info.device_idx + ": ";
tooltip += row.client_status.gpu_info_list[id].gpu_info.name + ", "
tooltip += "intensity: " + row.client_status.gpu_info_list[id].gpu_info.raw_intensity + " ";
tooltip += "("+ row.client_status.gpu_info_list[id].gpu_info.work_size + "/" + row.client_status.gpu_info_list[id].gpu_info.max_work_size + "), ";
tooltip += "cu: " + row.client_status.gpu_info_list[id].gpu_info.compute_units;
tooltip += '\n';
}
}
tooltip += "Client IP: " + row.client_status.external_ip; tooltip += "Client IP: " + row.client_status.external_ip;
tooltip += '\n'; tooltip += '\n';
tooltip += "Version: " + row.client_status.version; tooltip += "Version: " + row.client_status.version;

View file

@ -90,7 +90,8 @@ App::App(int argc, char **argv) :
} }
if (m_options->ccUseRemoteLogging()) { if (m_options->ccUseRemoteLogging()) {
Log::add(new RemoteLog(m_options->ccRemoteLoggingMaxRows())); // 20 lines per second should be enough
Log::add(new RemoteLog(static_cast<size_t>(m_options->ccUpdateInterval() * 20)));
} }
# ifdef HAVE_SYSLOG_H # ifdef HAVE_SYSLOG_H

View file

@ -98,7 +98,7 @@ Options:\n"
--cc-worker-id=ID custom worker-id for CC Server\n\ --cc-worker-id=ID custom worker-id for CC Server\n\
--cc-update-interval-s=N status update interval in seconds (default: 10 min: 1)\n\ --cc-update-interval-s=N status update interval in seconds (default: 10 min: 1)\n\
--cc-use-remote-logging enable remote logging on CC Server\n\ --cc-use-remote-logging enable remote logging on CC Server\n\
--cc-remote-logging-max-rows=N maximum last n-log rows to send CC Server\n" --cc-upload-config-on-startup upload current miner config to CC Server on startup\n"
# endif # endif
# endif # endif
@ -111,6 +111,7 @@ Options:\n"
--cc-use-tls enable tls encryption for CC communication\n\ --cc-use-tls enable tls encryption for CC communication\n\
--cc-cert-file=FILE when tls is turned on, use this to point to the right cert file (default: server.pem) \n\ --cc-cert-file=FILE when tls is turned on, use this to point to the right cert file (default: server.pem) \n\
--cc-key-file=FILE when tls is turned on, use this to point to the right key file (default: server.key) \n\ --cc-key-file=FILE when tls is turned on, use this to point to the right key file (default: server.key) \n\
--cc-client-log-lines-history=N maximum lines of log history kept per miner (default: 100)\n\
--cc-client-config-folder=FOLDER Folder contains the client config files\n\ --cc-client-config-folder=FOLDER Folder contains the client config files\n\
--cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/'\n" --cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/'\n"
# endif # endif
@ -182,8 +183,9 @@ static struct option const options[] = {
{ "cc-cert-file", 1, nullptr, 4014 }, { "cc-cert-file", 1, nullptr, 4014 },
{ "cc-key-file", 1, nullptr, 4015 }, { "cc-key-file", 1, nullptr, 4015 },
{ "cc-use-tls", 0, nullptr, 4016 }, { "cc-use-tls", 0, nullptr, 4016 },
{ "cc-use-remote-logging", 0, nullptr, 4017 }, { "cc-use-remote-logging", 0, nullptr, 4017 },
{ "cc-remote-logging-max-rows", 1, nullptr, 4018 }, { "cc-client-log-lines-history", 1, nullptr, 4018 },
{ "cc-upload-config-on-startup", 0, nullptr, 4019 },
{ "daemonized", 0, nullptr, 4011 }, { "daemonized", 0, nullptr, 4011 },
{ "doublehash-thread-mask", 1, nullptr, 4013 }, { "doublehash-thread-mask", 1, nullptr, 4013 },
{ "multihash-thread-mask", 1, nullptr, 4013 }, { "multihash-thread-mask", 1, nullptr, 4013 },
@ -246,7 +248,7 @@ static struct option const cc_client_options[] = {
{ "update-interval-s", 1, nullptr, 4012 }, { "update-interval-s", 1, nullptr, 4012 },
{ "use-tls", 0, nullptr, 4016 }, { "use-tls", 0, nullptr, 4016 },
{ "use-remote-logging", 0, nullptr, 4017 }, { "use-remote-logging", 0, nullptr, 4017 },
{ "remote-logging-max-rows",1, nullptr, 4018 }, { "upload-config-on-startup", 0, nullptr, 4019 },
{ nullptr, 0, nullptr, 0 } { nullptr, 0, nullptr, 0 }
}; };
@ -260,6 +262,7 @@ static struct option const cc_server_options[] = {
{ "cert-file", 1, nullptr, 4014 }, { "cert-file", 1, nullptr, 4014 },
{ "key-file", 1, nullptr, 4015 }, { "key-file", 1, nullptr, 4015 },
{ "use-tls", 0, nullptr, 4016 }, { "use-tls", 0, nullptr, 4016 },
{ "client-log-lines-history", 1, nullptr, 4018 },
{ nullptr, 0, nullptr, 0 } { nullptr, 0, nullptr, 0 }
}; };
@ -320,7 +323,8 @@ Options::Options(int argc, char **argv) :
m_daemonized(false), m_daemonized(false),
m_ccUseTls(false), m_ccUseTls(false),
m_ccUseRemoteLogging(true), m_ccUseRemoteLogging(true),
m_configFile(Platform::defaultConfigName()), m_ccUploadConfigOnStartup(true),
m_fileName(Platform::defaultConfigName()),
m_apiToken(nullptr), m_apiToken(nullptr),
m_apiWorkerId(nullptr), m_apiWorkerId(nullptr),
m_logFile(nullptr), m_logFile(nullptr),
@ -349,12 +353,14 @@ Options::Options(int argc, char **argv) :
m_threads(0), m_threads(0),
m_ccUpdateInterval(10), m_ccUpdateInterval(10),
m_ccPort(0), m_ccPort(0),
m_ccRemoteLoggingMaxRows(25), m_ccClientLogLinesHistory(100),
m_affinity(-1L), m_affinity(-1L),
m_multiHashThreadMask(-1L) m_multiHashThreadMask(-1L)
{ {
m_pools.push_back(new Url()); m_pools.push_back(new Url());
parseConfig(Platform::defaultConfigName());
int key; int key;
while (true) { while (true) {
@ -374,10 +380,6 @@ Options::Options(int argc, char **argv) :
} }
#ifdef XMRIG_CC_SERVER #ifdef XMRIG_CC_SERVER
if (m_ccPort == 0) {
parseConfig(Platform::defaultConfigName());
}
if (m_ccPort == 0) { if (m_ccPort == 0) {
fprintf(stderr, "No CC Server Port supplied. Exiting.\n"); fprintf(stderr, "No CC Server Port supplied. Exiting.\n");
return; return;
@ -390,10 +392,6 @@ Options::Options(int argc, char **argv) :
} }
#endif #endif
if (!m_pools[0]->isValid()) {
parseConfig(Platform::defaultConfigName());
}
if (!m_pools[0]->isValid() && (!m_ccHost || m_ccPort == 0)) { if (!m_pools[0]->isValid() && (!m_ccHost || m_ccPort == 0)) {
fprintf(stderr, "Neither pool nor CCServer URL supplied. Exiting.\n"); fprintf(stderr, "Neither pool nor CCServer URL supplied. Exiting.\n");
return; return;
@ -562,7 +560,7 @@ bool Options::parseArg(int key, const char *arg)
case 4006: /* --cc-port */ case 4006: /* --cc-port */
case 4012: /* --cc-update-interval-c */ case 4012: /* --cc-update-interval-c */
return parseArg(key, strtol(arg, nullptr, 10)); return parseArg(key, strtol(arg, nullptr, 10));
case 4018: /* --cc-remote-logging-max-rows */ case 4018: /* --cc-client-log-lines-history */
return parseArg(key, strtol(arg, nullptr, 25)); return parseArg(key, strtol(arg, nullptr, 25));
case 'B': /* --background */ case 'B': /* --background */
@ -587,6 +585,9 @@ bool Options::parseArg(int key, const char *arg)
case 4017: /* --cc-use-remote-logging */ case 4017: /* --cc-use-remote-logging */
return parseBoolean(key, true); return parseBoolean(key, true);
case 4019: /* --cc-upload-config-on-startup */
return parseBoolean(key, true);
case 't': /* --threads */ case 't': /* --threads */
if (strncmp(arg, "all", 3) == 0) { if (strncmp(arg, "all", 3) == 0) {
m_threads = Cpu::threads(); m_threads = Cpu::threads();
@ -762,13 +763,8 @@ bool Options::parseArg(int key, uint64_t arg)
} }
break; break;
case 4018: /* --cc-remote-logging-max-rows */ case 4018: /* --cc-client-log-lines-history */
if (arg < 1) { m_ccClientLogLinesHistory = (int) arg;
m_ccUseRemoteLogging = false;
}
else {
m_ccRemoteLoggingMaxRows = (int) arg;
}
break; break;
default: default:
@ -828,6 +824,10 @@ bool Options::parseBoolean(int key, bool enable)
m_ccUseRemoteLogging = enable; m_ccUseRemoteLogging = enable;
break; break;
case 4019: /* --cc-upload-config-on-startup */
m_ccUploadConfigOnStartup = enable;
break;
default: default:
break; break;
} }
@ -850,7 +850,7 @@ Url *Options::parseUrl(const char *arg) const
void Options::parseConfig(const char *fileName) void Options::parseConfig(const char *fileName)
{ {
m_configFile = fileName; m_fileName = fileName;
rapidjson::Document doc; rapidjson::Document doc;
if (!getJSON(fileName, doc)) { if (!getJSON(fileName, doc)) {

View file

@ -73,7 +73,8 @@ public:
inline bool daemonized() const { return m_daemonized; } inline bool daemonized() const { return m_daemonized; }
inline bool ccUseTls() const { return m_ccUseTls; } inline bool ccUseTls() const { return m_ccUseTls; }
inline bool ccUseRemoteLogging() const { return m_ccUseRemoteLogging; } inline bool ccUseRemoteLogging() const { return m_ccUseRemoteLogging; }
inline const char *configFile() const { return m_configFile; } inline bool ccUploadConfigOnStartup() const { return m_ccUploadConfigOnStartup; }
inline const char *fileName() const { return m_fileName; }
inline const char *apiToken() const { return m_apiToken; } inline const char *apiToken() const { return m_apiToken; }
inline const char *apiWorkerId() const { return m_apiWorkerId; } inline const char *apiWorkerId() const { return m_apiWorkerId; }
inline const char *logFile() const { return m_logFile; } inline const char *logFile() const { return m_logFile; }
@ -101,7 +102,7 @@ public:
inline size_t threads() const { return m_threads; } inline size_t threads() const { return m_threads; }
inline int ccUpdateInterval() const { return m_ccUpdateInterval; } inline int ccUpdateInterval() const { return m_ccUpdateInterval; }
inline int ccPort() const { return m_ccPort; } inline int ccPort() const { return m_ccPort; }
inline size_t ccRemoteLoggingMaxRows() const { return m_ccRemoteLoggingMaxRows; } inline size_t ccClientLogLinesHistory() const { return m_ccClientLogLinesHistory; }
inline int64_t affinity() const { return m_affinity; } inline int64_t affinity() const { return m_affinity; }
inline int64_t multiHashThreadMask() const { return m_multiHashThreadMask; } inline int64_t multiHashThreadMask() const { return m_multiHashThreadMask; }
inline void setColors(bool colors) { m_colors = colors; } inline void setColors(bool colors) { m_colors = colors; }
@ -147,7 +148,8 @@ private:
bool m_daemonized; bool m_daemonized;
bool m_ccUseTls; bool m_ccUseTls;
bool m_ccUseRemoteLogging; bool m_ccUseRemoteLogging;
const char* m_configFile; bool m_ccUploadConfigOnStartup;
const char* m_fileName;
char *m_apiToken; char *m_apiToken;
char *m_apiWorkerId; char *m_apiWorkerId;
char *m_logFile; char *m_logFile;
@ -176,7 +178,7 @@ private:
size_t m_threads; size_t m_threads;
int m_ccUpdateInterval; int m_ccUpdateInterval;
int m_ccPort; int m_ccPort;
size_t m_ccRemoteLoggingMaxRows; size_t m_ccClientLogLinesHistory;
int64_t m_affinity; int64_t m_affinity;
int64_t m_multiHashThreadMask; int64_t m_multiHashThreadMask;
std::vector<Url*> m_pools; std::vector<Url*> m_pools;

View file

@ -1,10 +1,4 @@
/* XMRig /* XMRigCC
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in> * Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
@ -27,19 +21,28 @@
#include <fstream> #include <fstream>
#include <3rdparty/rapidjson/stringbuffer.h> #include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/prettywriter.h> #include <3rdparty/rapidjson/prettywriter.h>
#include <version.h>
#include <log/RemoteLog.h> #include "version.h"
#include <api/NetworkState.h> #include "api/NetworkState.h"
#include "CCClient.h" #include "CCClient.h"
#include "App.h" #include "App.h"
#include "Platform.h"
#include "Cpu.h" #include "Cpu.h"
#include "Mem.h"
#include "ControlCommand.h" #include "ControlCommand.h"
#include "api/NetworkState.h" #ifdef TYPE_AMD_GPU
#include "common/log/Log.h"
#include "common/log/RemoteLog.h"
#include "common/Platform.h"
#include "core/Config.h"
#else
#include "Mem.h"
#include "log/Log.h" #include "log/Log.h"
#include "log/RemoteLog.h"
#include "Platform.h"
#include "api/NetworkState.h"
#endif
#include "workers/Workers.h" #include "workers/Workers.h"
#include "workers/Hashrate.h" #include "workers/Hashrate.h"
@ -55,8 +58,12 @@
CCClient* CCClient::m_self = nullptr; CCClient* CCClient::m_self = nullptr;
uv_mutex_t CCClient::m_mutex; uv_mutex_t CCClient::m_mutex;
CCClient::CCClient(Options* options, uv_async_t* async) #ifdef TYPE_AMD_GPU
: m_options(options), CCClient::CCClient(xmrig::Config* config, uv_async_t* async)
#else
CCClient::CCClient(Options* config, uv_async_t* async)
#endif
: m_config(config),
m_async(async) m_async(async)
{ {
uv_mutex_init(&m_mutex); uv_mutex_init(&m_mutex);
@ -64,8 +71,8 @@ CCClient::CCClient(Options* options, uv_async_t* async)
m_self = this; m_self = this;
std::string clientId; std::string clientId;
if (m_options->ccWorkerId()) { if (config->ccWorkerId()) {
clientId = m_options->ccWorkerId(); clientId =m_self->m_config->ccWorkerId();
} else { } else {
char hostname[128]; char hostname[128];
memset(hostname, 0, sizeof(hostname)); memset(hostname, 0, sizeof(hostname));
@ -74,27 +81,28 @@ CCClient::CCClient(Options* options, uv_async_t* async)
} }
m_clientStatus.setClientId(clientId); m_clientStatus.setClientId(clientId);
if (m_options->algoName() != nullptr) {
m_clientStatus.setCurrentAlgoName(m_options->algoName());
}
m_clientStatus.setHashFactor(Mem::hashFactor());
m_clientStatus.setVersion(Version::string()); m_clientStatus.setVersion(Version::string());
m_clientStatus.setCpuBrand(Cpu::brand()); m_clientStatus.setCpuBrand(Cpu::brand());
m_clientStatus.setCpuAES(Cpu::hasAES()); m_clientStatus.setCpuAES(Cpu::hasAES());
m_clientStatus.setCpuSockets(Cpu::sockets()); m_clientStatus.setCpuSockets(static_cast<int>(Cpu::sockets()));
m_clientStatus.setCpuCores(Cpu::cores()); m_clientStatus.setCpuCores(static_cast<int>(Cpu::cores()));
m_clientStatus.setCpuThreads(Cpu::threads()); m_clientStatus.setCpuThreads(static_cast<int>(Cpu::threads()));
m_clientStatus.setCpuX64(Cpu::isX64()); m_clientStatus.setCpuX64(Cpu::isX64());
m_clientStatus.setCpuL2(Cpu::l2()); m_clientStatus.setCpuL2(static_cast<int>(Cpu::l2()));
m_clientStatus.setCpuL3(Cpu::l3()); m_clientStatus.setCpuL3(static_cast<int>(Cpu::l3()));
m_clientStatus.setCurrentThreads(m_options->threads());
#ifdef TYPE_AMD_GPU
m_clientStatus.setCurrentThreads(static_cast<int>(config->threads().size()));
m_clientStatus.setCurrentAlgoName(config->algorithm().name());
#else
m_clientStatus.setCurrentThreads(static_cast<int>(config->threads()));
m_clientStatus.setCurrentAlgoName(config->algoName());
#endif
m_startTime = std::chrono::system_clock::now(); m_startTime = std::chrono::system_clock::now();
if (m_options->ccToken() != nullptr) { if (config->ccToken() != nullptr) {
m_authorization = std::string("Bearer ") + m_self->m_options->ccToken(); m_authorization = std::string("Bearer ") + m_self->m_config->ccToken();
} }
uv_thread_create(&m_thread, CCClient::onThreadStarted, this); uv_thread_create(&m_thread, CCClient::onThreadStarted, this);
@ -133,16 +141,54 @@ void CCClient::updateNetworkState(const NetworkState& network)
m_self->m_clientStatus.setHashesTotal(network.total); m_self->m_clientStatus.setHashesTotal(network.total);
m_self->m_clientStatus.setAvgTime(network.avgTime()); m_self->m_clientStatus.setAvgTime(network.avgTime());
#ifdef TYPE_AMD_GPU
m_self->m_clientStatus.setHashFactor(0);
m_self->m_clientStatus.setHugepagesEnabled(false);
m_self->m_clientStatus.setHugepages(false);
m_self->m_clientStatus.setTotalPages(0);
m_self->m_clientStatus.setTotalHugepages(0);
m_self->m_clientStatus.setCurrentPowVariantName(xmrig::Algorithm::getVariantName(network.powVariant));
#else
m_self->m_clientStatus.setHashFactor(Mem::hashFactor());
m_self->m_clientStatus.setHugepagesEnabled(Mem::isHugepagesEnabled()); m_self->m_clientStatus.setHugepagesEnabled(Mem::isHugepagesEnabled());
m_self->m_clientStatus.setHugepages(Mem::isHugepagesAvailable()); m_self->m_clientStatus.setHugepages(Mem::isHugepagesAvailable());
m_self->m_clientStatus.setTotalPages(Mem::getTotalPages()); m_self->m_clientStatus.setTotalPages(Mem::getTotalPages());
m_self->m_clientStatus.setTotalHugepages(Mem::getTotalHugepages()); m_self->m_clientStatus.setTotalHugepages(Mem::getTotalHugepages());
m_self->m_clientStatus.setCurrentPowVariantName(getPowVariantName(network.powVariant)); m_self->m_clientStatus.setCurrentPowVariantName(getPowVariantName(network.powVariant));
#endif
uv_mutex_unlock(&m_mutex); uv_mutex_unlock(&m_mutex);
} }
} }
#ifdef TYPE_AMD_GPU
void CCClient::updateGpuInfo(const std::vector<GpuContext>& gpuContext)
{
if (m_self) {
uv_mutex_lock(&m_mutex);
m_self->m_clientStatus.clearGPUInfoList();
for (auto gpu : gpuContext) {
GPUInfo gpuInfo;
gpuInfo.setName(gpu.name);
gpuInfo.setCompMode(gpu.compMode);
gpuInfo.setComputeUnits(gpu.computeUnits);
gpuInfo.setDeviceIdx(gpu.deviceIdx);
gpuInfo.setFreeMem(gpu.freeMem);
gpuInfo.setWorkSize(gpu.workSize);
gpuInfo.setMaxWorkSize(gpu.maximumWorkSize);
gpuInfo.setMemChunk(gpu.memChunk);
gpuInfo.setRawIntensity(gpu.rawIntensity);
m_self->m_clientStatus.addGPUInfo(gpuInfo);
}
uv_mutex_unlock(&m_mutex);
}
}
#endif
void CCClient::publishClientStatusReport() void CCClient::publishClientStatusReport()
{ {
std::string requestUrl = "/client/setClientStatus?clientId=" + m_self->m_clientStatus.getClientId(); std::string requestUrl = "/client/setClientStatus?clientId=" + m_self->m_clientStatus.getClientId();
@ -151,10 +197,10 @@ void CCClient::publishClientStatusReport()
auto res = performRequest(requestUrl, requestBuffer, "POST"); auto res = performRequest(requestUrl, requestBuffer, "POST");
if (!res) { if (!res) {
LOG_ERR("[CC-Client] error: unable to performRequest POST -> http://%s:%d%s", LOG_ERR("[CC-Client] error: unable to performRequest POST -> http://%s:%d%s",
m_self->m_options->ccHost(), m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_config->ccHost(), m_self->m_config->ccPort(), requestUrl.c_str());
} else if (res->status != 200) { } else if (res->status != 200) {
LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_options->ccHost(), LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status,m_self->m_config->ccHost(),
m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_config->ccPort(), requestUrl.c_str());
} else { } else {
ControlCommand controlCommand; ControlCommand controlCommand;
if (controlCommand.parseFromJsonString(res->body)) { if (controlCommand.parseFromJsonString(res->body)) {
@ -194,14 +240,14 @@ void CCClient::updateConfig()
auto res = performRequest(requestUrl, requestBuffer, "GET"); auto res = performRequest(requestUrl, requestBuffer, "GET");
if (!res) { if (!res) {
LOG_ERR("[CC-Client] error: unable to performRequest GET -> http://%s:%d%s", LOG_ERR("[CC-Client] error: unable to performRequest GET -> http://%s:%d%s",
m_self->m_options->ccHost(), m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_config->ccHost(), m_self->m_config->ccPort(), requestUrl.c_str());
} else if (res->status != 200) { } else if (res->status != 200) {
LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_options->ccHost(), LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_config->ccHost(),
m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_config->ccPort(), requestUrl.c_str());
} else { } else {
rapidjson::Document document; rapidjson::Document document;
if (!document.Parse(res->body.c_str()).HasParseError()) { if (!document.Parse(res->body.c_str()).HasParseError()) {
std::ofstream clientConfigFile(m_self->m_options->configFile()); std::ofstream clientConfigFile(m_self->m_config->fileName());
if (clientConfigFile) { if (clientConfigFile) {
rapidjson::StringBuffer buffer(0, 65536); rapidjson::StringBuffer buffer(0, 65536);
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer); rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
@ -213,7 +259,7 @@ void CCClient::updateConfig()
LOG_WARN("[CC-Client] Config updated. -> trigger restart"); LOG_WARN("[CC-Client] Config updated. -> trigger restart");
} else { } else {
LOG_ERR("[CC-Client] Not able to store client config to file %s.", m_self->m_options->configFile()); LOG_ERR("[CC-Client] Not able to store client config to file %s.", m_self->m_config->fileName());
} }
} else { } else {
LOG_ERR("[CC-Client] Not able to store client config. received client config is broken!"); LOG_ERR("[CC-Client] Not able to store client config. received client config is broken!");
@ -226,7 +272,7 @@ void CCClient::publishConfig()
std::string requestUrl = "/client/setClientConfig?clientId=" + m_self->m_clientStatus.getClientId(); std::string requestUrl = "/client/setClientConfig?clientId=" + m_self->m_clientStatus.getClientId();
std::stringstream data; std::stringstream data;
std::ifstream clientConfig(m_self->m_options->configFile()); std::ifstream clientConfig(m_self->m_config->fileName());
if (clientConfig) { if (clientConfig) {
data << clientConfig.rdbuf(); data << clientConfig.rdbuf();
@ -246,16 +292,16 @@ void CCClient::publishConfig()
auto res = performRequest(requestUrl, buffer.GetString(), "POST"); auto res = performRequest(requestUrl, buffer.GetString(), "POST");
if (!res) { if (!res) {
LOG_ERR("[CC-Client] error: unable to performRequest POST -> http://%s:%d%s", LOG_ERR("[CC-Client] error: unable to performRequest POST -> http://%s:%d%s",
m_self->m_options->ccHost(), m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_config->ccHost(), m_self->m_config->ccPort(), requestUrl.c_str());
} else if (res->status != 200) { } else if (res->status != 200) {
LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_options->ccHost(), LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_config->ccHost(),
m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_config->ccPort(), requestUrl.c_str());
} }
} else { } else {
LOG_ERR("Not able to send config. Client config %s is broken!", m_self->m_options->configFile()); LOG_ERR("Not able to send config. Client config %s is broken!", m_self->m_config->fileName());
} }
} else { } else {
LOG_ERR("Not able to load client config %s. Please make sure it exists!", m_self->m_options->configFile()); LOG_ERR("Not able to load client config %s. Please make sure it exists!", m_self->m_config->fileName());
} }
} }
@ -266,11 +312,11 @@ std::shared_ptr<httplib::Response> CCClient::performRequest(const std::string& r
std::shared_ptr<httplib::Client> cli; std::shared_ptr<httplib::Client> cli;
# ifndef XMRIG_NO_TLS # ifndef XMRIG_NO_TLS
if (m_self->m_options->ccUseTls()) { if (m_self->m_config->ccUseTls()) {
cli = std::make_shared<httplib::SSLClient>(m_self->m_options->ccHost(), m_self->m_options->ccPort(), 10); cli = std::make_shared<httplib::SSLClient>(m_self->m_config->ccHost(), m_self->m_config->ccPort(), 10);
} else { } else {
# endif # endif
cli = std::make_shared<httplib::Client>(m_self->m_options->ccHost(), m_self->m_options->ccPort(), 10); cli = std::make_shared<httplib::Client>(m_self->m_config->ccHost(), m_self->m_config->ccPort(), 10);
# ifndef XMRIG_NO_TLS # ifndef XMRIG_NO_TLS
} }
# endif # endif
@ -317,10 +363,12 @@ void CCClient::onThreadStarted(void* handle)
uv_timer_init(&m_self->m_client_loop, &m_self->m_timer); uv_timer_init(&m_self->m_client_loop, &m_self->m_timer);
uv_timer_start(&m_self->m_timer, CCClient::onReport, uv_timer_start(&m_self->m_timer, CCClient::onReport,
static_cast<uint64_t>(m_self->m_options->ccUpdateInterval() * 1000), static_cast<uint64_t>(m_self->m_config->ccUpdateInterval() * 1000),
static_cast<uint64_t>(m_self->m_options->ccUpdateInterval() * 1000)); static_cast<uint64_t>(m_self->m_config->ccUpdateInterval() * 1000));
m_self->publishConfig(); if (m_self->m_config->ccUploadConfigOnStartup()) {
m_self->publishConfig();
}
uv_run(&m_self->m_client_loop, UV_RUN_DEFAULT); uv_run(&m_self->m_client_loop, UV_RUN_DEFAULT);
} }

View file

@ -1,10 +1,4 @@
/* XMRig /* XMRigCC
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in> * Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
@ -31,8 +25,15 @@
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
#include <3rdparty/cpp-httplib/httplib.h> #include <3rdparty/cpp-httplib/httplib.h>
#include "Options.h"
#include "ClientStatus.h" #include "ClientStatus.h"
#include "version.h"
#ifdef TYPE_AMD_GPU
#include "amd/GpuContext.h"
#include "core/Controller.h"
#else
#include "Options.h"
#endif
class Hashrate; class Hashrate;
class NetworkState; class NetworkState;
@ -40,7 +41,13 @@ class NetworkState;
class CCClient class CCClient
{ {
public: public:
CCClient(Options *options, uv_async_t* async); #ifdef TYPE_AMD_GPU
CCClient(xmrig::Config* m_config, uv_async_t* async);
static void updateGpuInfo(const std::vector<GpuContext>& network);
#else
CCClient(Options* config, uv_async_t* async);
#endif
~CCClient(); ~CCClient();
static void updateHashrate(const Hashrate *hashrate); static void updateHashrate(const Hashrate *hashrate);
@ -60,7 +67,11 @@ private:
static void onThreadStarted(void *handle); static void onThreadStarted(void *handle);
static void onReport(uv_timer_t *handle); static void onReport(uv_timer_t *handle);
const Options* m_options; #ifdef TYPE_AMD_GPU
const xmrig::Config* m_config;
#else
const Options* m_config;
#endif
static CCClient* m_self; static CCClient* m_self;
static uv_mutex_t m_mutex; static uv_mutex_t m_mutex;

View file

@ -1,13 +1,6 @@
/* XMRig /* XMRigCC
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in> * Copyright 2017- BenDr0id <ben@graef.in>
* *
*
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -27,7 +20,6 @@
#include <cstring> #include <cstring>
#include <3rdparty/rapidjson/stringbuffer.h> #include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/prettywriter.h> #include <3rdparty/rapidjson/prettywriter.h>
#include <log/Log.h>
#include "ClientStatus.h" #include "ClientStatus.h"
@ -150,6 +142,11 @@ void ClientStatus::setLog(const std::string& log)
m_log = log; m_log = log;
} }
void ClientStatus::clearLog()
{
m_log.clear();
}
bool ClientStatus::hasHugepages() const bool ClientStatus::hasHugepages() const
{ {
return m_hasHugepages; return m_hasHugepages;
@ -380,7 +377,7 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
if (document.HasMember("client_status")) if (document.HasMember("client_status"))
{ {
rapidjson::Value::ConstObject clientStatus = document["client_status"].GetObject(); const rapidjson::Value& clientStatus = document["client_status"];
if (clientStatus.HasMember("current_status")) { if (clientStatus.HasMember("current_status")) {
m_currentStatus = toStatus(clientStatus["current_status"].GetString()); m_currentStatus = toStatus(clientStatus["current_status"].GetString());
@ -486,6 +483,18 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
m_cpuL3 = clientStatus["cpu_l3"].GetInt(); m_cpuL3 = clientStatus["cpu_l3"].GetInt();
} }
if (clientStatus.HasMember("gpu_info_list") && clientStatus["gpu_info_list"].IsArray()) {
m_gpuInfoList.clear();
auto gpuInfoList = clientStatus["gpu_info_list"].GetArray();
for (rapidjson::Value::ConstValueIterator itr = gpuInfoList.Begin(); itr != gpuInfoList.End(); ++itr) {
GPUInfo gpuInfo;
gpuInfo.parseFromJson((*itr)["gpu_info"]);
m_gpuInfoList.push_back(gpuInfo);
}
}
if (clientStatus.HasMember("shares_good")) { if (clientStatus.HasMember("shares_good")) {
m_sharesGood = clientStatus["shares_good"].GetUint64(); m_sharesGood = clientStatus["shares_good"].GetUint64();
} }
@ -510,8 +519,6 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
m_lastStatusUpdate = std::chrono::system_clock::to_time_t(time_point); m_lastStatusUpdate = std::chrono::system_clock::to_time_t(time_point);
result = true; result = true;
} else {
LOG_ERR("Parse Error, JSON does not contain: control_command");
} }
return result; return result;
@ -551,6 +558,14 @@ rapidjson::Value ClientStatus::toJson(rapidjson::MemoryPoolAllocator<rapidjson::
clientStatus.AddMember("cpu_l2", m_cpuL2, allocator); clientStatus.AddMember("cpu_l2", m_cpuL2, allocator);
clientStatus.AddMember("cpu_l3", m_cpuL3, allocator); clientStatus.AddMember("cpu_l3", m_cpuL3, allocator);
rapidjson::Value gpuInfoList(rapidjson::kArrayType);
for (auto& gpuInfo : m_gpuInfoList) {
rapidjson::Value gpuInfoEntry(rapidjson::kObjectType);
gpuInfoEntry.AddMember("gpu_info", gpuInfo.toJson(allocator), allocator);
gpuInfoList.PushBack(gpuInfoEntry, allocator);
}
clientStatus.AddMember("gpu_info_list", gpuInfoList, allocator);
clientStatus.AddMember("shares_good", m_sharesGood, allocator); clientStatus.AddMember("shares_good", m_sharesGood, allocator);
clientStatus.AddMember("shares_total", m_sharesTotal, allocator); clientStatus.AddMember("shares_total", m_sharesTotal, allocator);
clientStatus.AddMember("hashes_total", m_hashesTotal, allocator); clientStatus.AddMember("hashes_total", m_hashesTotal, allocator);
@ -558,9 +573,7 @@ rapidjson::Value ClientStatus::toJson(rapidjson::MemoryPoolAllocator<rapidjson::
clientStatus.AddMember("avg_time", m_avgTime, allocator); clientStatus.AddMember("avg_time", m_avgTime, allocator);
clientStatus.AddMember("uptime", m_uptime, allocator); clientStatus.AddMember("uptime", m_uptime, allocator);
clientStatus.AddMember("last_status_update", static_cast<uint64_t >(m_lastStatusUpdate), allocator); clientStatus.AddMember("last_status_update", static_cast<uint64_t >(m_lastStatusUpdate), allocator);
clientStatus.AddMember("log", rapidjson::StringRef(m_log.c_str()), allocator); clientStatus.AddMember("log", rapidjson::StringRef(m_log.c_str()), allocator);
@ -584,3 +597,13 @@ std::string ClientStatus::toJsonString()
return strdup(buffer.GetString()); return strdup(buffer.GetString());
} }
void ClientStatus::clearGPUInfoList()
{
m_gpuInfoList.clear();
}
void ClientStatus::addGPUInfo(const GPUInfo gpuInfo)
{
m_gpuInfoList.push_back(gpuInfo);
}

View file

@ -1,10 +1,4 @@
/* XMRig /* XMRigCC
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in> * Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
@ -27,7 +21,9 @@
#include <string> #include <string>
#include <ctime> #include <ctime>
#include <list>
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include "GPUInfo.h"
class ClientStatus class ClientStatus
{ {
@ -82,7 +78,8 @@ public:
void setVersion(const std::string& version); void setVersion(const std::string& version);
std::string getLog() const; std::string getLog() const;
void setLog(const std::string& version); void setLog(const std::string& log);
void clearLog();
bool hasHugepages() const; bool hasHugepages() const;
void setHugepages(bool hasHugepages); void setHugepages(bool hasHugepages);
@ -135,6 +132,10 @@ public:
int getCpuL3() const; int getCpuL3() const;
void setCpuL3(int cpuL3); void setCpuL3(int cpuL3);
const std::list<GPUInfo> getGPUInfoList() const;
void addGPUInfo(const GPUInfo gpuInfo);
void clearGPUInfoList();
uint64_t getSharesGood() const; uint64_t getSharesGood() const;
void setSharesGood(uint64_t sharesGood); void setSharesGood(uint64_t sharesGood);
@ -156,7 +157,6 @@ public:
rapidjson::Value toJson(rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& allocator); rapidjson::Value toJson(rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& allocator);
bool parseFromJson(const rapidjson::Document& document); bool parseFromJson(const rapidjson::Document& document);
private: private:
const char* status_str[3] = { const char* status_str[3] = {
"RUNNING", "RUNNING",
@ -195,6 +195,8 @@ private:
int m_cpuL2; int m_cpuL2;
int m_cpuL3; int m_cpuL3;
std::list<GPUInfo> m_gpuInfoList;
uint64_t m_sharesGood; uint64_t m_sharesGood;
uint64_t m_sharesTotal; uint64_t m_sharesTotal;
uint64_t m_hashesTotal; uint64_t m_hashesTotal;

View file

@ -1,13 +1,6 @@
/* XMRig /* XMRigCC
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in> * Copyright 2017- BenDr0id <ben@graef.in>
* *
*
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -22,12 +15,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cstring>
#include <3rdparty/rapidjson/stringbuffer.h> #include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/prettywriter.h> #include <3rdparty/rapidjson/prettywriter.h>
#include "log/Log.h"
#include "ControlCommand.h" #include "ControlCommand.h"
#include "version.h"
#ifdef TYPE_AMD_GPU
#include "common/log/Log.h"
#else
#include "log/Log.h"
#endif
ControlCommand::ControlCommand() ControlCommand::ControlCommand()
: m_command(Command::START) : m_command(Command::START)
{ {
@ -57,7 +58,7 @@ bool ControlCommand::parseFromJson(const rapidjson::Document& document)
bool result = false; bool result = false;
if (document.HasMember("control_command")) { if (document.HasMember("control_command")) {
rapidjson::Value::ConstObject controlCommand = document["control_command"].GetObject(); const rapidjson::Value& controlCommand = document["control_command"];
if (controlCommand.HasMember("command")) { if (controlCommand.HasMember("command")) {
m_command = toCommand(controlCommand["command"].GetString()); m_command = toCommand(controlCommand["command"].GetString());
result = true; result = true;
@ -81,7 +82,7 @@ rapidjson::Value ControlCommand::toJson(rapidjson::MemoryPoolAllocator<rapidjson
return controlCommand; return controlCommand;
} }
void ControlCommand::setCommand(Command command) void ControlCommand::setCommand(const Command& command)
{ {
m_command = command; m_command = command;
} }

View file

@ -1,13 +1,6 @@
/* XMRig /* XMRigCC
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in> * Copyright 2017- BenDr0id <ben@graef.in>
* *
*
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -74,7 +67,7 @@ public:
bool parseFromJson(const rapidjson::Document& document); bool parseFromJson(const rapidjson::Document& document);
Command getCommand() const; Command getCommand() const;
void setCommand(Command command); void setCommand(const Command& command);
bool isOneTimeCommand() const; bool isOneTimeCommand() const;

187
src/cc/GPUInfo.cpp Normal file
View file

@ -0,0 +1,187 @@
/* XMRigCC
* Copyright 2018- BenDr0id <ben@graef.in>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GPUInfo.h"
GPUInfo::GPUInfo()
: m_deviceIdx(0),
m_rawIntensity(0),
m_workSize(0),
m_maxWorkSize(0),
m_freeMem(0),
m_memChunk(0),
m_compMode(0),
m_computeUnits(0)
{
}
GPUInfo::~GPUInfo()
{
}
rapidjson::Value GPUInfo::toJson(rapidjson::MemoryPoolAllocator <rapidjson::CrtAllocator>& allocator)
{
rapidjson::Value gpuInfo(rapidjson::kObjectType);
gpuInfo.AddMember("name", rapidjson::StringRef(m_name.c_str()), allocator);
gpuInfo.AddMember("device_idx", m_deviceIdx, allocator);
gpuInfo.AddMember("raw_intensity", m_rawIntensity, allocator);
gpuInfo.AddMember("work_size", m_workSize, allocator);
gpuInfo.AddMember("max_work_size", m_maxWorkSize, allocator);
gpuInfo.AddMember("free_mem", m_freeMem, allocator);
gpuInfo.AddMember("mem_chunk", m_memChunk, allocator);
gpuInfo.AddMember("comp_mode", m_memChunk, allocator);
gpuInfo.AddMember("compute_units", m_memChunk, allocator);
return gpuInfo;
}
bool GPUInfo::parseFromJson(const rapidjson::Value& gpuInfo)
{
bool result = false;
if (gpuInfo.HasMember("name")) {
m_name = gpuInfo["name"].GetString();
result = true;
}
if (gpuInfo.HasMember("device_idx")) {
m_deviceIdx = static_cast<size_t>(gpuInfo["device_idx"].GetInt());
}
if (gpuInfo.HasMember("raw_intensity")) {
m_rawIntensity = static_cast<size_t>(gpuInfo["raw_intensity"].GetInt());
}
if (gpuInfo.HasMember("work_size")) {
m_workSize = static_cast<size_t>(gpuInfo["work_size"].GetInt());
}
if (gpuInfo.HasMember("max_work_size")) {
m_maxWorkSize = static_cast<size_t>(gpuInfo["max_work_size"].GetInt());
}
if (gpuInfo.HasMember("free_mem")) {
m_freeMem = static_cast<size_t>(gpuInfo["free_mem"].GetInt());
}
if (gpuInfo.HasMember("mem_chunk")) {
m_memChunk = gpuInfo["mem_chunk"].GetInt();
}
if (gpuInfo.HasMember("comp_mode")) {
m_compMode = gpuInfo["comp_mode"].GetInt();
}
if (gpuInfo.HasMember("compute_units")) {
m_computeUnits = gpuInfo["compute_units"].GetInt();
}
return result;
}
size_t GPUInfo::getDeviceIdx() const
{
return m_deviceIdx;
}
void GPUInfo::setDeviceIdx(size_t deviceIdx)
{
m_deviceIdx = deviceIdx;
}
size_t GPUInfo::getRawIntensity() const
{
return m_rawIntensity;
}
void GPUInfo::setRawIntensity(size_t rawIntensity)
{
m_rawIntensity = rawIntensity;
}
size_t GPUInfo::getWorkSize() const
{
return m_workSize;
}
void GPUInfo::setWorkSize(size_t workSize)
{
m_workSize = workSize;
}
size_t GPUInfo::getMaxWorkSize() const
{
return m_maxWorkSize;
}
void GPUInfo::setMaxWorkSize(size_t maxWorkSize)
{
m_maxWorkSize = maxWorkSize;
}
size_t GPUInfo::getFreeMem() const
{
return m_freeMem;
}
void GPUInfo::setFreeMem(size_t freeMem)
{
m_freeMem = freeMem;
}
int GPUInfo::getMemChunk() const
{
return m_memChunk;
}
void GPUInfo::setMemChunk(int memChunk)
{
m_memChunk = memChunk;
}
int GPUInfo::getCompMode() const
{
return m_compMode;
}
void GPUInfo::setCompMode(int compMode)
{
m_compMode = compMode;
}
int GPUInfo::getComputeUnits() const
{
return m_computeUnits;
}
void GPUInfo::setComputeUnits(int computeUnits)
{
m_computeUnits = computeUnits;
}
std::string GPUInfo::getName() const
{
return m_name;
}
void GPUInfo::setName(const std::string& name)
{
m_name = name;
}

75
src/cc/GPUInfo.h Normal file
View file

@ -0,0 +1,75 @@
/* XMRigCC
* Copyright 2018- BenDr0id <ben@graef.in>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_GPUINFO_H
#define XMRIG_GPUINFO_H
#include <string>
#include <3rdparty/rapidjson/document.h>
class GPUInfo
{
public:
GPUInfo();
~GPUInfo();
rapidjson::Value toJson(rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& allocator);
bool parseFromJson(const rapidjson::Value& gpuInfo);
std::string getName() const;
void setName(const std::string& name);
size_t getDeviceIdx() const;
void setDeviceIdx(size_t deviceIdx);
size_t getRawIntensity() const;
void setRawIntensity(size_t rawIntensity);
size_t getWorkSize() const;
void setWorkSize(size_t workSize);
size_t getMaxWorkSize() const;
void setMaxWorkSize(size_t maxWorkSize);
size_t getFreeMem() const;
void setFreeMem(size_t freeMem);
int getMemChunk() const;
void setMemChunk(int memChunk);
int getCompMode() const;
void setCompMode(int compMode);
int getComputeUnits() const;
void setComputeUnits(int computeUnits);
private:
size_t m_deviceIdx;
size_t m_rawIntensity;
size_t m_workSize;
size_t m_maxWorkSize;
size_t m_freeMem;
int m_memChunk;
int m_compMode;
int m_computeUnits;
std::string m_name;
};
#endif //XMRIG_GPUINFO_H

View file

@ -1,7 +0,0 @@
# XMRigCC common repository
This repository contains all common XMRigCC files.
# Used in this repos
* [xmrigCC](https://github.com/bendr0id/xmrigCC)
* [xmrigCC-nvidia](https://github.com/bendr0id/xmrigCC-nvidia)

View file

@ -40,6 +40,8 @@
uv_mutex_t Service::m_mutex; uv_mutex_t Service::m_mutex;
std::map<std::string, ControlCommand> Service::m_clientCommand; std::map<std::string, ControlCommand> Service::m_clientCommand;
std::map<std::string, ClientStatus> Service::m_clientStatus; std::map<std::string, ClientStatus> Service::m_clientStatus;
std::map<std::string, std::list<std::string>> Service::m_clientLog;
int Service::m_currentServerTime = 0; int Service::m_currentServerTime = 0;
bool Service::start() bool Service::start()
@ -55,6 +57,7 @@ void Service::release()
m_clientCommand.clear(); m_clientCommand.clear();
m_clientStatus.clear(); m_clientStatus.clear();
m_clientLog.clear();
uv_mutex_unlock(&m_mutex); uv_mutex_unlock(&m_mutex);
} }
@ -77,6 +80,8 @@ unsigned Service::handleGET(const Options* options, const std::string& url, cons
resultCode = getClientConfig(options, clientId, resp); resultCode = getClientConfig(options, clientId, resp);
} else if (url.rfind("/admin/getClientCommand", 0) == 0) { } else if (url.rfind("/admin/getClientCommand", 0) == 0) {
resultCode = getClientCommand(clientId, resp); resultCode = getClientCommand(clientId, resp);
} else if (url.rfind("/admin/getClientLog", 0) == 0) {
resultCode = getClientLog(clientId, resp);
} }
} }
else { else {
@ -100,7 +105,7 @@ unsigned Service::handlePOST(const Options* options, const std::string& url, con
url.c_str(), clientIp.c_str(), clientId.c_str(), data.length()); url.c_str(), clientIp.c_str(), clientId.c_str(), data.length());
if (url.rfind("/client/setClientStatus", 0) == 0) { if (url.rfind("/client/setClientStatus", 0) == 0) {
resultCode = setClientStatus(clientIp, clientId, data, resp); resultCode = setClientStatus(options, clientIp, clientId, data, resp);
} else if (url.rfind("/admin/setClientConfig", 0) == 0 || url.rfind("/client/setClientConfig", 0) == 0) { } else if (url.rfind("/admin/setClientConfig", 0) == 0 || url.rfind("/client/setClientConfig", 0) == 0) {
resultCode = setClientConfig(options, clientId, data, resp); resultCode = setClientConfig(options, clientId, data, resp);
} else if (url.rfind("/admin/setClientCommand", 0) == 0) { } else if (url.rfind("/admin/setClientCommand", 0) == 0) {
@ -216,7 +221,7 @@ unsigned Service::getClientStatusList(std::string& resp)
return MHD_HTTP_OK; return MHD_HTTP_OK;
} }
unsigned Service::setClientStatus(const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp) unsigned Service::setClientStatus(const Options* options, const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp)
{ {
int resultCode = MHD_HTTP_BAD_REQUEST; int resultCode = MHD_HTTP_BAD_REQUEST;
@ -228,6 +233,10 @@ unsigned Service::setClientStatus(const std::string& clientIp, const std::string
clientStatus.parseFromJson(document); clientStatus.parseFromJson(document);
clientStatus.setExternalIp(clientIp); clientStatus.setExternalIp(clientIp);
setClientLog(options->ccClientLogLinesHistory(), clientId, clientStatus.getLog());
clientStatus.clearLog();
m_clientStatus[clientId] = clientStatus; m_clientStatus[clientId] = clientStatus;
resultCode = getClientCommand(clientId, resp); resultCode = getClientCommand(clientId, resp);
@ -266,25 +275,29 @@ unsigned Service::getClientCommand(const std::string& clientId, std::string& res
return MHD_HTTP_OK; return MHD_HTTP_OK;
} }
unsigned Service::setClientCommand(const std::string& clientId, const std::string& data, std::string& resp) unsigned Service::getClientLog(const std::string& clientId, std::string& resp)
{ {
ControlCommand controlCommand; if (m_clientLog.find(clientId) != m_clientLog.end()) {
rapidjson::Document respDocument;
respDocument.SetObject();
rapidjson::Document document; auto& allocator = respDocument.GetAllocator();
if (!document.Parse(data.c_str()).HasParseError()) {
controlCommand.parseFromJson(document);
m_clientCommand[clientId] = controlCommand; std::stringstream data;
for (auto& m_row : m_clientLog[clientId]) {
data << m_row.c_str() << std::endl;
}
return MHD_HTTP_OK; std::string log = data.str();
} else { respDocument.AddMember("client_log", rapidjson::StringRef(log.c_str()), allocator);
return MHD_HTTP_BAD_REQUEST;
rapidjson::StringBuffer buffer(0, 4096);
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(10);
respDocument.Accept(writer);
resp = buffer.GetString();
} }
}
unsigned Service::resetClientStatusList(const std::string& data, std::string& resp)
{
m_clientStatus.clear();
return MHD_HTTP_OK; return MHD_HTTP_OK;
} }
@ -323,6 +336,49 @@ unsigned Service::getAdminPage(const Options* options, std::string& resp)
return MHD_HTTP_OK; return MHD_HTTP_OK;
} }
unsigned Service::setClientCommand(const std::string& clientId, const std::string& data, std::string& resp)
{
ControlCommand controlCommand;
rapidjson::Document document;
if (!document.Parse(data.c_str()).HasParseError()) {
controlCommand.parseFromJson(document);
m_clientCommand[clientId] = controlCommand;
return MHD_HTTP_OK;
} else {
return MHD_HTTP_BAD_REQUEST;
}
}
void Service::setClientLog(size_t maxRows, const std::string& clientId, const std::string& log)
{
if (m_clientLog.find(clientId) == m_clientLog.end()) {
m_clientLog[clientId] = std::list<std::string>();
}
auto* clientLog = &m_clientLog[clientId];
std::istringstream logStream(log);
std::string logLine;
while (std::getline(logStream, logLine))
{
if (clientLog->size() == maxRows) {
clientLog->pop_front();
}
clientLog->push_back(logLine);
}
}
unsigned Service::resetClientStatusList(const std::string& data, std::string& resp)
{
m_clientStatus.clear();
return MHD_HTTP_OK;
}
std::string Service::getClientConfigFileName(const Options* options, const std::string& clientId) std::string Service::getClientConfigFileName(const Options* options, const std::string& clientId)
{ {
std::string clientConfigFileName; std::string clientConfigFileName;

View file

@ -48,14 +48,17 @@ public:
private: private:
static unsigned getClientConfig(const Options* options, const std::string& clientId, std::string& resp); static unsigned getClientConfig(const Options* options, const std::string& clientId, std::string& resp);
static unsigned getClientCommand(const std::string& clientId, std::string& resp); static unsigned getClientCommand(const std::string& clientId, std::string& resp);
static unsigned getClientLog(const std::string& clientId, std::string& resp);
static unsigned getClientStatusList(std::string& resp); static unsigned getClientStatusList(std::string& resp);
static unsigned getAdminPage(const Options* options, std::string& resp); static unsigned getAdminPage(const Options* options, std::string& resp);
static unsigned setClientStatus(const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp); static unsigned setClientStatus(const Options* options, const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp);
static unsigned setClientCommand(const std::string& clientId, const std::string& data, std::string& resp); static unsigned setClientCommand(const std::string& clientId, const std::string& data, std::string& resp);
static unsigned setClientConfig(const Options* options, const std::string &clientId, const std::string &data, std::string &resp); static unsigned setClientConfig(const Options* options, const std::string &clientId, const std::string &data, std::string &resp);
static unsigned resetClientStatusList(const std::string& data, std::string& resp); static unsigned resetClientStatusList(const std::string& data, std::string& resp);
static void setClientLog(size_t maxRows, const std::string& clientId, const std::string& log);
static std::string getClientConfigFileName(const Options *options, const std::string &clientId); static std::string getClientConfigFileName(const Options *options, const std::string &clientId);
private: private:
@ -63,6 +66,7 @@ private:
static std::map<std::string, ClientStatus> m_clientStatus; static std::map<std::string, ClientStatus> m_clientStatus;
static std::map<std::string, ControlCommand> m_clientCommand; static std::map<std::string, ControlCommand> m_clientCommand;
static std::map<std::string, std::list<std::string>> m_clientLog;
static uv_mutex_t m_mutex; static uv_mutex_t m_mutex;

View file

@ -35,6 +35,6 @@
"worker-id": null, // custom worker-id for CC Server (otherwise hostname is used) "worker-id": null, // custom worker-id for CC Server (otherwise hostname is used)
"update-interval-s": 10, // status update interval in seconds (default: 10 min: 1) "update-interval-s": 10, // status update interval in seconds (default: 10 min: 1)
"use-remote-logging" : true, // enable remote logging on CC Server "use-remote-logging" : true, // enable remote logging on CC Server
"remote-logging-max-rows" : 20 // maximum last n-log rows to send CC Server "upload-config-on-startup" : true // upload current miner config to CC Server on startup
} }
} }

View file

@ -12,6 +12,7 @@
"user": "admin", // admin user for access CC Dashboard "user": "admin", // admin user for access CC Dashboard
"pass": "pass", // admin pass for access CC Dashboard "pass": "pass", // admin pass for access CC Dashboard
"client-config-folder" : null, // folder which contains the client-config files (null=current) "client-config-folder" : null, // folder which contains the client-config files (null=current)
"client-log-lines-history" : 100, // maximum lines of log history kept per miner
"custom-dashboard" : "index.html" // dashboard html file "custom-dashboard" : "index.html" // dashboard html file
} }
} }

View file

@ -5,7 +5,7 @@
"multihash-factor": 0, // number of hash blocks to process at a time (not set or 0 enables automatic selection of optimal number of hash blocks) "multihash-factor": 0, // number of hash blocks to process at a time (not set or 0 enables automatic selection of optimal number of hash blocks)
"multihash-thread-mask" : null, // for multihash-factors>0 only, limits multihash to given threads (mask), mask "0x3" means run multihash on thread 0 and 1 only (default: all threads) "multihash-thread-mask" : null, // for multihash-factors>0 only, limits multihash to given threads (mask), mask "0x3" means run multihash on thread 0 and 1 only (default: all threads)
"pow-variant" : "auto", // specificy the PoW variat to use: -> auto (default), 0 (v0), 1 (v1, aka monerov7, aeonv7), tube (ipbc), alloy, xtl (including autodetect for v5), msr, xhv, rto "pow-variant" : "auto", // specificy the PoW variat to use: -> auto (default), 0 (v0), 1 (v1, aka monerov7, aeonv7), tube (ipbc), alloy, xtl (including autodetect for v5), msr, xhv, rto
// for further help see: https://github.com/Bendr0id/xmrigCC/wiki/Coin-configurations // for further help see: https://github.com/Bendr0id/xmrigCC/wiki/Coin-configurations
"background": false, // true to run the miner in the background (Windows only, for *nix plase use screen/tmux or systemd service instead) "background": false, // true to run the miner in the background (Windows only, for *nix plase use screen/tmux or systemd service instead)
"colors": true, // false to disable colored output "colors": true, // false to disable colored output
"cpu-affinity": null, // set process affinity to CPU core(s), mask "0x3" for cores 0 and 1 "cpu-affinity": null, // set process affinity to CPU core(s), mask "0x3" for cores 0 and 1
@ -35,6 +35,6 @@
"worker-id": null, // custom worker-id for CC Server (otherwise hostname is used) "worker-id": null, // custom worker-id for CC Server (otherwise hostname is used)
"update-interval-s": 10, // status update interval in seconds (default: 10 min: 1) "update-interval-s": 10, // status update interval in seconds (default: 10 min: 1)
"use-remote-logging" : true, // enable remote logging on CC Server "use-remote-logging" : true, // enable remote logging on CC Server
"remote-logging-max-rows" : 20 // maximum last n-log rows to send CC Server "upload-config-on-startup" : true // upload current miner config to CC Server on startup
} }
} }

View file

@ -35,7 +35,6 @@
Log *Log::m_self = nullptr; Log *Log::m_self = nullptr;
Log::Log() Log::Log()
{ {
uv_mutex_init(&m_mutex); uv_mutex_init(&m_mutex);

View file

@ -23,14 +23,18 @@
RemoteLog* RemoteLog::m_self = nullptr; RemoteLog* RemoteLog::m_self = nullptr;
RemoteLog::RemoteLog(size_t maxRows) RemoteLog::RemoteLog(size_t maxRows)
: maxRows_(maxRows) : m_maxRows(maxRows)
{ {
uv_mutex_init(&m_mutex);
m_self = this; m_self = this;
} }
RemoteLog::~RemoteLog() RemoteLog::~RemoteLog()
{ {
m_self = nullptr; m_self = nullptr;
uv_mutex_destroy(&m_mutex);
} }
void RemoteLog::message(int level, const char* fmt, va_list args) void RemoteLog::message(int level, const char* fmt, va_list args)
@ -56,13 +60,17 @@ void RemoteLog::message(int level, const char* fmt, va_list args)
size = vsnprintf(buf + size, 512 - size - 1, fmt, args) + size; size = vsnprintf(buf + size, 512 - size - 1, fmt, args) + size;
buf[size] = '\n'; buf[size] = '\n';
if (rows_.size() == maxRows_) { uv_mutex_lock(&m_mutex);
rows_.pop_front();
if (m_rows.size() == m_maxRows) {
m_rows.pop_front();
} }
std::string row = std::regex_replace(std::string(buf, size+1), std::regex("\x1B\\[[0-9;]*[a-zA-Z]"), ""); std::string row = std::regex_replace(std::string(buf, size+1), std::regex("\x1B\\[[0-9;]*[a-zA-Z]"), "");
rows_.push_back(row); m_rows.push_back(row);
uv_mutex_unlock(&m_mutex);
delete[](buf); delete[](buf);
} }
@ -73,23 +81,21 @@ void RemoteLog::text(const char* fmt, va_list args)
message(0, fmt, args); message(0, fmt, args);
} }
void RemoteLog::flushRows()
{
if (m_self) {
m_self->rows_.clear();
}
}
std::string RemoteLog::getRows() std::string RemoteLog::getRows()
{ {
std::stringstream data; std::stringstream data;
uv_mutex_lock(&m_self->m_mutex);
if (m_self) { if (m_self) {
for (std::list<std::string>::iterator it = m_self->rows_.begin(); it != m_self->rows_.end(); it++) { for (auto& m_row : m_self->m_rows) {
data << it->c_str(); data << m_row.c_str();
} }
} }
m_self->m_rows.clear();
uv_mutex_unlock(&m_self->m_mutex);
return data.str(); return data.str();
} }

View file

@ -21,6 +21,7 @@
#include <list> #include <list>
#include <string> #include <string>
#include <uv.h>
#include "interfaces/ILogBackend.h" #include "interfaces/ILogBackend.h"
@ -34,15 +35,15 @@ public:
void message(int level, const char* fmt, va_list args) override; void message(int level, const char* fmt, va_list args) override;
void text(const char* fmt, va_list args) override; void text(const char* fmt, va_list args) override;
static void flushRows();
static std::string getRows(); static std::string getRows();
private: private:
static RemoteLog* m_self; static RemoteLog* m_self;
size_t maxRows_; uv_mutex_t m_mutex;
std::list<std::string> rows_; size_t m_maxRows;
std::list<std::string> m_rows;
}; };
#endif /* __REMOTELOG_H__ */ #endif /* __REMOTELOG_H__ */

View file

@ -36,14 +36,14 @@
#define APP_DESC "XMRigCC CPU miner" #define APP_DESC "XMRigCC CPU miner"
#define APP_COPYRIGHT "Copyright (C) 2017- BenDr0id" #define APP_COPYRIGHT "Copyright (C) 2017- BenDr0id"
#endif #endif
#define APP_VERSION "1.6.5 (based on XMRig)" #define APP_VERSION "1.7.0_beta1 (based on XMRig)"
#define APP_DOMAIN "" #define APP_DOMAIN ""
#define APP_SITE "https://github.com/Bendr0id/xmrigCC" #define APP_SITE "https://github.com/Bendr0id/xmrigCC"
#define APP_KIND "cpu" #define APP_KIND "cpu"
#define APP_VER_MAJOR 1 #define APP_VER_MAJOR 1
#define APP_VER_MINOR 6 #define APP_VER_MINOR 7
#define APP_VER_BUILD 5 #define APP_VER_BUILD 0
#define APP_VER_REV 0 #define APP_VER_REV 0
#ifndef NDEBUG #ifndef NDEBUG