1
0
mirror of https://github.com/xmrig/xmrig.git synced 2025-12-12 09:42:50 -05:00

Compare commits

...

64 Commits

Author SHA1 Message Date
XMRig
7b44fa3737 v2.3.0 2017-08-20 10:39:19 +03:00
xmrig
f96e9d5ab7 Update README.md 2017-08-20 10:32:52 +03:00
XMRig
f041571674 Merge branch 'dev' 2017-08-20 10:24:49 +03:00
xmrig
bb4aeed874 Update README.md 2017-08-20 10:02:52 +03:00
xmrig
076a69907c Update README.md 2017-08-20 09:55:03 +03:00
xmrig
fa5e326d5e Update README.md 2017-08-20 09:48:31 +03:00
xmrig
55bfab95f9 Update CHANGELOG.md 2017-08-20 09:42:35 +03:00
xmrig
fbaae0f080 Update README.md 2017-08-18 17:11:26 +03:00
xmrig
d53a47b12f Update README.md 2017-08-18 06:47:51 +03:00
XMRig
e3e52f6d06 #62 Don't send the login to the dev pool. 2017-08-18 06:08:35 +03:00
xmrig
b5897b336a Update CHANGELOG.md 2017-08-18 04:44:02 +03:00
XMRig
60224ccd23 Fix error if stdout not available. 2017-08-17 18:54:41 +03:00
xmrig
168b1aac2f Update CHANGELOG.md 2017-08-17 18:11:03 +03:00
XMRig
fc1d6c7e84 Better fix for MSVC. 2017-08-17 07:33:21 +03:00
XMRig
e3dd4a6581 Fixed config load for MSVC. 2017-08-17 06:43:32 +03:00
XMRig
9cb7d727c2 Force close connection if IP address banned. 2017-08-16 15:14:21 +03:00
XMRig
e049b80f1a Fixed linux build. 2017-08-16 14:49:37 +03:00
XMRig
beb9af4313 Fixed, message "Huge pages support was successfully enabled, but reboot required to use it" was not shown in release builds. 2017-08-16 14:44:35 +03:00
XMRig
8bba0df054 Added option --no-huge-pages. 2017-08-16 14:21:12 +03:00
XMRig
27f02d5f9f Added option --user-agent. 2017-08-16 13:19:14 +03:00
XMRig
79ffb95f05 Added support for --cpu-priority for OS X. 2017-08-16 12:57:05 +03:00
XMRig
1b0ddae4eb Fixed: failed open default config file if path contains non English characters. 2017-08-16 12:22:35 +03:00
XMRig
ad0d876b18 Added support --cpu-priority support for Linux. 2017-08-15 09:03:10 +03:00
XMRig
2f371e884e Merge branch 'dev' of github.com:xmrig/xmrig into dev 2017-08-15 08:20:33 +03:00
XMRig
f05a328474 Added --cpu-priority option. 2017-08-15 08:19:55 +03:00
XMRig
c40f212e23 Fix Linux build. 2017-08-15 03:13:11 +03:00
XMRig
61859dfe14 Add class Platform. 2017-08-15 03:04:46 +03:00
XMRig
eb140fd30f Fix gcc warnings. 2017-08-14 09:53:48 +03:00
XMRig
a07b0e5953 Fix Visual Studio warnings. 2017-08-14 09:30:41 +03:00
XMRig
9975b4e4cd Backport unified client timer from proxy project. 2017-08-14 08:41:54 +03:00
XMRig
5ad1a48489 Merge branch 'master' into dev 2017-08-14 08:19:11 +03:00
XMRig
62681adcfb Fixed assert when try read unavailable stdin. 2017-08-05 18:45:06 +03:00
XMRig
1720d3e096 Fixed initialization, no need init logs and network if configuration not ready. 2017-08-04 21:47:43 +03:00
xmrig
92d787c817 Update CHANGELOG.md 2017-08-04 11:51:09 +03:00
XMRig
816fc3ee43 Fixed terminal issues after exit on Linux and OS X. 2017-08-04 11:10:33 +03:00
XMRig
7004a51ce6 v2.2.0 2017-08-02 20:08:41 +03:00
XMRig
3cc18d30de Merge branch 'dev' 2017-08-02 20:01:10 +03:00
xmrig
bd3665e111 Update CHANGELOG.md 2017-08-02 19:53:10 +03:00
XMRig
a680220d28 Fixed autoconf mode for AMD FX CPUs. 2017-08-02 18:59:24 +03:00
xmrig
2d1fdec618 Update CHANGELOG.md 2017-08-01 20:20:30 +03:00
XMRig
b1a2215829 Add missing port in config.json. 2017-08-01 19:34:36 +03:00
XMRig
eb5f7c6a7b #46 Simplify config parsing 2017-08-01 12:56:30 +03:00
XMRig
1bc23354d3 #46 Add support for default config. 2017-07-31 18:38:02 +03:00
XMRig
e6a72b2f78 #46 Added config file support. 2017-07-31 16:05:16 +03:00
XMRig
5bed17a8af Fix stop for FailoverStrategy. 2017-07-27 07:36:16 +03:00
XMRig
7b21749a19 Merge branch 'feature-async-console' into dev 2017-07-23 11:08:09 +03:00
XMRig
0b5587fd6a Add commands help. 2017-07-23 10:04:23 +03:00
XMRig
776f77a8d4 Added IConsoleListener 2017-07-23 09:36:30 +03:00
XMRig
583f45e2da Add Console class. 2017-07-23 08:35:26 +03:00
XMRig
9b474f239f Disable QuickEdit mode for Windows. 2017-07-23 07:38:57 +03:00
XMRig
9665ff15ae Use uv_tty for console output and remove legacy winansi. 2017-07-23 05:59:57 +03:00
xmrig
b6bf6d9bc9 Update CHANGELOG.md 2017-07-20 02:56:07 +03:00
XMRig
3d9be9484d Merge branch 'dev'
# Conflicts:
#	src/version.h
2017-07-20 00:54:03 +03:00
XMRig
35fd43a6b4 Changed donation address, new xmrig-proxy is coming soon. 2017-07-19 23:57:03 +03:00
xmrig
294453fdc1 Update CHANGELOG.md 2017-07-19 23:54:50 +03:00
XMRig
30a7f9f7f5 Backport crypto changes from Dead2 xmr-stak-cpu fork. 2017-07-19 21:02:38 +03:00
XMRig
8f38462bbe #40 Fix crash on Linux. 2017-07-19 04:28:59 +03:00
XMRig
ebf54c6d04 Fix warnings on Linux. 2017-07-18 22:38:38 +03:00
XMRig
d7659b5093 Fixed %lld and %llu related warnings. 2017-07-18 20:20:29 +03:00
XMRig
e00c568ae9 Fix OS X build. 2017-07-18 14:09:20 +03:00
XMRig
a3988374f0 Fixed graceful shutdown. 2017-07-18 05:20:36 +03:00
XMRig
9732636155 Fixed bug, login request was contain malformed JSON if username or password has some special characters for example \. 2017-07-18 01:49:04 +03:00
XMRig
986aee4297 Better support for Round Robin DNS, related https://github.com/fireice-uk/xmr-stak-cpu/pull/220 2017-07-17 23:35:36 +03:00
XMRig
66d3e96a1a Sync changes with upcoming xmrig-proxy project. 2017-07-17 21:57:03 +03:00
67 changed files with 1724 additions and 2203 deletions

View File

@@ -1,3 +1,30 @@
# v2.3.0
- Added `--cpu-priority` option (0 idle, 2 normal to 5 highest).
- Added `--user-agent` option, to set custom user-agent string for pool. For example `cpuminer-multi/0.1`.
- Added `--no-huge-pages` option, to disable huge pages support.
- [#62](https://github.com/xmrig/xmrig/issues/62) Don't send the login to the dev pool.
- Force reconnect if pool block miner IP address. helps switch to backup pool.
- Fixed: failed open default config file if path contains non English characters.
- Fixed: error occurred if try use unavailable stdin or stdout, regression since version 2.2.0.
- Fixed: message about huge pages support successfully enabled on Windows was not shown in release builds.
# v2.2.1
- Fixed [terminal issues](https://github.com/xmrig/xmrig-proxy/issues/2#issuecomment-319914085) after exit on Linux and OS X.
# v2.2.0
- [#46](https://github.com/xmrig/xmrig/issues/46) Restored config file support. Now possible use multiple config files and combine with command line options also added support for default config.
- Improved colors support on Windows, now used uv_tty, legacy code removed.
- QuickEdit Mode now disabled on Windows.
- Added interactive commands in console window:: **h**ashrate, **p**ause, **r**esume.
- Fixed autoconf mode for AMD FX CPUs.
# v2.1.0
- [#40](https://github.com/xmrig/xmrig/issues/40)
Improved miner shutdown, fixed crash on exit for Linux and OS X.
- Fixed, login request was contain malformed JSON if username or password has some special characters for example `\`.
- [#220](https://github.com/fireice-uk/xmr-stak-cpu/pull/220) Better support for Round Robin DNS, IP address now always chosen randomly instead of stuck on first one.
- Changed donation address, new [xmrig-proxy](https://github.com/xmrig/xmrig-proxy) is coming soon.
# v2.0.2 # v2.0.2
- Better deal with possible duplicate jobs from pool, show warning and ignore duplicates. - Better deal with possible duplicate jobs from pool, show warning and ignore duplicates.
- For Windows builds libuv updated to version 1.13.1 and gcc to 7.1.0. - For Windows builds libuv updated to version 1.13.1 and gcc to 7.1.0.

View File

@@ -11,8 +11,10 @@ include (CheckIncludeFile)
set(HEADERS set(HEADERS
src/3rdparty/align.h src/3rdparty/align.h
src/App.h src/App.h
src/Console.h
src/Cpu.h src/Cpu.h
src/interfaces/IClientListener.h src/interfaces/IClientListener.h
src/interfaces/IConsoleListener.h
src/interfaces/IJobResultListener.h src/interfaces/IJobResultListener.h
src/interfaces/ILogBackend.h src/interfaces/ILogBackend.h
src/interfaces/IStrategy.h src/interfaces/IStrategy.h
@@ -26,12 +28,13 @@ set(HEADERS
src/net/Job.h src/net/Job.h
src/net/JobResult.h src/net/JobResult.h
src/net/Network.h src/net/Network.h
src/net/SubmitResult.h
src/net/Url.h
src/net/strategies/DonateStrategy.h src/net/strategies/DonateStrategy.h
src/net/strategies/FailoverStrategy.h src/net/strategies/FailoverStrategy.h
src/net/strategies/SinglePoolStrategy.h src/net/strategies/SinglePoolStrategy.h
src/net/SubmitResult.h
src/net/Url.h
src/Options.h src/Options.h
src/Platform.h
src/Summary.h src/Summary.h
src/version.h src/version.h
src/workers/DoubleWorker.h src/workers/DoubleWorker.h
@@ -58,6 +61,7 @@ set(HEADERS_CRYPTO
set(SOURCES set(SOURCES
src/App.cpp src/App.cpp
src/Console.cpp
src/log/ConsoleLog.cpp src/log/ConsoleLog.cpp
src/log/FileLog.cpp src/log/FileLog.cpp
src/log/Log.cpp src/log/Log.cpp
@@ -65,11 +69,12 @@ set(SOURCES
src/net/Client.cpp src/net/Client.cpp
src/net/Job.cpp src/net/Job.cpp
src/net/Network.cpp src/net/Network.cpp
src/net/Url.cpp
src/net/strategies/DonateStrategy.cpp src/net/strategies/DonateStrategy.cpp
src/net/strategies/FailoverStrategy.cpp src/net/strategies/FailoverStrategy.cpp
src/net/strategies/SinglePoolStrategy.cpp src/net/strategies/SinglePoolStrategy.cpp
src/net/Url.cpp
src/Options.cpp src/Options.cpp
src/Platform.cpp
src/Summary.cpp src/Summary.cpp
src/workers/DoubleWorker.cpp src/workers/DoubleWorker.cpp
src/workers/Handle.cpp src/workers/Handle.cpp
@@ -94,12 +99,10 @@ set(SOURCES_CRYPTO
if (WIN32) if (WIN32)
set(SOURCES_OS set(SOURCES_OS
res/app.rc res/app.rc
src/3rdparty/winansi.cpp
src/3rdparty/winansi.h
src/App_win.cpp src/App_win.cpp
src/Cpu_win.cpp src/Cpu_win.cpp
src/Mem_win.cpp src/Mem_win.cpp
src/net/Network_win.cpp src/Platform_win.cpp
) )
add_definitions(/DWIN32) add_definitions(/DWIN32)
@@ -109,14 +112,14 @@ elseif (APPLE)
src/App_unix.cpp src/App_unix.cpp
src/Cpu_mac.cpp src/Cpu_mac.cpp
src/Mem_unix.cpp src/Mem_unix.cpp
src/net/Network_mac.cpp src/Platform_mac.cpp
) )
else() else()
set(SOURCES_OS set(SOURCES_OS
src/App_unix.cpp src/App_unix.cpp
src/Cpu_unix.cpp src/Cpu_unix.cpp
src/Mem_unix.cpp src/Mem_unix.cpp
src/net/Network_unix.cpp src/Platform_unix.cpp
) )
set(EXTRA_LIBS pthread) set(EXTRA_LIBS pthread)
@@ -145,6 +148,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
if (WIN32) if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
add_definitions(/D__STDC_FORMAT_MACROS)
else() else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
endif() endif()
@@ -157,6 +161,8 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL")
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
add_definitions(/D_CRT_NONSTDC_NO_WARNINGS)
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)

View File

@@ -2,7 +2,9 @@
XMRig is high performance Monero (XMR) CPU miner, with the official full Windows support. XMRig is high performance Monero (XMR) CPU miner, with the official full Windows support.
Originally based on cpuminer-multi with heavy optimizations/rewrites and removing a lot of legacy code, since version 1.0.0 complete rewritten from scratch on C++. Originally based on cpuminer-multi with heavy optimizations/rewrites and removing a lot of legacy code, since version 1.0.0 complete rewritten from scratch on C++.
<img src="https://i.imgur.com/OXoB10D.png" width="628" > * This is the CPU-mining version, there is also a [NVIDIA GPU version](https://github.com/xmrig/xmrig-nvidia).
<img src="http://i.imgur.com/OKZRVDh.png" width="619" >
#### Table of contents #### Table of contents
* [Features](#features) * [Features](#features)
@@ -16,9 +18,10 @@ Originally based on cpuminer-multi with heavy optimizations/rewrites and removin
* [Contacts](#contacts) * [Contacts](#contacts)
## Features ## Features
* High performance (290+ H/s on i7 6700). * High performance.
* Official Windows support. * Official Windows support.
* Small Windows executable, only 535 KB without dependencies. * Small Windows executable, without dependencies.
* x86/x64 support.
* Support for backup (failover) mining server. * Support for backup (failover) mining server.
* keepalived support. * keepalived support.
* Command line options compatible with cpuminer. * Command line options compatible with cpuminer.
@@ -30,17 +33,17 @@ Originally based on cpuminer-multi with heavy optimizations/rewrites and removin
## Download ## Download
* Binary releases: https://github.com/xmrig/xmrig/releases * Binary releases: https://github.com/xmrig/xmrig/releases
* Git tree: https://github.com/xmrig/xmrig.git * Git tree: https://github.com/xmrig/xmrig.git
* Clone with `git clone https://github.com/xmrig/xmrig.git` * Clone with `git clone https://github.com/xmrig/xmrig.git` :hammer: [Build instructions](https://github.com/xmrig/xmrig/wiki/Build).
## Usage ## Usage
### Basic example ### Basic example
``` ```
xmrig.exe -o xmr-eu.dwarfpool.com:8005 -u YOUR_WALLET -p x -k xmrig.exe -o pool.minemonero.pro:5555 -u YOUR_WALLET -p x -k
``` ```
### Failover ### Failover
``` ```
xmrig.exe -o pool.supportxmr.com:5555 -u YOUR_WALLET1 -k -o xmr-eu.dwarfpool.com:8005 -u YOUR_WALLET2 -p x -k xmrig.exe -o pool.minemonero.pro:5555 -u YOUR_WALLET1 -p x -k -o pool.supportxmr.com:5555 -u YOUR_WALLET2 -p x -k
``` ```
For failover you can add multiple pools, maximum count not limited. For failover you can add multiple pools, maximum count not limited.
@@ -56,19 +59,25 @@ For failover you can add multiple pools, maximum count not limited.
-k, --keepalive send keepalived for prevent timeout (need pool support) -k, --keepalive send keepalived for prevent timeout (need pool support)
-r, --retries=N number of times to retry before switch to backup server (default: 5) -r, --retries=N number of times to retry before switch to backup server (default: 5)
-R, --retry-pause=N time to pause between retries (default: 5) -R, --retry-pause=N time to pause between retries (default: 5)
--cpu-affinity set process affinity to cpu core(s), mask 0x3 for cores 0 and 1 --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1
--cpu-priority set process priority (0 idle, 2 normal to 5 highest)
--no-huge-pages disable huge pages support
--no-color disable colored output --no-color disable colored output
--donate-level=N donate level, default 5% (5 minutes in 100 minutes) --donate-level=N donate level, default 5% (5 minutes in 100 minutes)
--user-agent set custom user-agent string for pool
-B, --background run the miner in the background -B, --background run the miner in the background
-c, --config=FILE load a JSON-format configuration file -c, --config=FILE load a JSON-format configuration file
--max-cpu-usage=N maximum cpu usage for automatic threads mode (default 75) -l, --log-file=FILE log all output to a file
--safe safe adjust threads and av settings for current cpu --max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)
--safe safe adjust threads and av settings for current CPU
--nicehash enable nicehash support --nicehash enable nicehash support
--print-time=N print hashrate report every N seconds --print-time=N print hashrate report every N seconds
-h, --help display this help and exit -h, --help display this help and exit
-V, --version output version information and exit -V, --version output version information and exit
``` ```
Also you can use configuration via config file, default **config.json**. You can load multiple config files and combine it with command line options.
## Algorithm variations ## Algorithm variations
Since version 0.8.0. Since version 0.8.0.
* `--av=1` For CPUs with hardware AES. * `--av=1` For CPUs with hardware AES.
@@ -88,8 +97,8 @@ Since version 0.8.0.
### CPU mining performance ### CPU mining performance
* **i7-6700** - 290+ H/s (4 threads, cpu affinity 0xAA) * **Intel i7-7700** - 307 H/s (4 threads)
* **Dual E5620** - 377 H/s (12 threads, cpu affinity 0xEEEE) * **AMD Ryzen 7 1700X** - 560 H/s (8 threads)
Please note performance is highly dependent on system load. The numbers above are obtained on an idle system. Tasks heavily using a processor cache, such as video playback, can greatly degrade hashrate. Optimal number of threads depends on the size of the L3 cache of a processor, 1 thread requires 2 MB of cache. Please note performance is highly dependent on system load. The numbers above are obtained on an idle system. Tasks heavily using a processor cache, such as video playback, can greatly degrade hashrate. Optimal number of threads depends on the size of the L3 cache of a processor, 1 thread requires 2 MB of cache.

View File

@@ -56,7 +56,7 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#pragma warning(disable:4996); #pragma warning(disable:4996)
#define __GETOPT_H__ #define __GETOPT_H__

View File

@@ -5,6 +5,10 @@
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#ifdef _MSC_VER
#pragma warning(disable:4090)
#endif
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
@@ -15,8 +19,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#ifdef HAVE_UNISTD_H
#if defined(HAVE_UNISTD_H)
# include <unistd.h> # include <unistd.h>
#elif defined(_MSC_VER)
# include <io.h>
#endif #endif
#include "jansson.h" #include "jansson.h"
@@ -62,9 +69,12 @@ static int dump_to_file(const char *buffer, size_t size, void *data)
static int dump_to_fd(const char *buffer, size_t size, void *data) static int dump_to_fd(const char *buffer, size_t size, void *data)
{ {
int *dest = (int *)data; int *dest = (int *)data;
#ifdef HAVE_UNISTD_H # if defined(HAVE_UNISTD_H)
if(write(*dest, buffer, size) == (ssize_t)size) if(write(*dest, buffer, size) == (ssize_t)size)
return 0; return 0;
# elif (defined(_MSC_VER))
if (write(*dest, buffer, (unsigned int) size) == (int) size)
return 0;
# endif # endif
return -1; return -1;
} }

View File

@@ -5,6 +5,10 @@
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#ifdef _MSC_VER
#pragma warning(disable:4334)
#endif
#if HAVE_CONFIG_H #if HAVE_CONFIG_H
#include <jansson_private_config.h> #include <jansson_private_config.h>
#endif #endif

View File

@@ -17,8 +17,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#ifdef HAVE_UNISTD_H
#if defined(HAVE_UNISTD_H)
# include <unistd.h> # include <unistd.h>
#elif defined(_MSC_VER)
# include <io.h>
# define HAVE_UNISTD_H
# define STDIN_FILENO 0
#endif #endif
#include "jansson.h" #include "jansson.h"
@@ -1034,8 +1039,8 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
static int fd_get_func(int *fd) static int fd_get_func(int *fd)
{ {
uint8_t c;
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
uint8_t c;
if (read(*fd, &c, 1) == 1) if (read(*fd, &c, 1) == 1)
return c; return c;
#endif #endif

View File

@@ -1,392 +0,0 @@
/**
* Old Git implementation of windows terminal colors (2009)
* before use of a threaded wrapper.
*/
#undef NOGDI
#include <windows.h>
#include <wingdi.h>
#include <winreg.h>
#include <malloc.h>
#include <stdio.h>
#include <io.h>
#include "winansi.h"
/*
* Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
*/
/*
Functions to be wrapped:
*/
#undef printf
#undef fprintf
#undef fputs
#undef vfprintf
/* TODO: write */
/*
ANSI codes used by git: m, K
This file is git-specific. Therefore, this file does not attempt
to implement any codes that are not used by git.
*/
static HANDLE console;
static WORD plain_attr;
static WORD attr;
static int negative;
static void init(void)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
static int initialized = 0;
if (initialized)
return;
console = GetStdHandle(STD_OUTPUT_HANDLE);
if (console == INVALID_HANDLE_VALUE)
console = NULL;
if (!console)
return;
GetConsoleScreenBufferInfo(console, &sbi);
attr = plain_attr = sbi.wAttributes;
negative = 0;
initialized = 1;
}
static int write_console(const char *str, int len)
{
/* convert utf-8 to utf-16, write directly to console */
int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
wchar_t *wbuf = (wchar_t *)alloca(wlen * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
WriteConsoleW(console, wbuf, wlen, NULL, NULL);
/* return original (utf-8 encoded) length */
return len;
}
#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
static void set_console_attr(void)
{
WORD attributes = attr;
if (negative) {
attributes &= ~FOREGROUND_ALL;
attributes &= ~BACKGROUND_ALL;
/* This could probably use a bitmask
instead of a series of ifs */
if (attr & FOREGROUND_RED)
attributes |= BACKGROUND_RED;
if (attr & FOREGROUND_GREEN)
attributes |= BACKGROUND_GREEN;
if (attr & FOREGROUND_BLUE)
attributes |= BACKGROUND_BLUE;
if (attr & BACKGROUND_RED)
attributes |= FOREGROUND_RED;
if (attr & BACKGROUND_GREEN)
attributes |= FOREGROUND_GREEN;
if (attr & BACKGROUND_BLUE)
attributes |= FOREGROUND_BLUE;
}
SetConsoleTextAttribute(console, attributes);
}
static void erase_in_line(void)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
if (!console)
return;
GetConsoleScreenBufferInfo(console, &sbi);
FillConsoleOutputCharacterA(console, ' ',
sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
&dummy);
}
static const char *set_attr(const char *str)
{
const char *func;
size_t len = strspn(str, "0123456789;");
func = str + len;
switch (*func) {
case 'm':
do {
long val = strtol(str, (char **)&str, 10);
switch (val) {
case 0: /* reset */
attr = plain_attr;
negative = 0;
break;
case 1: /* bold */
attr |= FOREGROUND_INTENSITY;
break;
case 2: /* faint */
case 22: /* normal */
attr &= ~FOREGROUND_INTENSITY;
break;
case 3: /* italic */
/* Unsupported */
break;
case 4: /* underline */
case 21: /* double underline */
/* Wikipedia says this flag does nothing */
/* Furthermore, mingw doesn't define this flag
attr |= COMMON_LVB_UNDERSCORE; */
break;
case 24: /* no underline */
/* attr &= ~COMMON_LVB_UNDERSCORE; */
break;
case 5: /* slow blink */
case 6: /* fast blink */
/* We don't have blink, but we do have
background intensity */
attr |= BACKGROUND_INTENSITY;
break;
case 25: /* no blink */
attr &= ~BACKGROUND_INTENSITY;
break;
case 7: /* negative */
negative = 1;
break;
case 27: /* positive */
negative = 0;
break;
case 8: /* conceal */
case 28: /* reveal */
/* Unsupported */
break;
case 30: /* Black */
attr &= ~FOREGROUND_ALL;
break;
case 31: /* Red */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED;
break;
case 32: /* Green */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_GREEN;
break;
case 33: /* Yellow */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED | FOREGROUND_GREEN;
break;
case 34: /* Blue */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_BLUE;
break;
case 35: /* Magenta */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED | FOREGROUND_BLUE;
break;
case 36: /* Cyan */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
break;
case 37: /* White */
attr |= FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE;
break;
case 38: /* Unknown */
break;
case 39: /* reset */
attr &= ~FOREGROUND_ALL;
attr |= (plain_attr & FOREGROUND_ALL);
break;
case 40: /* Black */
attr &= ~BACKGROUND_ALL;
break;
case 41: /* Red */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED;
break;
case 42: /* Green */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_GREEN;
break;
case 43: /* Yellow */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED | BACKGROUND_GREEN;
break;
case 44: /* Blue */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_BLUE;
break;
case 45: /* Magenta */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED | BACKGROUND_BLUE;
break;
case 46: /* Cyan */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
break;
case 47: /* White */
attr |= BACKGROUND_RED |
BACKGROUND_GREEN |
BACKGROUND_BLUE;
break;
case 48: /* Unknown */
break;
case 49: /* reset */
attr &= ~BACKGROUND_ALL;
attr |= (plain_attr & BACKGROUND_ALL);
break;
default:
/* Unsupported code */
break;
}
str++;
} while (*(str - 1) == ';');
set_console_attr();
break;
case 'K':
erase_in_line();
break;
default:
/* Unsupported code */
break;
}
return func + 1;
}
static int ansi_emulate(const char *str, FILE *stream)
{
int rv = 0;
const char *pos = str;
fflush(stream);
while (*pos) {
pos = strstr(str, "\033[");
if (pos) {
int len = (int) (pos - str);
if (len) {
int out_len = write_console(str, len);
rv += out_len;
if (out_len < len)
return rv;
}
str = pos + 2;
rv += 2;
pos = set_attr(str);
rv += (int) (pos - str);
str = pos;
}
else {
int len = (int) strlen(str);
rv += write_console(str, len);
return rv;
}
}
return rv;
}
int winansi_fputs(const char *str, FILE *stream)
{
int rv;
if (!isatty(fileno(stream)))
return fputs(str, stream);
init();
if (!console)
return fputs(str, stream);
rv = ansi_emulate(str, stream);
if (rv >= 0)
return 0;
else
return EOF;
}
int winansi_vfprintf(FILE *stream, const char *format, va_list list)
{
int len, rv;
char small_buf[256] = { 0 };
char *buf = small_buf;
va_list cp;
if (!isatty(fileno(stream)))
goto abort;
init();
if (!console)
goto abort;
va_copy(cp, list);
len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
#ifdef WIN32
/* bug on long strings without that */
if (len == -1)
len = _vscprintf(format, cp);
#endif
va_end(cp);
if ((unsigned) len > sizeof(small_buf) - 1) {
buf = (char*)malloc(len + 1);
if (!buf)
goto abort;
len = vsnprintf(buf, len + 1, format, list);
#ifdef WIN32
if (len == -1)
len = _vscprintf(format, list);
#endif
}
rv = ansi_emulate(buf, stream);
if (buf != small_buf)
free(buf);
return rv;
abort:
rv = vfprintf(stream, format, list);
return rv;
}
int winansi_fprintf(FILE *stream, const char *format, ...)
{
va_list list;
int rv;
va_start(list, format);
rv = winansi_vfprintf(stream, format, list);
va_end(list);
return rv;
}
int winansi_printf(const char *format, ...)
{
va_list list;
int rv;
va_start(list, format);
rv = winansi_vfprintf(stdout, format, list);
va_end(list);
return rv;
}

View File

@@ -1,29 +0,0 @@
/*
* ANSI emulation wrappers
*/
#include <windows.h>
#include <stddef.h>
#include <stdio.h>
#define fileno(fd) _fileno(fd)
#ifdef __cplusplus
extern "C" {
#endif
int winansi_fputs(const char *str, FILE *stream);
int winansi_printf(const char *format, ...);
int winansi_fprintf(FILE *stream, const char *format, ...);
int winansi_vfprintf(FILE *stream, const char *format, va_list list);
#ifdef __cplusplus
}
#endif
#undef fputs
#undef fprintf
#undef vfprintf
#define fputs winansi_fputs
#define printf winansi_printf
#define fprintf winansi_fprintf
#define vfprintf winansi_vfprintf

View File

@@ -27,6 +27,7 @@
#include "App.h" #include "App.h"
#include "Console.h"
#include "Cpu.h" #include "Cpu.h"
#include "crypto/CryptoNight.h" #include "crypto/CryptoNight.h"
#include "log/ConsoleLog.h" #include "log/ConsoleLog.h"
@@ -35,6 +36,7 @@
#include "Mem.h" #include "Mem.h"
#include "net/Network.h" #include "net/Network.h"
#include "Options.h" #include "Options.h"
#include "Platform.h"
#include "Summary.h" #include "Summary.h"
#include "version.h" #include "version.h"
#include "workers/Workers.h" #include "workers/Workers.h"
@@ -50,6 +52,7 @@ App *App::m_self = nullptr;
App::App(int argc, char **argv) : App::App(int argc, char **argv) :
m_console(nullptr),
m_network(nullptr), m_network(nullptr),
m_options(nullptr) m_options(nullptr)
{ {
@@ -57,11 +60,15 @@ App::App(int argc, char **argv) :
Cpu::init(); Cpu::init();
m_options = Options::parse(argc, argv); m_options = Options::parse(argc, argv);
if (!m_options) {
return;
}
Log::init(); Log::init();
if (!m_options->background()) { if (!m_options->background()) {
Log::add(new ConsoleLog(m_options->colors())); Log::add(new ConsoleLog(m_options->colors()));
m_console = new Console(this);
} }
if (m_options->logFile()) { if (m_options->logFile()) {
@@ -74,6 +81,9 @@ App::App(int argc, char **argv) :
} }
# endif # endif
Platform::init(m_options->userAgent());
Platform::setProcessPriority(m_options->priority());
m_network = new Network(m_options); m_network = new Network(m_options);
uv_signal_init(uv_default_loop(), &m_signal); uv_signal_init(uv_default_loop(), &m_signal);
@@ -82,12 +92,13 @@ App::App(int argc, char **argv) :
App::~App() App::~App()
{ {
delete m_console;
} }
int App::exec() int App::exec()
{ {
if (!m_options->isReady()) { if (!m_options) {
return 0; return 0;
} }
@@ -102,27 +113,65 @@ int App::exec()
return 1; return 1;
} }
Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash()); Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash(), m_options->hugePages());
Summary::print(); Summary::print();
Workers::start(m_options->affinity()); Workers::start(m_options->affinity(), m_options->priority());
m_network->connect(); m_network->connect();
const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
uv_loop_close(uv_default_loop()); uv_loop_close(uv_default_loop());
uv_tty_reset_mode();
free(m_network); delete m_network;
free(m_options);
Options::release();
Mem::release(); Mem::release();
Platform::release();
return r; return r;
} }
void App::onConsoleCommand(char command)
{
switch (command) {
case 'h':
case 'H':
Workers::printHashrate(true);
break;
case 'p':
case 'P':
LOG_INFO(m_options->colors() ? "\x1B[01;33mpaused\x1B[0m, press \x1B[01;35mr\x1B[0m to resume" : "paused, press 'r' to resume");
Workers::setEnabled(false);
break;
case 'r':
case 'R':
if (!Workers::isEnabled()) {
LOG_INFO(m_options->colors() ? "\x1B[01;32mresumed" : "resumed");
Workers::setEnabled(true);
}
break;
case 3:
LOG_WARN("Ctrl+C received, exiting");
close();
break;
default:
break;
}
}
void App::close() void App::close()
{ {
m_network->stop();
Workers::stop();
uv_stop(uv_default_loop()); uv_stop(uv_default_loop());
} }
@@ -147,5 +196,6 @@ void App::onSignal(uv_signal_t *handle, int signum)
break; break;
} }
uv_signal_stop(handle);
m_self->close(); m_self->close();
} }

View File

@@ -28,11 +28,15 @@
#include <uv.h> #include <uv.h>
#include "interfaces/IConsoleListener.h"
class Console;
class Network; class Network;
class Options; class Options;
class App class App : public IConsoleListener
{ {
public: public:
App(int argc, char **argv); App(int argc, char **argv);
@@ -40,6 +44,9 @@ public:
int exec(); int exec();
protected:
void onConsoleCommand(char command) override;
private: private:
void background(); void background();
void close(); void close();
@@ -48,6 +55,7 @@ private:
static App *m_self; static App *m_self;
Console *m_console;
Network *m_network; Network *m_network;
Options *m_options; Options *m_options;
uv_signal_t m_signal; uv_signal_t m_signal;

61
src/Console.cpp Normal file
View File

@@ -0,0 +1,61 @@
/* XMRig
* 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>
*
*
* 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 "Console.h"
#include "interfaces/IConsoleListener.h"
Console::Console(IConsoleListener *listener)
: m_listener(listener)
{
m_tty.data = this;
uv_tty_init(uv_default_loop(), &m_tty, 0, 1);
if (!uv_is_readable(reinterpret_cast<uv_stream_t*>(&m_tty))) {
return;
}
uv_tty_set_mode(&m_tty, UV_TTY_MODE_RAW);
uv_read_start(reinterpret_cast<uv_stream_t*>(&m_tty), Console::onAllocBuffer, Console::onRead);
}
void Console::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
auto console = static_cast<Console*>(handle->data);
buf->len = 1;
buf->base = console->m_buf;
}
void Console::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
{
if (nread < 0) {
return uv_close(reinterpret_cast<uv_handle_t*>(stream), nullptr);
}
if (nread == 1) {
static_cast<Console*>(stream->data)->m_listener->onConsoleCommand(buf->base[0]);
}
}

View File

@@ -21,30 +21,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __CONSOLE_H__
#include <stdlib.h> #define __CONSOLE_H__
#include "net/Network.h" #include <uv.h>
#include "version.h"
char *Network::userAgent() class IConsoleListener;
class Console
{ {
const size_t max = 128; public:
Console(IConsoleListener *listener);
char *buf = static_cast<char*>(malloc(max)); private:
int length = snprintf(buf, max, "%s/%s (Linux ", APP_NAME, APP_VERSION); static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);
static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
# if defined(__x86_64__) char m_buf[1];
length += snprintf(buf + length, max - length, "x86_64) libuv/%s", uv_version_string()); IConsoleListener *m_listener;
# else uv_tty_t m_tty;
length += snprintf(buf + length, max - length, "i686) libuv/%s", uv_version_string()); };
# endif
# ifdef __GNUC__
length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
# endif
return buf; #endif /* __CONSOLE_H__ */
}

View File

@@ -29,6 +29,7 @@
#include "Cpu.h" #include "Cpu.h"
bool Cpu::m_l2_exclusive = false;
char Cpu::m_brand[64] = { 0 }; char Cpu::m_brand[64] = { 0 };
int Cpu::m_flags = 0; int Cpu::m_flags = 0;
int Cpu::m_l2_cache = 0; int Cpu::m_l2_cache = 0;
@@ -44,7 +45,14 @@ int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
return 1; return 1;
} }
int cache = m_l3_cache ? m_l3_cache : m_l2_cache; int cache = 0;
if (m_l3_cache) {
cache = m_l2_exclusive ? (m_l2_cache + m_l3_cache) : m_l3_cache;
}
else {
cache = m_l2_cache;
}
int count = 0; int count = 0;
const int size = (algo ? 1024 : 2048) * (doubleHash ? 2 : 1); const int size = (algo ? 1024 : 2048) * (doubleHash ? 2 : 1);
@@ -60,7 +68,7 @@ int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
} }
if (((float) count / m_totalThreads * 100) > maxCpuUsage) { if (((float) count / m_totalThreads * 100) > maxCpuUsage) {
count = ceil((float) m_totalThreads * (maxCpuUsage / 100.0)); count = (int) ceil((float) m_totalThreads * (maxCpuUsage / 100.0));
} }
return count < 1 ? 1 : count; return count < 1 ? 1 : count;
@@ -84,8 +92,9 @@ void Cpu::initCommon()
m_l3_cache = data.l3_cache > 0 ? data.l3_cache * m_sockets : 0; m_l3_cache = data.l3_cache > 0 ? data.l3_cache * m_sockets : 0;
// Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97 // Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97
if (data.vendor == VENDOR_AMD && data.l3_cache <= 0 && data.l2_assoc == 16 && data.ext_family >= 21) { if (data.vendor == VENDOR_AMD && data.ext_family >= 0x15 && data.ext_family < 0x17) {
m_l2_cache = data.l2_cache * (m_totalCores / 2) * m_sockets; m_l2_cache = data.l2_cache * (m_totalCores / 2) * m_sockets;
m_l2_exclusive = true;
} }
else { else {
m_l2_cache = data.l2_cache > 0 ? data.l2_cache * m_totalCores * m_sockets : 0; m_l2_cache = data.l2_cache > 0 ? data.l2_cache * m_totalCores * m_sockets : 0;

View File

@@ -41,8 +41,8 @@ public:
static void init(); static void init();
static void setAffinity(int id, uint64_t mask); static void setAffinity(int id, uint64_t mask);
static inline bool hasAES() { return m_flags & AES; } static inline bool hasAES() { return (m_flags & AES) != 0; }
static inline bool isX64() { return m_flags & X86_64; } static inline bool isX64() { return (m_flags & X86_64) != 0; }
static inline const char *brand() { return m_brand; } static inline const char *brand() { return m_brand; }
static inline int cores() { return m_totalCores; } static inline int cores() { return m_totalCores; }
static inline int l2() { return m_l2_cache; } static inline int l2() { return m_l2_cache; }
@@ -53,6 +53,7 @@ public:
private: private:
static void initCommon(); static void initCommon();
static bool m_l2_exclusive;
static char m_brand[64]; static char m_brand[64];
static int m_flags; static int m_flags;
static int m_l2_cache; static int m_l2_cache;

View File

@@ -44,14 +44,14 @@ public:
Lock = 4 Lock = 4
}; };
static bool allocate(int algo, int threads, bool doubleHash); static bool allocate(int algo, int threads, bool doubleHash, bool enabled);
static cryptonight_ctx *create(int threadId); static cryptonight_ctx *create(int threadId);
static void *calloc(size_t num, size_t size); static void *calloc(size_t num, size_t size);
static void release(); static void release();
static inline bool isDoubleHash() { return m_doubleHash; } static inline bool isDoubleHash() { return m_doubleHash; }
static inline bool isHugepagesAvailable() { return m_flags & HugepagesAvailable; } static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; }
static inline bool isHugepagesEnabled() { return m_flags & HugepagesEnabled; } static inline bool isHugepagesEnabled() { return (m_flags & HugepagesEnabled) != 0; }
static inline int flags() { return m_flags; } static inline int flags() { return m_flags; }
static inline int threads() { return m_threads; } static inline int threads() { return m_threads; }

View File

@@ -33,7 +33,7 @@
#include "Options.h" #include "Options.h"
bool Mem::allocate(int algo, int threads, bool doubleHash) bool Mem::allocate(int algo, int threads, bool doubleHash, bool enabled)
{ {
m_algo = algo; m_algo = algo;
m_threads = threads; m_threads = threads;
@@ -42,6 +42,11 @@ bool Mem::allocate(int algo, int threads, bool doubleHash)
const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1; const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
const size_t size = MEMORY * (threads * ratio + 1); const size_t size = MEMORY * (threads * ratio + 1);
if (!enabled) {
m_memory = static_cast<uint8_t*>(_mm_malloc(size, 16));
return true;
}
m_flags |= HugepagesAvailable; m_flags |= HugepagesAvailable;
# if defined(__APPLE__) # if defined(__APPLE__)

View File

@@ -85,9 +85,8 @@ static BOOL SetLockPagesPrivilege() {
static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) { static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) {
LSA_UNICODE_STRING lsaString; LSA_UNICODE_STRING lsaString;
DWORD dwLen = 0;
dwLen = wcslen(string); DWORD dwLen = (DWORD) wcslen(string);
lsaString.Buffer = (LPWSTR) string; lsaString.Buffer = (LPWSTR) string;
lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR)); lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR));
lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR)); lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR));
@@ -124,7 +123,7 @@ static BOOL ObtainLockPagesPrivilege() {
LSA_UNICODE_STRING str = StringToLsaUnicodeString(_T(SE_LOCK_MEMORY_NAME)); LSA_UNICODE_STRING str = StringToLsaUnicodeString(_T(SE_LOCK_MEMORY_NAME));
if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) { if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) {
LOG_DEBUG("Huge pages support was successfully enabled, but reboot required to use it"); LOG_NOTICE("Huge pages support was successfully enabled, but reboot required to use it");
result = TRUE; result = TRUE;
} }
@@ -145,7 +144,7 @@ static BOOL TrySetLockPagesPrivilege() {
} }
bool Mem::allocate(int algo, int threads, bool doubleHash) bool Mem::allocate(int algo, int threads, bool doubleHash, bool enabled)
{ {
m_algo = algo; m_algo = algo;
m_threads = threads; m_threads = threads;
@@ -154,6 +153,11 @@ bool Mem::allocate(int algo, int threads, bool doubleHash)
const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1; const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
const size_t size = MEMORY * (threads * ratio + 1); const size_t size = MEMORY * (threads * ratio + 1);
if (!enabled) {
m_memory = static_cast<uint8_t*>(_mm_malloc(size, 16));
return true;
}
if (TrySetLockPagesPrivilege()) { if (TrySetLockPagesPrivilege()) {
m_flags |= HugepagesAvailable; m_flags |= HugepagesAvailable;
} }

View File

@@ -38,6 +38,7 @@
#include "donate.h" #include "donate.h"
#include "net/Url.h" #include "net/Url.h"
#include "Options.h" #include "Options.h"
#include "Platform.h"
#include "version.h" #include "version.h"
@@ -63,8 +64,11 @@ Options:\n\
-r, --retries=N number of times to retry before switch to backup server (default: 5)\n\ -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\
-R, --retry-pause=N time to pause between retries (default: 5)\n\ -R, --retry-pause=N time to pause between retries (default: 5)\n\
--cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\
--cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\
--no-huge-pages disable huge pages support\n\
--no-color disable colored output\n\ --no-color disable colored output\n\
--donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\
--user-agent set custom user-agent string for pool\n\
-B, --background run the miner in the background\n\ -B, --background run the miner in the background\n\
-c, --config=FILE load a JSON-format configuration file\n\ -c, --config=FILE load a JSON-format configuration file\n\
-l, --log-file=FILE log all output to a file\n" -l, --log-file=FILE log all output to a file\n"
@@ -91,6 +95,7 @@ static struct option const options[] = {
{ "background", 0, nullptr, 'B' }, { "background", 0, nullptr, 'B' },
{ "config", 1, nullptr, 'c' }, { "config", 1, nullptr, 'c' },
{ "cpu-affinity", 1, nullptr, 1020 }, { "cpu-affinity", 1, nullptr, 1020 },
{ "cpu-priority", 1, nullptr, 1021 },
{ "donate-level", 1, nullptr, 1003 }, { "donate-level", 1, nullptr, 1003 },
{ "help", 0, nullptr, 'h' }, { "help", 0, nullptr, 'h' },
{ "keepalive", 0, nullptr ,'k' }, { "keepalive", 0, nullptr ,'k' },
@@ -98,6 +103,7 @@ static struct option const options[] = {
{ "max-cpu-usage", 1, nullptr, 1004 }, { "max-cpu-usage", 1, nullptr, 1004 },
{ "nicehash", 0, nullptr, 1006 }, { "nicehash", 0, nullptr, 1006 },
{ "no-color", 0, nullptr, 1002 }, { "no-color", 0, nullptr, 1002 },
{ "no-huge-pages", 0, nullptr, 1009 },
{ "pass", 1, nullptr, 'p' }, { "pass", 1, nullptr, 'p' },
{ "print-time", 1, nullptr, 1007 }, { "print-time", 1, nullptr, 1007 },
{ "retries", 1, nullptr, 'r' }, { "retries", 1, nullptr, 'r' },
@@ -107,12 +113,46 @@ static struct option const options[] = {
{ "threads", 1, nullptr, 't' }, { "threads", 1, nullptr, 't' },
{ "url", 1, nullptr, 'o' }, { "url", 1, nullptr, 'o' },
{ "user", 1, nullptr, 'u' }, { "user", 1, nullptr, 'u' },
{ "user-agent", 1, nullptr, 1008 },
{ "userpass", 1, nullptr, 'O' }, { "userpass", 1, nullptr, 'O' },
{ "version", 0, nullptr, 'V' }, { "version", 0, nullptr, 'V' },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
static struct option const config_options[] = {
{ "algo", 1, nullptr, 'a' },
{ "av", 1, nullptr, 'v' },
{ "background", 0, nullptr, 'B' },
{ "colors", 0, nullptr, 2000 },
{ "cpu-affinity", 1, nullptr, 1020 },
{ "cpu-priority", 1, nullptr, 1021 },
{ "donate-level", 1, nullptr, 1003 },
{ "huge-pages", 0, nullptr, 1009 },
{ "log-file", 1, nullptr, 'l' },
{ "max-cpu-usage", 1, nullptr, 1004 },
{ "print-time", 1, nullptr, 1007 },
{ "retries", 1, nullptr, 'r' },
{ "retry-pause", 1, nullptr, 'R' },
{ "safe", 0, nullptr, 1005 },
{ "syslog", 0, nullptr, 'S' },
{ "threads", 1, nullptr, 't' },
{ "user-agent", 1, nullptr, 1008 },
{ 0, 0, 0, 0 }
};
static struct option const pool_options[] = {
{ "url", 1, nullptr, 'o' },
{ "pass", 1, nullptr, 'p' },
{ "user", 1, nullptr, 'u' },
{ "userpass", 1, nullptr, 'O' },
{ "keepalive", 0, nullptr ,'k' },
{ "nicehash", 0, nullptr, 1006 },
{ 0, 0, 0, 0 }
};
static const char *algo_names[] = { static const char *algo_names[] = {
"cryptonight", "cryptonight",
# ifndef XMRIG_NO_AEON # ifndef XMRIG_NO_AEON
@@ -123,11 +163,14 @@ static const char *algo_names[] = {
Options *Options::parse(int argc, char **argv) Options *Options::parse(int argc, char **argv)
{ {
if (!m_self) { Options *options = new Options(argc, argv);
m_self = new Options(argc, argv); if (options->isReady()) {
m_self = options;
return m_self;
} }
return m_self; delete options;
return nullptr;
} }
@@ -141,15 +184,18 @@ Options::Options(int argc, char **argv) :
m_background(false), m_background(false),
m_colors(true), m_colors(true),
m_doubleHash(false), m_doubleHash(false),
m_hugePages(true),
m_ready(false), m_ready(false),
m_safe(false), m_safe(false),
m_syslog(false), m_syslog(false),
m_logFile(nullptr), m_logFile(nullptr),
m_userAgent(nullptr),
m_algo(0), m_algo(0),
m_algoVariant(0), m_algoVariant(0),
m_donateLevel(kDonateLevel), m_donateLevel(kDonateLevel),
m_maxCpuUsage(75), m_maxCpuUsage(75),
m_printTime(60), m_printTime(60),
m_priority(-1),
m_retries(5), m_retries(5),
m_retryPause(5), m_retryPause(5),
m_threads(0), m_threads(0),
@@ -176,7 +222,11 @@ Options::Options(int argc, char **argv) :
} }
if (!m_pools[0]->isValid()) { if (!m_pools[0]->isValid()) {
fprintf(stderr, "No pool URL supplied. Exiting."); parseConfig(Platform::defaultConfigName());
}
if (!m_pools[0]->isValid()) {
fprintf(stderr, "No pool URL supplied. Exiting.\n");
return; return;
} }
@@ -204,11 +254,8 @@ Options::~Options()
} }
bool Options::parseArg(int key, char *arg) bool Options::parseArg(int key, const char *arg)
{ {
char *p;
int v;
switch (key) { switch (key) {
case 'a': /* --algo */ case 'a': /* --algo */
if (!setAlgo(arg)) { if (!setAlgo(arg)) {
@@ -216,13 +263,6 @@ bool Options::parseArg(int key, char *arg)
} }
break; break;
case 'O': /* --userpass */
if (!m_pools.back()->setUserpass(arg)) {
return false;
}
break;
case 'o': /* --url */ case 'o': /* --url */
if (m_pools.size() > 1 || m_pools[0]->isValid()) { if (m_pools.size() > 1 || m_pools[0]->isValid()) {
Url *url = new Url(arg); Url *url = new Url(arg);
@@ -240,7 +280,12 @@ bool Options::parseArg(int key, char *arg)
if (!m_pools.back()->isValid()) { if (!m_pools.back()->isValid()) {
return false; return false;
} }
break;
case 'O': /* --userpass */
if (!m_pools.back()->setUserpass(arg)) {
return false;
}
break; break;
case 'u': /* --user */ case 'u': /* --user */
@@ -258,52 +303,25 @@ bool Options::parseArg(int key, char *arg)
break; break;
case 'r': /* --retries */ case 'r': /* --retries */
v = strtol(arg, nullptr, 10);
if (v < 1 || v > 1000) {
showUsage(1);
return false;
}
m_retries = v;
break;
case 'R': /* --retry-pause */ case 'R': /* --retry-pause */
v = strtol(arg, nullptr, 10);
if (v < 1 || v > 3600) {
showUsage(1);
return false;
}
m_retryPause = v;
break;
case 't': /* --threads */ case 't': /* --threads */
v = strtol(arg, nullptr, 10); case 'v': /* --av */
if (v < 1 || v > 1024) { case 1003: /* --donate-level */
showUsage(1);
return false;
}
m_threads = v;
break;
case 1004: /* --max-cpu-usage */ case 1004: /* --max-cpu-usage */
v = strtol(arg, nullptr, 10); case 1007: /* --print-time */
if (v < 1 || v > 100) { case 1021: /* --cpu-priority */
showUsage(1); return parseArg(key, strtol(arg, nullptr, 10));
return false;
}
m_maxCpuUsage = v;
break;
case 1005: /* --safe */
m_safe = true;
break;
case 'B': /* --background */
case 'k': /* --keepalive */ case 'k': /* --keepalive */
m_pools.back()->setKeepAlive(true); case 'S': /* --syslog */
break; case 1005: /* --safe */
case 1006: /* --nicehash */
return parseBoolean(key, true);
case 1002: /* --no-color */
case 1009: /* --no-huge-pages */
return parseBoolean(key, false);
case 'V': /* --version */ case 'V': /* --version */
showVersion(); showVersion();
@@ -313,57 +331,18 @@ bool Options::parseArg(int key, char *arg)
showUsage(0); showUsage(0);
return false; return false;
case 'B': /* --background */ case 'c': /* --config */
m_background = true; parseConfig(arg);
m_colors = false;
break; break;
case 'S': /* --syslog */ case 1020: { /* --cpu-affinity */
m_syslog = true; const char *p = strstr(arg, "0x");
m_colors = false; return parseArg(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10));
break;
case 'v': /* --av */
v = strtol(arg, nullptr, 10);
if (v < 0 || v > 1000) {
showUsage(1);
return false;
} }
m_algoVariant = v; case 1008: /* --user-agent */
break; free(m_userAgent);
m_userAgent = strdup(arg);
case 1020: /* --cpu-affinity */
p = strstr(arg, "0x");
m_affinity = p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10);
break;
case 1002: /* --no-color */
m_colors = false;
break;
case 1003: /* --donate-level */
v = strtol(arg, nullptr, 10);
if (v < 1 || v > 99) {
showUsage(1);
return false;
}
m_donateLevel = v;
break;
case 1006: /* --nicehash */
m_pools.back()->setNicehash(true);
break;
case 1007: /* --print-time */
v = strtol(arg, nullptr, 10);
if (v < 0 || v > 1000) {
showUsage(1);
return false;
}
m_printTime = v;
break; break;
default: default:
@@ -375,6 +354,137 @@ bool Options::parseArg(int key, char *arg)
} }
bool Options::parseArg(int key, uint64_t arg)
{
switch (key) {
case 'r': /* --retries */
if (arg < 1 || arg > 1000) {
showUsage(1);
return false;
}
m_retries = (int) arg;
break;
case 'R': /* --retry-pause */
if (arg < 1 || arg > 3600) {
showUsage(1);
return false;
}
m_retryPause = (int) arg;
break;
case 't': /* --threads */
if (arg < 1 || arg > 1024) {
showUsage(1);
return false;
}
m_threads = (int) arg;
break;
case 'v': /* --av */
if (arg > 1000) {
showUsage(1);
return false;
}
m_algoVariant = (int) arg;
break;
case 1003: /* --donate-level */
if (arg < 1 || arg > 99) {
showUsage(1);
return false;
}
m_donateLevel = (int) arg;
break;
case 1004: /* --max-cpu-usage */
if (arg < 1 || arg > 100) {
showUsage(1);
return false;
}
m_maxCpuUsage = (int) arg;
break;
case 1007: /* --print-time */
if (arg > 1000) {
showUsage(1);
return false;
}
m_printTime = (int) arg;
break;
case 1020: /* --cpu-affinity */
if (arg) {
m_affinity = arg;
}
break;
case 1021: /* --cpu-priority */
if (arg <= 5) {
m_priority = (int) arg;
}
break;
default:
break;
}
return true;
}
bool Options::parseBoolean(int key, bool enable)
{
switch (key) {
case 'k': /* --keepalive */
m_pools.back()->setKeepAlive(enable);
break;
case 'B': /* --background */
m_background = enable;
m_colors = enable ? false : m_colors;
break;
case 'S': /* --syslog */
m_syslog = enable;
m_colors = enable ? false : m_colors;
break;
case 1002: /* --no-color */
m_colors = enable;
break;
case 1005: /* --safe */
m_safe = enable;
break;
case 1006: /* --nicehash */
m_pools.back()->setNicehash(enable);
break;
case 1009: /* --no-huge-pages */
m_hugePages = enable;
break;
case 2000: /* colors */
m_colors = enable;
break;
default:
break;
}
return true;
}
Url *Options::parseUrl(const char *arg) const Url *Options::parseUrl(const char *arg) const
{ {
auto url = new Url(arg); auto url = new Url(arg);
@@ -387,6 +497,84 @@ Url *Options::parseUrl(const char *arg) const
} }
void Options::parseConfig(const char *fileName)
{
uv_fs_t req;
const int fd = uv_fs_open(uv_default_loop(), &req, fileName, O_RDONLY, 0644, nullptr);
if (fd < 0) {
fprintf(stderr, "unable to open %s: %s\n", fileName, uv_strerror(fd));
return;
}
uv_fs_req_cleanup(&req);
json_error_t err;
json_t *config = json_loadfd(fd, 0, &err);
uv_fs_close(uv_default_loop(), &req, fd, nullptr);
uv_fs_req_cleanup(&req);
if (!json_is_object(config)) {
if (config) {
json_decref(config);
return;
}
if (err.line < 0) {
fprintf(stderr, "%s\n", err.text);
}
else {
fprintf(stderr, "%s:%d: %s\n", fileName, err.line, err.text);
}
return;
}
for (size_t i = 0; i < ARRAY_SIZE(config_options); i++) {
parseJSON(&config_options[i], config);
}
json_t *pools = json_object_get(config, "pools");
if (json_is_array(pools)) {
size_t index;
json_t *value;
json_array_foreach(pools, index, value) {
if (json_is_object(value)) {
for (size_t i = 0; i < ARRAY_SIZE(pool_options); i++) {
parseJSON(&pool_options[i], value);
}
}
}
}
json_decref(config);
}
void Options::parseJSON(const struct option *option, json_t *object)
{
if (!option->name) {
return;
}
json_t *val = json_object_get(object, option->name);
if (!val) {
return;
}
if (option->has_arg && json_is_string(val)) {
parseArg(option->val, json_string_value(val));
}
else if (option->has_arg && json_is_integer(val)) {
parseArg(option->val, json_integer_value(val));
}
else if (!option->has_arg && json_is_boolean(val)) {
parseBoolean(option->val, json_is_true(val));
}
}
void Options::showUsage(int status) const void Options::showUsage(int status) const
{ {
if (status) { if (status) {
@@ -435,7 +623,7 @@ bool Options::setAlgo(const char *algo)
{ {
for (size_t i = 0; i < ARRAY_SIZE(algo_names); i++) { for (size_t i = 0; i < ARRAY_SIZE(algo_names); i++) {
if (algo_names[i] && !strcmp(algo, algo_names[i])) { if (algo_names[i] && !strcmp(algo, algo_names[i])) {
m_algo = i; m_algo = (int) i;
break; break;
} }

View File

@@ -25,11 +25,13 @@
#define __OPTIONS_H__ #define __OPTIONS_H__
#include <vector> #include <jansson.h>
#include <stdint.h> #include <stdint.h>
#include <vector>
class Url; class Url;
struct option;
class Options class Options
@@ -55,29 +57,39 @@ public:
inline bool background() const { return m_background; } inline bool background() const { return m_background; }
inline bool colors() const { return m_colors; } inline bool colors() const { return m_colors; }
inline bool doubleHash() const { return m_doubleHash; } inline bool doubleHash() const { return m_doubleHash; }
inline bool isReady() const { return m_ready; } inline bool hugePages() const { return m_hugePages; }
inline bool syslog() const { return m_syslog; } inline bool syslog() const { return m_syslog; }
inline const char *logFile() const { return m_logFile; } inline const char *logFile() const { return m_logFile; }
inline const char *userAgent() const { return m_userAgent; }
inline const std::vector<Url*> &pools() const { return m_pools; } inline const std::vector<Url*> &pools() const { return m_pools; }
inline int algo() const { return m_algo; } inline int algo() const { return m_algo; }
inline int algoVariant() const { return m_algoVariant; } inline int algoVariant() const { return m_algoVariant; }
inline int donateLevel() const { return m_donateLevel; } inline int donateLevel() const { return m_donateLevel; }
inline int printTime() const { return m_printTime; } inline int printTime() const { return m_printTime; }
inline int priority() const { return m_priority; }
inline int retries() const { return m_retries; } inline int retries() const { return m_retries; }
inline int retryPause() const { return m_retryPause; } inline int retryPause() const { return m_retryPause; }
inline int threads() const { return m_threads; } inline int threads() const { return m_threads; }
inline int64_t affinity() const { return m_affinity; } inline int64_t affinity() const { return m_affinity; }
inline static void release() { delete m_self; }
const char *algoName() const; const char *algoName() const;
private: private:
Options(int argc, char **argv); Options(int argc, char **argv);
~Options(); ~Options();
inline bool isReady() const { return m_ready; }
static Options *m_self; static Options *m_self;
bool parseArg(int key, char *arg); bool parseArg(int key, const char *arg);
bool parseArg(int key, uint64_t arg);
bool parseBoolean(int key, bool enable);
Url *parseUrl(const char *arg) const; Url *parseUrl(const char *arg) const;
void parseConfig(const char *fileName);
void parseJSON(const struct option *option, json_t *object);
void showUsage(int status) const; void showUsage(int status) const;
void showVersion(void); void showVersion(void);
@@ -91,15 +103,18 @@ private:
bool m_background; bool m_background;
bool m_colors; bool m_colors;
bool m_doubleHash; bool m_doubleHash;
bool m_hugePages;
bool m_ready; bool m_ready;
bool m_safe; bool m_safe;
bool m_syslog; bool m_syslog;
char *m_logFile; char *m_logFile;
char *m_userAgent;
int m_algo; int m_algo;
int m_algoVariant; int m_algoVariant;
int m_donateLevel; int m_donateLevel;
int m_maxCpuUsage; int m_maxCpuUsage;
int m_printTime; int m_printTime;
int m_priority;
int m_retries; int m_retries;
int m_retryPause; int m_retryPause;
int m_threads; int m_threads;

62
src/Platform.cpp Normal file
View File

@@ -0,0 +1,62 @@
/* XMRig
* 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>
*
*
* 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 <string.h>
#include <uv.h>
#include "Platform.h"
char *Platform::m_defaultConfigName = nullptr;
char *Platform::m_userAgent = nullptr;
const char *Platform::defaultConfigName()
{
size_t size = 520;
if (m_defaultConfigName == nullptr) {
m_defaultConfigName = new char[size];
}
if (uv_exepath(m_defaultConfigName, &size) < 0) {
return nullptr;
}
if (size < 500) {
# ifdef WIN32
char *p = strrchr(m_defaultConfigName, '\\');
# else
char *p = strrchr(m_defaultConfigName, '/');
# endif
if (p) {
strcpy(p + 1, "config.json");
return m_defaultConfigName;
}
}
return nullptr;
}

45
src/Platform.h Normal file
View File

@@ -0,0 +1,45 @@
/* XMRig
* 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>
*
*
* 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 __PLATFORM_H__
#define __PLATFORM_H__
class Platform
{
public:
static const char *defaultConfigName();
static void init(const char *userAgent);
static void release();
static void setProcessPriority(int priority);
static void setThreadPriority(int priority);
static inline const char *userAgent() { return m_userAgent; }
private:
static char *m_defaultConfigName;
static char *m_userAgent;
};
#endif /* __PLATFORM_H__ */

108
src/Platform_mac.cpp Normal file
View File

@@ -0,0 +1,108 @@
/* XMRig
* 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>
*
*
* 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 <stdlib.h>
#include <sys/resource.h>
#include <uv.h>
#include "Platform.h"
#include "version.h"
#ifdef XMRIG_NVIDIA_PROJECT
# include "nvidia/cryptonight.h"
#endif
static inline char *createUserAgent()
{
const size_t max = 160;
char *buf = new char[max];
# ifdef XMRIG_NVIDIA_PROJECT
const int cudaVersion = cuda_get_runtime_version();
snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s CUDA/%d.%d clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), cudaVersion / 1000, cudaVersion % 100, __clang_major__, __clang_minor__, __clang_patchlevel__);
# else
snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), __clang_major__, __clang_minor__, __clang_patchlevel__);
# endif
return buf;
}
void Platform::init(const char *userAgent)
{
m_userAgent = userAgent ? strdup(userAgent) : createUserAgent();
}
void Platform::release()
{
delete [] m_userAgent;
}
void Platform::setProcessPriority(int priority)
{
}
void Platform::setThreadPriority(int priority)
{
if (priority == -1) {
return;
}
int prio = 19;
switch (priority)
{
case 1:
prio = 5;
break;
case 2:
prio = 0;
break;
case 3:
prio = -5;
break;
case 4:
prio = -10;
break;
case 5:
prio = -15;
break;
default:
break;
}
setpriority(PRIO_PROCESS, 0, prio);
}

127
src/Platform_unix.cpp Normal file
View File

@@ -0,0 +1,127 @@
/* XMRig
* 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>
*
*
* 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 <sched.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <uv.h>
#include "Platform.h"
#include "version.h"
#ifdef XMRIG_NVIDIA_PROJECT
# include "nvidia/cryptonight.h"
#endif
static inline char *createUserAgent()
{
const size_t max = 160;
char *buf = new char[max];
int length = snprintf(buf, max, "%s/%s (Linux ", APP_NAME, APP_VERSION);
# if defined(__x86_64__)
length += snprintf(buf + length, max - length, "x86_64) libuv/%s", uv_version_string());
# else
length += snprintf(buf + length, max - length, "i686) libuv/%s", uv_version_string());
# endif
# ifdef XMRIG_NVIDIA_PROJECT
const int cudaVersion = cuda_get_runtime_version();
length += snprintf(buf + length, max - length, " CUDA/%d.%d", cudaVersion / 1000, cudaVersion % 100);
# endif
# ifdef __GNUC__
length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
# endif
return buf;
}
void Platform::init(const char *userAgent)
{
m_userAgent = userAgent ? strdup(userAgent) : createUserAgent();
}
void Platform::release()
{
delete [] m_userAgent;
}
void Platform::setProcessPriority(int priority)
{
}
void Platform::setThreadPriority(int priority)
{
if (priority == -1) {
return;
}
int prio = 19;
switch (priority)
{
case 1:
prio = 5;
break;
case 2:
prio = 0;
break;
case 3:
prio = -5;
break;
case 4:
prio = -10;
break;
case 5:
prio = -15;
break;
default:
break;
}
setpriority(PRIO_PROCESS, 0, prio);
if (priority == 0) {
sched_param param;
param.sched_priority = 0;
if (sched_setscheduler(0, SCHED_IDLE, &param) != 0) {
sched_setscheduler(0, SCHED_BATCH, &param);
}
}
}

View File

@@ -24,11 +24,16 @@
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#include <uv.h>
#include "net/Network.h" #include "Platform.h"
#include "version.h" #include "version.h"
#ifdef XMRIG_NVIDIA_PROJECT
# include "nvidia/cryptonight.h"
#endif
static inline OSVERSIONINFOEX winOsVersion() static inline OSVERSIONINFOEX winOsVersion()
{ {
@@ -48,12 +53,12 @@ static inline OSVERSIONINFOEX winOsVersion()
} }
char *Network::userAgent() static inline char *createUserAgent()
{ {
const auto osver = winOsVersion(); const auto osver = winOsVersion();
const size_t max = 128; const size_t max = 160;
char *buf = static_cast<char*>(malloc(max)); char *buf = new char[max];
int length = snprintf(buf, max, "%s/%s (Windows NT %lu.%lu", APP_NAME, APP_VERSION, osver.dwMajorVersion, osver.dwMinorVersion); int length = snprintf(buf, max, "%s/%s (Windows NT %lu.%lu", APP_NAME, APP_VERSION, osver.dwMajorVersion, osver.dwMinorVersion);
# if defined(__x86_64__) || defined(_M_AMD64) # if defined(__x86_64__) || defined(_M_AMD64)
@@ -62,6 +67,11 @@ char *Network::userAgent()
length += snprintf(buf + length, max - length, ") libuv/%s", uv_version_string()); length += snprintf(buf + length, max - length, ") libuv/%s", uv_version_string());
# endif # endif
# ifdef XMRIG_NVIDIA_PROJECT
const int cudaVersion = cuda_get_runtime_version();
length += snprintf(buf + length, max - length, " CUDA/%d.%d", cudaVersion / 1000, cudaVersion % 100);
# endif
# ifdef __GNUC__ # ifdef __GNUC__
length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
# elif _MSC_VER # elif _MSC_VER
@@ -70,3 +80,91 @@ char *Network::userAgent()
return buf; return buf;
} }
void Platform::init(const char *userAgent)
{
m_userAgent = userAgent ? strdup(userAgent) : createUserAgent();
}
void Platform::release()
{
delete [] m_defaultConfigName;
delete [] m_userAgent;
}
void Platform::setProcessPriority(int priority)
{
if (priority == -1) {
return;
}
DWORD prio = IDLE_PRIORITY_CLASS;
switch (priority)
{
case 1:
prio = BELOW_NORMAL_PRIORITY_CLASS;
break;
case 2:
prio = NORMAL_PRIORITY_CLASS;
break;
case 3:
prio = ABOVE_NORMAL_PRIORITY_CLASS;
break;
case 4:
prio = HIGH_PRIORITY_CLASS;
break;
case 5:
prio = REALTIME_PRIORITY_CLASS;
default:
break;
}
SetPriorityClass(GetCurrentProcess(), prio);
}
void Platform::setThreadPriority(int priority)
{
if (priority == -1) {
return;
}
int prio = THREAD_PRIORITY_IDLE;
switch (priority)
{
case 1:
prio = THREAD_PRIORITY_BELOW_NORMAL;
break;
case 2:
prio = THREAD_PRIORITY_NORMAL;
break;
case 3:
prio = THREAD_PRIORITY_ABOVE_NORMAL;
break;
case 4:
prio = THREAD_PRIORITY_HIGHEST;
break;
case 5:
prio = THREAD_PRIORITY_TIME_CRITICAL;
break;
default:
break;
}
SetThreadPriority(GetCurrentThread(), prio);
}

View File

@@ -22,6 +22,7 @@
*/ */
#include <inttypes.h>
#include <uv.h> #include <uv.h>
@@ -49,11 +50,8 @@ static void print_versions()
# endif # endif
if (Options::i()->colors()) { Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s%s" : " * VERSIONS: XMRig/%s libuv/%s%s",
Log::i()->text("\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s%s", APP_VERSION, uv_version_string(), buf); APP_VERSION, uv_version_string(), buf);
} else {
Log::i()->text(" * VERSIONS: XMRig/%s libuv/%s%s", APP_VERSION, uv_version_string(), buf);
}
} }
@@ -94,7 +92,7 @@ static void print_threads()
{ {
char buf[32]; char buf[32];
if (Options::i()->affinity() != -1L) { if (Options::i()->affinity() != -1L) {
snprintf(buf, 32, ", affinity=0x%llX", Options::i()->affinity()); snprintf(buf, 32, ", affinity=0x%" PRIX64, Options::i()->affinity());
} }
else { else {
buf[0] = '\0'; buf[0] = '\0';
@@ -129,6 +127,17 @@ static void print_pools()
} }
static void print_commands()
{
if (Options::i()->colors()) {
Log::i()->text("\x1B[01;32m * \x1B[01;37mCOMMANDS: \x1B[01;35mh\x1B[01;37mashrate, \x1B[01;35mp\x1B[01;37mause, \x1B[01;35mr\x1B[01;37mesume");
}
else {
Log::i()->text(" * COMMANDS: 'h' hashrate, 'p' pause, 'r' resume");
}
}
void Summary::print() void Summary::print()
{ {
print_versions(); print_versions();
@@ -136,6 +145,7 @@ void Summary::print()
print_cpu(); print_cpu();
print_threads(); print_threads();
print_pools(); print_pools();
print_commands();
} }

26
src/config.json Normal file
View File

@@ -0,0 +1,26 @@
{
"algo": "cryptonight",
"av": 0,
"background": false,
"colors": true,
"cpu-affinity": null,
"cpu-priority": null,
"donate-level": 5,
"log-file": null,
"max-cpu-usage": 75,
"print-time": 60,
"retries": 5,
"retry-pause": 5,
"safe": false,
"syslog": false,
"threads": null,
"pools": [
{
"url": "pool.minemonero.pro:5555",
"user": "",
"pass": "x",
"keepalive": true,
"nicehash": false
}
]
}

View File

@@ -65,7 +65,7 @@ static inline void do_jh_hash(const void* input, size_t len, char* output) {
static inline void do_skein_hash(const void* input, size_t len, char* output) { static inline void do_skein_hash(const void* input, size_t len, char* output) {
skein_hash(8 * 32, static_cast<const uint8_t*>(input), 8 * len, reinterpret_cast<uint8_t*>(output)); xmr_skein(static_cast<const uint8_t*>(input), reinterpret_cast<uint8_t*>(output));
} }
@@ -311,7 +311,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
template<size_t ITERATIONS, size_t MEM, size_t MASK, bool SOFT_AES> template<size_t ITERATIONS, size_t MEM, size_t MASK, bool SOFT_AES>
inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx) inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx)
{ {
keccak(static_cast<const uint8_t*>(input), size, ctx->state0, 200); keccak(static_cast<const uint8_t*>(input), (int) size, ctx->state0, 200);
cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*) ctx->state0, (__m128i*) ctx->memory); cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*) ctx->state0, (__m128i*) ctx->memory);
@@ -365,8 +365,8 @@ inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *
template<size_t ITERATIONS, size_t MEM, size_t MASK, bool SOFT_AES> template<size_t ITERATIONS, size_t MEM, size_t MASK, bool SOFT_AES>
inline void cryptonight_double_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx) inline void cryptonight_double_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx)
{ {
keccak((const uint8_t *) input, size, ctx->state0, 200); keccak((const uint8_t *) input, (int) size, ctx->state0, 200);
keccak((const uint8_t *) input + size, size, ctx->state1, 200); keccak((const uint8_t *) input + size, (int) size, ctx->state1, 200);
const uint8_t* l0 = ctx->memory; const uint8_t* l0 = ctx->memory;
const uint8_t* l1 = ctx->memory + MEM; const uint8_t* l1 = ctx->memory + MEM;

View File

@@ -148,7 +148,7 @@ void blake256_update(state *S, const uint8_t *data, uint64_t datalen) {
if (datalen > 0) { if (datalen > 0) {
memcpy((void *) (S->buf + left), (void *) data, datalen >> 3); memcpy((void *) (S->buf + left), (void *) data, datalen >> 3);
S->buflen = (left << 3) + datalen; S->buflen = (left << 3) + (int) datalen;
} else { } else {
S->buflen = 0; S->buflen = 0;
} }

View File

@@ -3,7 +3,7 @@
// A baseline Keccak (3rd round) implementation. // A baseline Keccak (3rd round) implementation.
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <memory.h>
#define HASH_DATA_AREA 136 #define HASH_DATA_AREA 136
#define KECCAK_ROUNDS 24 #define KECCAK_ROUNDS 24
@@ -24,18 +24,6 @@ const uint64_t keccakf_rndc[24] =
0x8000000000008080, 0x0000000080000001, 0x8000000080008008 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
}; };
const int keccakf_rotc[24] =
{
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
};
const int keccakf_piln[24] =
{
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
};
// update the state with given number of rounds // update the state with given number of rounds
void keccakf(uint64_t st[25], int rounds) void keccakf(uint64_t st[25], int rounds)
@@ -63,25 +51,85 @@ void keccakf(uint64_t st[25], int rounds)
// Rho Pi // Rho Pi
t = st[1]; t = st[1];
for (i = 0; i < 24; ++i) { st[ 1] = ROTL64(st[ 6], 44);
bc[0] = st[keccakf_piln[i]]; st[ 6] = ROTL64(st[ 9], 20);
st[keccakf_piln[i]] = ROTL64(t, keccakf_rotc[i]); st[ 9] = ROTL64(st[22], 61);
t = bc[0]; st[22] = ROTL64(st[14], 39);
} st[14] = ROTL64(st[20], 18);
st[20] = ROTL64(st[ 2], 62);
st[ 2] = ROTL64(st[12], 43);
st[12] = ROTL64(st[13], 25);
st[13] = ROTL64(st[19], 8);
st[19] = ROTL64(st[23], 56);
st[23] = ROTL64(st[15], 41);
st[15] = ROTL64(st[ 4], 27);
st[ 4] = ROTL64(st[24], 14);
st[24] = ROTL64(st[21], 2);
st[21] = ROTL64(st[ 8], 55);
st[ 8] = ROTL64(st[16], 45);
st[16] = ROTL64(st[ 5], 36);
st[ 5] = ROTL64(st[ 3], 28);
st[ 3] = ROTL64(st[18], 21);
st[18] = ROTL64(st[17], 15);
st[17] = ROTL64(st[11], 10);
st[11] = ROTL64(st[ 7], 6);
st[ 7] = ROTL64(st[10], 3);
st[10] = ROTL64(t, 1);
// Chi // Chi
for (j = 0; j < 25; j += 5) { // unrolled loop, where only last iteration is different
j = 0;
bc[0] = st[j ];
bc[1] = st[j + 1];
st[j ] ^= (~st[j + 1]) & st[j + 2];
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
st[j + 3] ^= (~st[j + 4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
j = 5;
bc[0] = st[j ];
bc[1] = st[j + 1];
st[j ] ^= (~st[j + 1]) & st[j + 2];
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
st[j + 3] ^= (~st[j + 4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
j = 10;
bc[0] = st[j ];
bc[1] = st[j + 1];
st[j ] ^= (~st[j + 1]) & st[j + 2];
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
st[j + 3] ^= (~st[j + 4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
j = 15;
bc[0] = st[j ];
bc[1] = st[j + 1];
st[j ] ^= (~st[j + 1]) & st[j + 2];
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
st[j + 3] ^= (~st[j + 4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
j = 20;
bc[0] = st[j ]; bc[0] = st[j ];
bc[1] = st[j + 1]; bc[1] = st[j + 1];
bc[2] = st[j + 2]; bc[2] = st[j + 2];
bc[3] = st[j + 3]; bc[3] = st[j + 3];
bc[4] = st[j + 4]; bc[4] = st[j + 4];
st[j ] ^= (~bc[1]) & bc[2]; st[j ] ^= (~bc[1]) & bc[2];
st[j + 1] ^= (~bc[2]) & bc[3]; st[j + 1] ^= (~bc[2]) & bc[3];
st[j + 2] ^= (~bc[3]) & bc[4]; st[j + 2] ^= (~bc[3]) & bc[4];
st[j + 3] ^= (~bc[4]) & bc[0]; st[j + 3] ^= (~bc[4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1]; st[j + 4] ^= (~bc[0]) & bc[1];
}
// Iota // Iota
st[0] ^= keccakf_rndc[round]; st[0] ^= keccakf_rndc[round];
@@ -121,3 +169,8 @@ void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen)
memcpy(md, st, mdlen); memcpy(md, st, mdlen);
} }
void keccak1600(const uint8_t *in, int inlen, uint8_t *md)
{
keccak(in, inlen, md, sizeof(state_t));
}

File diff suppressed because it is too large Load Diff

View File

@@ -44,4 +44,6 @@ typedef u08b_t SkeinBitSequence; /* bit stream type */
SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data, SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data,
SkeinDataLength databitlen, SkeinBitSequence *hashval); SkeinDataLength databitlen, SkeinBitSequence *hashval);
void xmr_skein(const SkeinBitSequence *data, SkeinBitSequence *hashval);
#endif /* ifndef _SKEIN_H_ */ #endif /* ifndef _SKEIN_H_ */

View File

@@ -40,7 +40,7 @@ public:
virtual void onClose(Client *client, int failures) = 0; virtual void onClose(Client *client, int failures) = 0;
virtual void onJobReceived(Client *client, const Job &job) = 0; virtual void onJobReceived(Client *client, const Job &job) = 0;
virtual void onLoginSuccess(Client *client) = 0; virtual void onLoginSuccess(Client *client) = 0;
virtual void onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) = 0; virtual void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) = 0;
}; };

View File

@@ -21,19 +21,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __ICONSOLELISTENER_H__
#include <stdlib.h> #define __ICONSOLELISTENER_H__
#include "net/Network.h"
#include "version.h"
char *Network::userAgent() class IConsoleListener
{ {
const size_t max = 128; public:
virtual ~IConsoleListener() {}
char *buf = static_cast<char*>(malloc(max)); virtual void onConsoleCommand(char command) = 0;
snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), __clang_major__, __clang_minor__, __clang_patchlevel__); };
return buf;
} #endif // __ICONSOLELISTENER_H__

View File

@@ -25,6 +25,9 @@
#define __ISTRATEGY_H__ #define __ISTRATEGY_H__
#include <stdint.h>
class JobResult; class JobResult;
@@ -34,9 +37,11 @@ public:
virtual ~IStrategy() {} virtual ~IStrategy() {}
virtual bool isActive() const = 0; virtual bool isActive() const = 0;
virtual int64_t submit(const JobResult &result) = 0;
virtual void connect() = 0; virtual void connect() = 0;
virtual void resume() = 0; virtual void resume() = 0;
virtual void submit(const JobResult &result) = 0; virtual void stop() = 0;
virtual void tick(uint64_t now) = 0;
}; };

View File

@@ -41,7 +41,7 @@ public:
virtual void onActive(Client *client) = 0; virtual void onActive(Client *client) = 0;
virtual void onJob(Client *client, const Job &job) = 0; virtual void onJob(Client *client, const Job &job) = 0;
virtual void onPause(IStrategy *strategy) = 0; virtual void onPause(IStrategy *strategy) = 0;
virtual void onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) = 0; virtual void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) = 0;
}; };

View File

@@ -27,13 +27,12 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#ifdef WIN32 #ifdef WIN32
# include <winsock2.h> # include <winsock2.h>
# include <malloc.h> # include <windows.h>
# include "3rdparty/winansi.h"
#endif #endif
#include "log/ConsoleLog.h" #include "log/ConsoleLog.h"
#include "log/Log.h" #include "log/Log.h"
@@ -41,11 +40,31 @@
ConsoleLog::ConsoleLog(bool colors) : ConsoleLog::ConsoleLog(bool colors) :
m_colors(colors) m_colors(colors)
{ {
if (uv_tty_init(uv_default_loop(), &m_tty, 1, 0) < 0) {
return;
}
uv_tty_set_mode(&m_tty, UV_TTY_MODE_NORMAL);
# ifdef WIN32
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
if (handle != INVALID_HANDLE_VALUE) {
DWORD mode = 0;
if (GetConsoleMode(handle, &mode)) {
mode &= ~ENABLE_QUICK_EDIT_MODE;
SetConsoleMode(handle, mode | ENABLE_EXTENDED_FLAGS);
}
}
# endif
} }
void ConsoleLog::message(int level, const char* fmt, va_list args) void ConsoleLog::message(int level, const char* fmt, va_list args)
{ {
if (!isWritable()) {
return;
}
time_t now = time(nullptr); time_t now = time(nullptr);
tm stime; tm stime;
@@ -80,8 +99,7 @@ void ConsoleLog::message(int level, const char* fmt, va_list args)
} }
} }
const size_t len = 64 + strlen(fmt) + 2; char *buf = new char[64 + strlen(fmt) + 2];
char *buf = static_cast<char *>(alloca(len));
sprintf(buf, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s\n", sprintf(buf, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s\n",
stime.tm_year + 1900, stime.tm_year + 1900,
@@ -95,18 +113,44 @@ void ConsoleLog::message(int level, const char* fmt, va_list args)
m_colors ? Log::kCL_N : "" m_colors ? Log::kCL_N : ""
); );
vfprintf(stdout, buf, args); print(buf, args);
fflush(stdout);
} }
void ConsoleLog::text(const char* fmt, va_list args) void ConsoleLog::text(const char* fmt, va_list args)
{ {
const int len = 64 + strlen(fmt) + 2; if (!isWritable()) {
char *buf = static_cast<char *>(alloca(len)); return;
}
char *buf = new char[64 + strlen(fmt) + 2];
sprintf(buf, "%s%s\n", fmt, m_colors ? Log::kCL_N : ""); sprintf(buf, "%s%s\n", fmt, m_colors ? Log::kCL_N : "");
vfprintf(stdout, buf, args); print(buf, args);
fflush(stdout); }
bool ConsoleLog::isWritable() const
{
return uv_is_writable(reinterpret_cast<const uv_stream_t*>(&m_tty)) == 1 && uv_guess_handle(1) == UV_TTY;
}
void ConsoleLog::print(char *fmt, va_list args)
{
vsnprintf(m_buf, sizeof(m_buf) - 1, fmt, args);
delete [] fmt;
uv_buf_t buf;
buf.base = strdup(m_buf);
buf.len = strlen(buf.base);
uv_write_t *req = new uv_write_t;
req->data = buf.base;
uv_write(req, reinterpret_cast<uv_stream_t*>(&m_tty), &buf, 1, [](uv_write_t *req, int status) {
free(req->data);
delete req;
});
} }

View File

@@ -25,6 +25,9 @@
#define __CONSOLELOG_H__ #define __CONSOLELOG_H__
#include <uv.h>
#include "interfaces/ILogBackend.h" #include "interfaces/ILogBackend.h"
@@ -37,7 +40,12 @@ public:
void text(const char *fmt, va_list args) override; void text(const char *fmt, va_list args) override;
private: private:
bool isWritable() const;
void print(char *fmt, va_list args);
bool m_colors; bool m_colors;
char m_buf[512];
uv_tty_t m_tty;
}; };
#endif /* __CONSOLELOG_H__ */ #endif /* __CONSOLELOG_H__ */

View File

@@ -28,13 +28,6 @@
#include <time.h> #include <time.h>
#ifdef WIN32
# include <winsock2.h>
# include <malloc.h>
# include "3rdparty/winansi.h"
#endif
#include "log/FileLog.h" #include "log/FileLog.h"
@@ -95,7 +88,7 @@ void FileLog::onWrite(uv_fs_t *req)
void FileLog::write(char *data, size_t size) void FileLog::write(char *data, size_t size)
{ {
uv_buf_t buf = uv_buf_init(data, size); uv_buf_t buf = uv_buf_init(data, (unsigned int) size);
uv_fs_t *req = static_cast<uv_fs_t*>(malloc(sizeof(uv_fs_t))); uv_fs_t *req = static_cast<uv_fs_t*>(malloc(sizeof(uv_fs_t)));
req->data = buf.base; req->data = buf.base;

View File

@@ -28,12 +28,6 @@
#include <time.h> #include <time.h>
#ifdef WIN32
# include <winsock2.h>
# include <malloc.h>
# include "3rdparty/winansi.h"
#endif
#include "interfaces/ILogBackend.h" #include "interfaces/ILogBackend.h"
#include "log/Log.h" #include "log/Log.h"

View File

@@ -77,10 +77,14 @@ private:
#ifdef APP_DEBUG #ifdef APP_DEBUG
# define LOG_DEBUG(x, ...) Log::i()->message(Log::DEBUG, x, ##__VA_ARGS__) # define LOG_DEBUG(x, ...) Log::i()->message(Log::DEBUG, x, ##__VA_ARGS__)
#else
# define LOG_DEBUG(x, ...)
#endif
#if defined(APP_DEBUG) || defined(APP_DEVEL)
# define LOG_DEBUG_ERR(x, ...) Log::i()->message(Log::ERR, x, ##__VA_ARGS__) # define LOG_DEBUG_ERR(x, ...) Log::i()->message(Log::ERR, x, ##__VA_ARGS__)
# define LOG_DEBUG_WARN(x, ...) Log::i()->message(Log::WARNING, x, ##__VA_ARGS__) # define LOG_DEBUG_WARN(x, ...) Log::i()->message(Log::WARNING, x, ##__VA_ARGS__)
#else #else
# define LOG_DEBUG(x, ...)
# define LOG_DEBUG_ERR(x, ...) # define LOG_DEBUG_ERR(x, ...)
# define LOG_DEBUG_WARN(x, ...) # define LOG_DEBUG_WARN(x, ...)
#endif #endif

View File

@@ -21,23 +21,32 @@
* 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 <inttypes.h>
#include <iterator> #include <iterator>
#include <string.h>
#include <utility> #include <utility>
#include "log/Log.h" #include "log/Log.h"
#include "interfaces/IClientListener.h" #include "interfaces/IClientListener.h"
#include "net/Client.h" #include "net/Client.h"
#include "net/JobResult.h"
#include "net/Url.h" #include "net/Url.h"
#ifdef XMRIG_PROXY_PROJECT
# include "proxy/JobResult.h"
#else
# include "net/JobResult.h"
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
# define strncasecmp(x,y,z) _strnicmp(x,y,z) # define strncasecmp(x,y,z) _strnicmp(x,y,z)
#endif #endif
int64_t Client::m_sequence = 1;
Client::Client(int id, const char *agent, IClientListener *listener) : Client::Client(int id, const char *agent, IClientListener *listener) :
m_quiet(false), m_quiet(false),
m_agent(agent), m_agent(agent),
@@ -45,16 +54,16 @@ Client::Client(int id, const char *agent, IClientListener *listener) :
m_id(id), m_id(id),
m_retryPause(5000), m_retryPause(5000),
m_failures(0), m_failures(0),
m_sequence(1),
m_recvBufPos(0), m_recvBufPos(0),
m_state(UnconnectedState), m_state(UnconnectedState),
m_expire(0),
m_stream(nullptr), m_stream(nullptr),
m_socket(nullptr) m_socket(nullptr)
{ {
memset(m_ip, 0, sizeof(m_ip)); memset(m_ip, 0, sizeof(m_ip));
memset(&m_hints, 0, sizeof(m_hints)); memset(&m_hints, 0, sizeof(m_hints));
m_resolver.data = m_responseTimer.data = m_retriesTimer.data = m_keepAliveTimer.data = this; m_resolver.data = this;
m_hints.ai_family = PF_INET; m_hints.ai_family = PF_INET;
m_hints.ai_socktype = SOCK_STREAM; m_hints.ai_socktype = SOCK_STREAM;
@@ -63,10 +72,10 @@ Client::Client(int id, const char *agent, IClientListener *listener) :
m_recvBuf.base = static_cast<char*>(malloc(kRecvBufSize)); m_recvBuf.base = static_cast<char*>(malloc(kRecvBufSize));
m_recvBuf.len = kRecvBufSize; m_recvBuf.len = kRecvBufSize;
auto loop = uv_default_loop(); # ifndef XMRIG_PROXY_PROJECT
uv_timer_init(loop, &m_retriesTimer); m_keepAliveTimer.data = this;
uv_timer_init(loop, &m_responseTimer); uv_timer_init(uv_default_loop(), &m_keepAliveTimer);
uv_timer_init(loop, &m_keepAliveTimer); # endif
} }
@@ -77,6 +86,34 @@ Client::~Client()
} }
/**
* @brief Send raw data to server.
*
* @param data
*/
int64_t Client::send(char *data, size_t size)
{
LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size ? size : strlen(data), data);
if (state() != ConnectedState || !uv_is_writable(m_stream)) {
LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state);
return -1;
}
uv_buf_t buf = uv_buf_init(data, (unsigned int) (size ? size : strlen(data)));
uv_write_t *req = new uv_write_t;
req->data = buf.base;
uv_write(req, m_stream, &buf, 1, [](uv_write_t *req, int status) {
free(req->data);
delete req;
});
m_expire = uv_now(uv_default_loop()) + kResponseTimeout;
return m_sequence++;
}
void Client::connect() void Client::connect()
{ {
resolve(m_url.host()); resolve(m_url.host());
@@ -97,41 +134,17 @@ void Client::connect(const Url *url)
void Client::disconnect() void Client::disconnect()
{ {
uv_timer_stop(&m_retriesTimer); # ifndef XMRIG_PROXY_PROJECT
uv_timer_stop(&m_keepAliveTimer);
# endif
m_expire = 0;
m_failures = -1; m_failures = -1;
close(); close();
} }
/**
* @brief Send raw data to server.
*
* @param data
*/
void Client::send(char *data)
{
LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), strlen(data), data);
if (state() != ConnectedState) {
LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state);
return;
}
m_sequence++;
uv_buf_t buf = uv_buf_init(data, strlen(data));
uv_write_t *req = static_cast<uv_write_t*>(malloc(sizeof(uv_write_t)));
req->data = buf.base;
uv_write(req, m_stream, &buf, 1, [](uv_write_t *req, int status) {
free(req->data);
free(req);
});
uv_timer_start(&m_responseTimer, [](uv_timer_t *handle) { getClient(handle->data)->close(); }, kResponseTimeout, 0);
}
void Client::setUrl(const Url *url) void Client::setUrl(const Url *url)
{ {
if (!url || !url->isValid()) { if (!url || !url->isValid()) {
@@ -142,9 +155,32 @@ void Client::setUrl(const Url *url)
} }
void Client::submit(const JobResult &result) void Client::tick(uint64_t now)
{
if (m_expire == 0 || now < m_expire) {
return;
}
if (m_state == ConnectedState) {
LOG_DEBUG_ERR("[%s:%u] timeout", m_url.host(), m_url.port());
close();
}
if (m_state == ConnectingState) {
connect();
}
}
int64_t Client::submit(const JobResult &result)
{ {
char *req = static_cast<char*>(malloc(345)); char *req = static_cast<char*>(malloc(345));
# ifdef XMRIG_PROXY_PROJECT
const char *nonce = result.nonce;
const char *data = result.result;
# else
char nonce[9]; char nonce[9];
char data[65]; char data[65];
@@ -153,12 +189,35 @@ void Client::submit(const JobResult &result)
Job::toHex(result.result, 32, data); Job::toHex(result.result, 32, data);
data[64] = '\0'; data[64] = '\0';
# endif
snprintf(req, 345, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"}}\n", snprintf(req, 345, "{\"id\":%" PRIu64 ",\"jsonrpc\":\"2.0\",\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"}}\n",
m_sequence, m_rpcId, result.jobId, nonce, data); m_sequence, m_rpcId, result.jobId, nonce, data);
m_results[m_sequence] = SubmitResult(result.diff); m_results[m_sequence] = SubmitResult(m_sequence, result.diff);
send(req); return send(req);
}
bool Client::isCriticalError(const char *message)
{
if (!message) {
return false;
}
if (strncasecmp(message, "Unauthenticated", 15) == 0) {
return true;
}
if (strncasecmp(message, "your IP is banned", 17) == 0) {
return true;
}
if (strncasecmp(message, "IP Address currently banned", 27) == 0) {
return true;
}
return false;
} }
@@ -191,8 +250,6 @@ bool Client::parseJob(const json_t *params, int *code)
} }
m_job = std::move(job); m_job = std::move(job);
LOG_DEBUG("[%s:%u] job: \"%s\", diff: %lld", m_url.host(), m_url.port(), job.id(), job.diff());
return true; return true;
} }
@@ -216,6 +273,7 @@ int Client::resolve(const char *host)
{ {
setState(HostLookupState); setState(HostLookupState);
m_expire = 0;
m_recvBufPos = 0; m_recvBufPos = 0;
if (m_failures == -1) { if (m_failures == -1) {
@@ -241,8 +299,11 @@ void Client::close()
} }
setState(ClosingState); setState(ClosingState);
if (uv_is_closing(reinterpret_cast<uv_handle_t*>(m_socket)) == 0) {
uv_close(reinterpret_cast<uv_handle_t*>(m_socket), Client::onClose); uv_close(reinterpret_cast<uv_handle_t*>(m_socket), Client::onClose);
} }
}
void Client::connect(struct sockaddr *addr) void Client::connect(struct sockaddr *addr)
@@ -265,20 +326,34 @@ void Client::connect(struct sockaddr *addr)
uv_tcp_keepalive(m_socket, 1, 60); uv_tcp_keepalive(m_socket, 1, 60);
# endif # endif
uv_tcp_connect(req, m_socket, (const sockaddr*) addr, Client::onConnect); uv_tcp_connect(req, m_socket, reinterpret_cast<const sockaddr*>(addr), Client::onConnect);
} }
void Client::login() void Client::login()
{ {
m_sequence = 1;
m_results.clear(); m_results.clear();
const size_t size = 96 + strlen(m_url.user()) + strlen(m_url.password()) + strlen(m_agent); json_t *req = json_object();
char *req = static_cast<char*>(malloc(size)); json_object_set(req, "id", json_integer(1));
snprintf(req, size, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"%s\"}}\n", m_sequence, m_url.user(), m_url.password(), m_agent); json_object_set(req, "jsonrpc", json_string("2.0"));
json_object_set(req, "method", json_string("login"));
send(req); json_t *params = json_object();
json_object_set(params, "login", json_string(m_url.user()));
json_object_set(params, "pass", json_string(m_url.password()));
json_object_set(params, "agent", json_string(m_agent));
json_object_set(req, "params", params);
char *buf = json_dumps(req, JSON_COMPACT);
const size_t size = strlen(buf);
buf[size] = '\n';
json_decref(req);
send(buf, size + 1);
} }
@@ -316,7 +391,7 @@ void Client::parseNotification(const char *method, const json_t *params, const j
{ {
if (json_is_object(error)) { if (json_is_object(error)) {
if (!m_quiet) { if (!m_quiet) {
LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_url.host(), m_url.port(), json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code"))); LOG_ERR("[%s:%u] error: \"%s\", code: %" PRId64, m_url.host(), m_url.port(), json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code")));
} }
return; return;
} }
@@ -345,14 +420,14 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error
auto it = m_results.find(id); auto it = m_results.find(id);
if (it != m_results.end()) { if (it != m_results.end()) {
m_listener->onResultAccepted(this, it->second.diff, it->second.elapsed(), message); m_listener->onResultAccepted(this, it->second.seq, it->second.diff, it->second.elapsed(), message);
m_results.erase(it); m_results.erase(it);
} }
else if (!m_quiet) { else if (!m_quiet) {
LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_url.host(), m_url.port(), message, json_integer_value(json_object_get(error, "code"))); LOG_ERR("[%s:%u] error: \"%s\", code: %" PRId64, m_url.host(), m_url.port(), message, json_integer_value(json_object_get(error, "code")));
} }
if (id == 1 || (message && strncasecmp(message, "Unauthenticated", 15) == 0)) { if (id == 1 || isCriticalError(message)) {
close(); close();
} }
@@ -381,7 +456,7 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error
auto it = m_results.find(id); auto it = m_results.find(id);
if (it != m_results.end()) { if (it != m_results.end()) {
m_listener->onResultAccepted(this, it->second.diff, it->second.elapsed(), nullptr); m_listener->onResultAccepted(this, it->second.seq, it->second.diff, it->second.elapsed(), nullptr);
m_results.erase(it); m_results.erase(it);
} }
} }
@@ -389,8 +464,8 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error
void Client::ping() void Client::ping()
{ {
char *req = static_cast<char*>(malloc(128)); char *req = static_cast<char*>(malloc(160));
snprintf(req, 128, "{\"id\":%lld,\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId); snprintf(req, 160, "{\"id\":%" PRId64 ",\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId);
send(req); send(req);
} }
@@ -400,19 +475,20 @@ void Client::reconnect()
{ {
setState(ConnectingState); setState(ConnectingState);
uv_timer_stop(&m_responseTimer); # ifndef XMRIG_PROXY_PROJECT
if (m_url.isKeepAlive()) { if (m_url.isKeepAlive()) {
uv_timer_stop(&m_keepAliveTimer); uv_timer_stop(&m_keepAliveTimer);
} }
# endif
if (m_failures == -1) { if (m_failures == -1) {
return m_listener->onClose(this, -1); return m_listener->onClose(this, -1);
} }
m_failures++; m_failures++;
m_listener->onClose(this, m_failures); m_listener->onClose(this, (int) m_failures);
uv_timer_start(&m_retriesTimer, [](uv_timer_t *handle) { getClient(handle->data)->connect(); }, m_retryPause, 0); m_expire = uv_now(uv_default_loop()) + m_retryPause;
} }
@@ -430,12 +506,15 @@ void Client::setState(SocketState state)
void Client::startTimeout() void Client::startTimeout()
{ {
uv_timer_stop(&m_responseTimer); m_expire = 0;
# ifndef XMRIG_PROXY_PROJECT
if (!m_url.isKeepAlive()) { if (!m_url.isKeepAlive()) {
return; return;
} }
uv_timer_start(&m_keepAliveTimer, [](uv_timer_t *handle) { getClient(handle->data)->ping(); }, kKeepAliveTimeout, 0); uv_timer_start(&m_keepAliveTimer, [](uv_timer_t *handle) { getClient(handle->data)->ping(); }, kKeepAliveTimeout, 0);
# endif
} }
@@ -491,12 +570,16 @@ void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
auto client = getClient(stream->data); auto client = getClient(stream->data);
if (nread < 0) { if (nread < 0) {
if (nread != UV_EOF && !client->m_quiet) { if (nread != UV_EOF && !client->m_quiet) {
LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(nread)); LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) nread));
} }
return client->close();; return client->close();;
} }
if ((size_t) nread > (kRecvBufSize - 8 - client->m_recvBufPos)) {
return client->close();;
}
client->m_recvBufPos += nread; client->m_recvBufPos += nread;
char* end; char* end;
@@ -534,8 +617,26 @@ void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res)
return client->reconnect();; return client->reconnect();;
} }
uv_ip4_name(reinterpret_cast<sockaddr_in*>(res->ai_addr), client->m_ip, 16); addrinfo *ptr = res;
std::vector<addrinfo*> ipv4;
client->connect(res->ai_addr); while (ptr != nullptr) {
if (ptr->ai_family == AF_INET) {
ipv4.push_back(ptr);
}
ptr = ptr->ai_next;
}
if (ipv4.empty()) {
LOG_ERR("[%s:%u] DNS error: \"No IPv4 records found\"", client->m_url.host(), client->m_url.port());
return client->reconnect();
}
ptr = ipv4[rand() % ipv4.size()];
uv_ip4_name(reinterpret_cast<sockaddr_in*>(ptr->ai_addr), client->m_ip, 16);
client->connect(ptr->ai_addr);
uv_freeaddrinfo(res); uv_freeaddrinfo(res);
} }

View File

@@ -56,12 +56,13 @@ public:
Client(int id, const char *agent, IClientListener *listener); Client(int id, const char *agent, IClientListener *listener);
~Client(); ~Client();
int64_t send(char *data, size_t size = 0);
int64_t submit(const JobResult &result);
void connect(); void connect();
void connect(const Url *url); void connect(const Url *url);
void disconnect(); void disconnect();
void send(char *data);
void setUrl(const Url *url); void setUrl(const Url *url);
void submit(const JobResult &result); void tick(uint64_t now);
inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; }
inline const char *host() const { return m_url.host(); } inline const char *host() const { return m_url.host(); }
@@ -76,6 +77,7 @@ public:
private: private:
constexpr static size_t kRecvBufSize = 4096; constexpr static size_t kRecvBufSize = 4096;
bool isCriticalError(const char *message);
bool parseJob(const json_t *params, int *code); bool parseJob(const json_t *params, int *code);
bool parseLogin(const json_t *result, int *code); bool parseLogin(const json_t *result, int *code);
int resolve(const char *host); int resolve(const char *host);
@@ -98,6 +100,7 @@ private:
static inline Client *getClient(void *data) { return static_cast<Client*>(data); } static inline Client *getClient(void *data) { return static_cast<Client*>(data); }
addrinfo m_hints;
bool m_quiet; bool m_quiet;
char m_ip[17]; char m_ip[17];
char m_rpcId[64]; char m_rpcId[64];
@@ -106,20 +109,21 @@ private:
int m_id; int m_id;
int m_retryPause; int m_retryPause;
int64_t m_failures; int64_t m_failures;
int64_t m_sequence;
Job m_job; Job m_job;
size_t m_recvBufPos; size_t m_recvBufPos;
SocketState m_state; SocketState m_state;
static int64_t m_sequence;
std::map<int64_t, SubmitResult> m_results; std::map<int64_t, SubmitResult> m_results;
struct addrinfo m_hints; uint64_t m_expire;
Url m_url; Url m_url;
uv_buf_t m_recvBuf; uv_buf_t m_recvBuf;
uv_getaddrinfo_t m_resolver; uv_getaddrinfo_t m_resolver;
uv_stream_t *m_stream; uv_stream_t *m_stream;
uv_tcp_t *m_socket; uv_tcp_t *m_socket;
# ifndef XMRIG_PROXY_PROJECT
uv_timer_t m_keepAliveTimer; uv_timer_t m_keepAliveTimer;
uv_timer_t m_responseTimer; # endif
uv_timer_t m_retriesTimer;
}; };

View File

@@ -82,7 +82,7 @@ bool Job::setBlob(const char *blob)
return false; return false;
} }
if (!fromHex(blob, m_size * 2, m_blob)) { if (!fromHex(blob, (int) m_size * 2, m_blob)) {
return false; return false;
} }
@@ -90,6 +90,11 @@ bool Job::setBlob(const char *blob)
m_nicehash = true; m_nicehash = true;
} }
# ifdef XMRIG_PROXY_PROJECT
memset(m_rawBlob, 0, sizeof(m_rawBlob));
memcpy(m_rawBlob, blob, m_size * 2);
# endif
return true; return true;
} }
@@ -138,6 +143,11 @@ bool Job::setTarget(const char *target)
return false; return false;
} }
# ifdef XMRIG_PROXY_PROJECT
memset(m_rawTarget, 0, sizeof(m_rawTarget));
memcpy(m_rawTarget, target, len);
# endif
m_diff = toDiff(m_target); m_diff = toDiff(m_target);
return true; return true;
} }

View File

@@ -42,14 +42,20 @@ public:
inline bool isNicehash() const { return m_nicehash; } inline bool isNicehash() const { return m_nicehash; }
inline bool isValid() const { return m_size > 0 && m_diff > 0; } inline bool isValid() const { return m_size > 0 && m_diff > 0; }
inline const char *id() const { return m_id; } inline const char *id() const { return m_id; }
inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + 39); }
inline const uint8_t *blob() const { return m_blob; } inline const uint8_t *blob() const { return m_blob; }
inline int poolId() const { return m_poolId; } inline int poolId() const { return m_poolId; }
inline size_t size() const { return m_size; }
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); } inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); }
inline uint32_t diff() const { return m_diff; } inline uint32_t diff() const { return (uint32_t) m_diff; }
inline uint32_t size() const { return m_size; }
inline uint64_t target() const { return m_target; } inline uint64_t target() const { return m_target; }
inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } inline void setNicehash(bool nicehash) { m_nicehash = nicehash; }
# ifdef XMRIG_PROXY_PROJECT
inline char *rawBlob() { return m_rawBlob; }
inline const char *rawTarget() const { return m_rawTarget; }
# endif
static bool fromHex(const char* in, unsigned int len, unsigned char* out); static bool fromHex(const char* in, unsigned int len, unsigned char* out);
static inline uint32_t *nonce(uint8_t *blob) { return reinterpret_cast<uint32_t*>(blob + 39); } static inline uint32_t *nonce(uint8_t *blob) { return reinterpret_cast<uint32_t*>(blob + 39); }
static inline uint64_t toDiff(uint64_t target) { return 0xFFFFFFFFFFFFFFFFULL / target; } static inline uint64_t toDiff(uint64_t target) { return 0xFFFFFFFFFFFFFFFFULL / target; }
@@ -62,9 +68,14 @@ private:
int m_poolId; int m_poolId;
VAR_ALIGN(16, char m_id[64]); VAR_ALIGN(16, char m_id[64]);
VAR_ALIGN(16, uint8_t m_blob[84]); // Max blob size is 84 (75 fixed + 9 variable), aligned to 96. https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk. VAR_ALIGN(16, uint8_t m_blob[84]); // Max blob size is 84 (75 fixed + 9 variable), aligned to 96. https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk.
uint32_t m_size; size_t m_size;
uint64_t m_diff; uint64_t m_diff;
uint64_t m_target; uint64_t m_target;
# ifdef XMRIG_PROXY_PROJECT
VAR_ALIGN(16, char m_rawBlob[169]);
VAR_ALIGN(16, char m_rawTarget[17]);
# endif
}; };
#endif /* __JOB_H__ */ #endif /* __JOB_H__ */

View File

@@ -43,6 +43,15 @@ public:
} }
inline JobResult(const Job &job) : poolId(0), diff(0), nonce(0)
{
memcpy(jobId, job.id(), sizeof(jobId));
poolId = job.poolId();
diff = job.diff();
nonce = *job.nonce();
}
inline JobResult &operator=(const Job &job) { inline JobResult &operator=(const Job &job) {
memcpy(jobId, job.id(), sizeof(jobId)); memcpy(jobId, job.id(), sizeof(jobId));
poolId = job.poolId(); poolId = job.poolId();

View File

@@ -21,8 +21,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef _MSC_VER
#pragma warning(disable:4244)
#endif
#include <inttypes.h>
#include <memory> #include <memory>
#include <time.h>
#include "log/Log.h" #include "log/Log.h"
@@ -33,37 +38,42 @@
#include "net/strategies/SinglePoolStrategy.h" #include "net/strategies/SinglePoolStrategy.h"
#include "net/Url.h" #include "net/Url.h"
#include "Options.h" #include "Options.h"
#include "Platform.h"
#include "workers/Workers.h" #include "workers/Workers.h"
Network::Network(const Options *options) : Network::Network(const Options *options) :
m_donateActive(false),
m_options(options), m_options(options),
m_donate(nullptr), m_donate(nullptr),
m_accepted(0), m_accepted(0),
m_rejected(0) m_rejected(0)
{ {
srand(time(0) ^ (uintptr_t) this);
Workers::setListener(this); Workers::setListener(this);
m_agent = userAgent();
const std::vector<Url*> &pools = options->pools(); const std::vector<Url*> &pools = options->pools();
if (pools.size() > 1) { if (pools.size() > 1) {
m_strategy = new FailoverStrategy(pools, m_agent, this); m_strategy = new FailoverStrategy(pools, Platform::userAgent(), this);
} }
else { else {
m_strategy = new SinglePoolStrategy(pools.front(), m_agent, this); m_strategy = new SinglePoolStrategy(pools.front(), Platform::userAgent(), this);
} }
if (m_options->donateLevel() > 0) { if (m_options->donateLevel() > 0) {
m_donate = new DonateStrategy(m_agent, this); m_donate = new DonateStrategy(Platform::userAgent(), this);
} }
m_timer.data = this;
uv_timer_init(uv_default_loop(), &m_timer);
uv_timer_start(&m_timer, Network::onTick, kTickInterval, kTickInterval);
} }
Network::~Network() Network::~Network()
{ {
free(m_agent);
} }
@@ -73,6 +83,16 @@ void Network::connect()
} }
void Network::stop()
{
if (m_donate) {
m_donate->stop();
}
m_strategy->stop();
}
void Network::onActive(Client *client) void Network::onActive(Client *client)
{ {
if (client->id() == -1) { if (client->id() == -1) {
@@ -97,7 +117,8 @@ void Network::onJob(Client *client, const Job &job)
void Network::onJobResult(const JobResult &result) void Network::onJobResult(const JobResult &result)
{ {
if (result.poolId == -1 && m_donate) { if (result.poolId == -1 && m_donate) {
return m_donate->submit(result); m_donate->submit(result);
return;
} }
m_strategy->submit(result); m_strategy->submit(result);
@@ -112,23 +133,27 @@ void Network::onPause(IStrategy *strategy)
} }
if (!m_strategy->isActive()) { if (!m_strategy->isActive()) {
LOG_ERR("no active pools, pause mining"); LOG_ERR("no active pools, stop mining");
return Workers::pause(); return Workers::pause();
} }
} }
void Network::onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) void Network::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
{ {
if (error) { if (error) {
m_rejected++; m_rejected++;
LOG_INFO(m_options->colors() ? "\x1B[01;31mrejected\x1B[0m (%lld/%lld) diff \x1B[01;37m%u\x1B[0m \x1B[31m\"%s\"\x1B[0m \x1B[01;30m(%llu ms)" : "accepted (%lld/%lld) diff %u \"%s\" (%llu ms)", m_accepted, m_rejected, diff, error, ms); LOG_INFO(m_options->colors() ? "\x1B[01;31mrejected\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[31m\"%s\"\x1B[0m \x1B[01;30m(%" PRIu64 " ms)"
: "rejected (%" PRId64 "/%" PRId64 ") diff %u \"%s\" (%" PRIu64 " ms)",
m_accepted, m_rejected, diff, error, ms);
} }
else { else {
m_accepted++; m_accepted++;
LOG_INFO(m_options->colors() ? "\x1B[01;32maccepted\x1B[0m (%lld/%lld) diff \x1B[01;37m%u\x1B[0m \x1B[01;30m(%llu ms)" : "accepted (%lld/%lld) diff %u (%llu ms)", m_accepted, m_rejected, diff, ms); LOG_INFO(m_options->colors() ? "\x1B[01;32maccepted\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[01;30m(%" PRIu64 " ms)"
: "accepted (%" PRId64 "/%" PRId64 ") diff %u (%" PRIu64 " ms)",
m_accepted, m_rejected, diff, ms);
} }
} }
@@ -145,3 +170,21 @@ void Network::setJob(Client *client, const Job &job)
Workers::setJob(job); Workers::setJob(job);
} }
void Network::tick()
{
const uint64_t now = uv_now(uv_default_loop());
m_strategy->tick(now);
if (m_donate) {
m_donate->tick(now);
}
}
void Network::onTick(uv_timer_t *handle)
{
static_cast<Network*>(handle->data)->tick();
}

View File

@@ -45,26 +45,29 @@ public:
~Network(); ~Network();
void connect(); void connect();
void stop();
static char *userAgent();
protected: protected:
void onActive(Client *client) override; void onActive(Client *client) override;
void onJob(Client *client, const Job &job) override; void onJob(Client *client, const Job &job) override;
void onJobResult(const JobResult &result) override; void onJobResult(const JobResult &result) override;
void onPause(IStrategy *strategy) override; void onPause(IStrategy *strategy) override;
void onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) override; void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
private: private:
void setJob(Client *client, const Job &job); constexpr static int kTickInterval = 1 * 1000;
void setJob(Client *client, const Job &job);
void tick();
static void onTick(uv_timer_t *handle);
bool m_donateActive;
char *m_agent;
const Options *m_options; const Options *m_options;
IStrategy *m_donate; IStrategy *m_donate;
IStrategy *m_strategy; IStrategy *m_strategy;
uint64_t m_accepted; uint64_t m_accepted;
uint64_t m_rejected; uint64_t m_rejected;
uv_timer_t m_timer;
}; };

View File

@@ -31,8 +31,9 @@
class SubmitResult class SubmitResult
{ {
public: public:
inline SubmitResult() : diff(0), start(0) {} inline SubmitResult() : seq(0), diff(0), start(0) {}
inline SubmitResult(uint32_t diff) : inline SubmitResult(int64_t seq, uint32_t diff) :
seq(seq),
diff(diff) diff(diff)
{ {
start = uv_hrtime(); start = uv_hrtime();
@@ -40,6 +41,7 @@ public:
inline uint64_t elapsed() const { return (uv_hrtime() - start) / 1000000; } inline uint64_t elapsed() const { return (uv_hrtime() - start) / 1000000; }
int64_t seq;
uint32_t diff; uint32_t diff;
uint64_t start; uint64_t start;
}; };

View File

@@ -121,7 +121,7 @@ bool Url::parse(const char *url)
memcpy(m_host, base, size - 1); memcpy(m_host, base, size - 1);
m_host[size - 1] = '\0'; m_host[size - 1] = '\0';
m_port = strtol(port, nullptr, 10); m_port = (uint16_t) strtol(port, nullptr, 10);
return true; return true;
} }

View File

@@ -24,17 +24,31 @@
#include "interfaces/IStrategyListener.h" #include "interfaces/IStrategyListener.h"
#include "net/Client.h" #include "net/Client.h"
#include "net/Job.h"
#include "net/strategies/DonateStrategy.h" #include "net/strategies/DonateStrategy.h"
#include "Options.h" #include "Options.h"
extern "C"
{
#include "crypto/c_keccak.h"
}
DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) : DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) :
m_active(false), m_active(false),
m_donateTime(Options::i()->donateLevel() * 60 * 1000), m_donateTime(Options::i()->donateLevel() * 60 * 1000),
m_idleTime((100 - Options::i()->donateLevel()) * 60 * 1000), m_idleTime((100 - Options::i()->donateLevel()) * 60 * 1000),
m_listener(listener) m_listener(listener)
{ {
Url *url = new Url("donate2.xmrig.com", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443, Options::i()->pools().front()->user()); uint8_t hash[200];
char userId[65] = { 0 };
const char *user = Options::i()->pools().front()->user();
keccak(reinterpret_cast<const uint8_t *>(user), static_cast<int>(strlen(user)), hash, sizeof(hash));
Job::toHex(hash, 32, userId);
Url *url = new Url("fee.xmrig.com", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443, userId, nullptr, false, true);
m_client = new Client(-1, agent, this); m_client = new Client(-1, agent, this);
m_client->setUrl(url); m_client->setUrl(url);
@@ -50,15 +64,28 @@ DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) :
} }
int64_t DonateStrategy::submit(const JobResult &result)
{
return m_client->submit(result);
}
void DonateStrategy::connect() void DonateStrategy::connect()
{ {
m_client->connect(); m_client->connect();
} }
void DonateStrategy::submit(const JobResult &result) void DonateStrategy::stop()
{ {
m_client->submit(result); uv_timer_stop(&m_timer);
m_client->disconnect();
}
void DonateStrategy::tick(uint64_t now)
{
m_client->tick(now);
} }
@@ -84,9 +111,9 @@ void DonateStrategy::onLoginSuccess(Client *client)
} }
void DonateStrategy::onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) void DonateStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
{ {
m_listener->onResultAccepted(client, diff, ms, error); m_listener->onResultAccepted(client, seq, diff, ms, error);
} }
@@ -96,7 +123,7 @@ void DonateStrategy::idle()
} }
void DonateStrategy::stop() void DonateStrategy::suspend()
{ {
m_client->disconnect(); m_client->disconnect();
@@ -115,5 +142,5 @@ void DonateStrategy::onTimer(uv_timer_t *handle)
return strategy->connect(); return strategy->connect();
} }
strategy->stop(); strategy->suspend();
} }

View File

@@ -46,18 +46,20 @@ public:
inline bool isActive() const override { return m_active; } inline bool isActive() const override { return m_active; }
inline void resume() override {} inline void resume() override {}
int64_t submit(const JobResult &result) override;
void connect() override; void connect() override;
void submit(const JobResult &result) override; void stop() override;
void tick(uint64_t now) override;
protected: protected:
void onClose(Client *client, int failures) override; void onClose(Client *client, int failures) override;
void onJobReceived(Client *client, const Job &job) override; void onJobReceived(Client *client, const Job &job) override;
void onLoginSuccess(Client *client) override; void onLoginSuccess(Client *client) override;
void onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) override; void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
private: private:
void idle(); void idle();
void stop(); void suspend();
static void onTimer(uv_timer_t *handle); static void onTimer(uv_timer_t *handle);

View File

@@ -39,6 +39,12 @@ FailoverStrategy::FailoverStrategy(const std::vector<Url*> &urls, const char *ag
} }
int64_t FailoverStrategy::submit(const JobResult &result)
{
return m_pools[m_active]->submit(result);
}
void FailoverStrategy::connect() void FailoverStrategy::connect()
{ {
m_pools[m_index]->connect(); m_pools[m_index]->connect();
@@ -55,9 +61,24 @@ void FailoverStrategy::resume()
} }
void FailoverStrategy::submit(const JobResult &result) void FailoverStrategy::stop()
{ {
m_pools[m_active]->submit(result); for (size_t i = 0; i < m_pools.size(); ++i) {
m_pools[i]->disconnect();
}
m_index = 0;
m_active = -1;
m_listener->onPause(this);
}
void FailoverStrategy::tick(uint64_t now)
{
for (Client *client : m_pools) {
client->tick(now);
}
} }
@@ -111,15 +132,15 @@ void FailoverStrategy::onLoginSuccess(Client *client)
} }
void FailoverStrategy::onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) void FailoverStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
{ {
m_listener->onResultAccepted(client, diff, ms, error); m_listener->onResultAccepted(client, seq, diff, ms, error);
} }
void FailoverStrategy::add(const Url *url, const char *agent) void FailoverStrategy::add(const Url *url, const char *agent)
{ {
Client *client = new Client(m_pools.size(), agent, this); Client *client = new Client((int) m_pools.size(), agent, this);
client->setUrl(url); client->setUrl(url);
client->setRetryPause(Options::i()->retryPause() * 1000); client->setRetryPause(Options::i()->retryPause() * 1000);

View File

@@ -45,15 +45,17 @@ public:
public: public:
inline bool isActive() const override { return m_active >= 0; } inline bool isActive() const override { return m_active >= 0; }
int64_t submit(const JobResult &result) override;
void connect() override; void connect() override;
void resume() override; void resume() override;
void submit(const JobResult &result) override; void stop() override;
void tick(uint64_t now) override;
protected: protected:
void onClose(Client *client, int failures) override; void onClose(Client *client, int failures) override;
void onJobReceived(Client *client, const Job &job) override; void onJobReceived(Client *client, const Job &job) override;
void onLoginSuccess(Client *client) override; void onLoginSuccess(Client *client) override;
void onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) override; void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
private: private:
void add(const Url *url, const char *agent); void add(const Url *url, const char *agent);

View File

@@ -38,6 +38,12 @@ SinglePoolStrategy::SinglePoolStrategy(const Url *url, const char *agent, IStrat
} }
int64_t SinglePoolStrategy::submit(const JobResult &result)
{
return m_client->submit(result);
}
void SinglePoolStrategy::connect() void SinglePoolStrategy::connect()
{ {
m_client->connect(); m_client->connect();
@@ -54,9 +60,15 @@ void SinglePoolStrategy::resume()
} }
void SinglePoolStrategy::submit(const JobResult &result) void SinglePoolStrategy::stop()
{ {
m_client->submit(result); m_client->disconnect();
}
void SinglePoolStrategy::tick(uint64_t now)
{
m_client->tick(now);
} }
@@ -84,7 +96,7 @@ void SinglePoolStrategy::onLoginSuccess(Client *client)
} }
void SinglePoolStrategy::onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) void SinglePoolStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
{ {
m_listener->onResultAccepted(client, diff, ms, error); m_listener->onResultAccepted(client, seq, diff, ms, error);
} }

View File

@@ -42,15 +42,17 @@ public:
public: public:
inline bool isActive() const override { return m_active; } inline bool isActive() const override { return m_active; }
int64_t submit(const JobResult &result) override;
void connect() override; void connect() override;
void resume() override; void resume() override;
void submit(const JobResult &result) override; void stop() override;
void tick(uint64_t now) override;
protected: protected:
void onClose(Client *client, int failures) override; void onClose(Client *client, int failures) override;
void onJobReceived(Client *client, const Job &job) override; void onJobReceived(Client *client, const Job &job) override;
void onLoginSuccess(Client *client) override; void onLoginSuccess(Client *client) override;
void onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) override; void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
private: private:
bool m_active; bool m_active;

View File

@@ -26,15 +26,15 @@
#define APP_ID "xmrig" #define APP_ID "xmrig"
#define APP_NAME "XMRig" #define APP_NAME "XMRig"
#define APP_DESC "Monero (XMR) CPU miner" #define APP_DESC "XMRig CPU miner"
#define APP_VERSION "2.0.2" #define APP_VERSION "2.3.0"
#define APP_DOMAIN "xmrig.com" #define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com" #define APP_SITE "www.xmrig.com"
#define APP_COPYRIGHT "Copyright (C) 2016-2017 xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2017 xmrig.com"
#define APP_VER_MAJOR 2 #define APP_VER_MAJOR 2
#define APP_VER_MINOR 0 #define APP_VER_MINOR 3
#define APP_VER_BUILD 2 #define APP_VER_BUILD 0
#define APP_VER_REV 0 #define APP_VER_REV 0
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@@ -62,13 +62,17 @@ DoubleWorker::~DoubleWorker()
void DoubleWorker::start() void DoubleWorker::start()
{ {
while (true) { while (Workers::sequence() > 0) {
if (Workers::isPaused()) { if (Workers::isPaused()) {
do { do {
std::this_thread::sleep_for(std::chrono::milliseconds(200)); std::this_thread::sleep_for(std::chrono::milliseconds(200));
} }
while (Workers::isPaused()); while (Workers::isPaused());
if (Workers::sequence() == 0) {
break;
}
consumeJob(); consumeJob();
} }

View File

@@ -25,7 +25,8 @@
#include "workers/Handle.h" #include "workers/Handle.h"
Handle::Handle(int threadId, int threads, int64_t affinity) : Handle::Handle(int threadId, int threads, int64_t affinity, int priority) :
m_priority(priority),
m_threadId(threadId), m_threadId(threadId),
m_threads(threads), m_threads(threads),
m_affinity(affinity), m_affinity(affinity),
@@ -34,6 +35,12 @@ Handle::Handle(int threadId, int threads, int64_t affinity) :
} }
void Handle::join()
{
uv_thread_join(&m_thread);
}
void Handle::start(void (*callback) (void *)) void Handle::start(void (*callback) (void *))
{ {
uv_thread_create(&m_thread, callback, this); uv_thread_create(&m_thread, callback, this);

View File

@@ -35,9 +35,11 @@ class IWorker;
class Handle class Handle
{ {
public: public:
Handle(int threadId, int threads, int64_t affinity); Handle(int threadId, int threads, int64_t affinity, int priority);
void join();
void start(void (*callback) (void *)); void start(void (*callback) (void *));
inline int priority() const { return m_priority; }
inline int threadId() const { return m_threadId; } inline int threadId() const { return m_threadId; }
inline int threads() const { return m_threads; } inline int threads() const { return m_threads; }
inline int64_t affinity() const { return m_affinity; } inline int64_t affinity() const { return m_affinity; }
@@ -45,6 +47,7 @@ public:
inline void setWorker(IWorker *worker) { m_worker = worker; } inline void setWorker(IWorker *worker) { m_worker = worker; }
private: private:
int m_priority;
int m_threadId; int m_threadId;
int m_threads; int m_threads;
int64_t m_affinity; int64_t m_affinity;

View File

@@ -127,8 +127,8 @@ double Hashrate::calc(size_t threadId, size_t ms) const
} }
double hashes, time; double hashes, time;
hashes = lastestHashCnt - earliestHashCount; hashes = (double) lastestHashCnt - earliestHashCount;
time = lastestStamp - earliestStamp; time = (double) lastestStamp - earliestStamp;
time /= 1000.0; time /= 1000.0;
return hashes / time; return hashes / time;
@@ -161,6 +161,12 @@ void Hashrate::print()
} }
void Hashrate::stop()
{
uv_timer_stop(&m_timer);
}
void Hashrate::updateHighest() void Hashrate::updateHighest()
{ {
double highest = calc(2500); double highest = calc(2500);

View File

@@ -37,6 +37,7 @@ public:
double calc(size_t threadId, size_t ms) const; double calc(size_t threadId, size_t ms) const;
void add(size_t threadId, uint64_t count, uint64_t timestamp); void add(size_t threadId, uint64_t count, uint64_t timestamp);
void print(); void print();
void stop();
void updateHighest(); void updateHighest();
inline double highest() const { return m_highest; } inline double highest() const { return m_highest; }

View File

@@ -38,13 +38,17 @@ SingleWorker::SingleWorker(Handle *handle)
void SingleWorker::start() void SingleWorker::start()
{ {
while (true) { while (Workers::sequence() > 0) {
if (Workers::isPaused()) { if (Workers::isPaused()) {
do { do {
std::this_thread::sleep_for(std::chrono::milliseconds(200)); std::this_thread::sleep_for(std::chrono::milliseconds(200));
} }
while (Workers::isPaused()); while (Workers::isPaused());
if (Workers::sequence() == 0) {
break;
}
consumeJob(); consumeJob();
} }

View File

@@ -26,6 +26,7 @@
#include "Cpu.h" #include "Cpu.h"
#include "Mem.h" #include "Mem.h"
#include "Platform.h"
#include "workers/Handle.h" #include "workers/Handle.h"
#include "workers/Worker.h" #include "workers/Worker.h"
@@ -42,6 +43,7 @@ Worker::Worker(Handle *handle) :
Cpu::setAffinity(m_id, handle->affinity()); Cpu::setAffinity(m_id, handle->affinity());
} }
Platform::setThreadPriority(handle->priority());
m_ctx = Mem::create(m_id); m_ctx = Mem::create(m_id);
} }

View File

@@ -60,6 +60,12 @@ Job Workers::job()
} }
void Workers::printHashrate(bool detail)
{
m_hashrate->print();
}
void Workers::setEnabled(bool enabled) void Workers::setEnabled(bool enabled)
{ {
if (m_enabled == enabled) { if (m_enabled == enabled) {
@@ -92,7 +98,7 @@ void Workers::setJob(const Job &job)
} }
void Workers::start(int64_t affinity) void Workers::start(int64_t affinity, int priority)
{ {
const int threads = Mem::threads(); const int threads = Mem::threads();
m_hashrate = new Hashrate(threads); m_hashrate = new Hashrate(threads);
@@ -100,7 +106,7 @@ void Workers::start(int64_t affinity)
uv_mutex_init(&m_mutex); uv_mutex_init(&m_mutex);
uv_rwlock_init(&m_rwlock); uv_rwlock_init(&m_rwlock);
m_sequence = 0; m_sequence = 1;
m_paused = 1; m_paused = 1;
uv_async_init(uv_default_loop(), &m_async, Workers::onResult); uv_async_init(uv_default_loop(), &m_async, Workers::onResult);
@@ -108,13 +114,28 @@ void Workers::start(int64_t affinity)
uv_timer_start(&m_timer, Workers::onTick, 500, 500); uv_timer_start(&m_timer, Workers::onTick, 500, 500);
for (int i = 0; i < threads; ++i) { for (int i = 0; i < threads; ++i) {
Handle *handle = new Handle(i, threads, affinity); Handle *handle = new Handle(i, threads, affinity, priority);
m_workers.push_back(handle); m_workers.push_back(handle);
handle->start(Workers::onReady); handle->start(Workers::onReady);
} }
} }
void Workers::stop()
{
uv_timer_stop(&m_timer);
m_hashrate->stop();
uv_close(reinterpret_cast<uv_handle_t*>(&m_async), nullptr);
m_paused = 0;
m_sequence = 0;
for (size_t i = 0; i < m_workers.size(); ++i) {
m_workers[i]->join();
}
}
void Workers::submit(const JobResult &result) void Workers::submit(const JobResult &result)
{ {
uv_mutex_lock(&m_mutex); uv_mutex_lock(&m_mutex);

View File

@@ -43,9 +43,11 @@ class Workers
{ {
public: public:
static Job job(); static Job job();
static void printHashrate(bool detail);
static void setEnabled(bool enabled); static void setEnabled(bool enabled);
static void setJob(const Job &job); static void setJob(const Job &job);
static void start(int64_t affinity); static void start(int64_t affinity, int priority);
static void stop();
static void submit(const JobResult &result); static void submit(const JobResult &result);
static inline bool isEnabled() { return m_enabled; } static inline bool isEnabled() { return m_enabled; }

View File

@@ -25,7 +25,7 @@
int main(int argc, char **argv) { int main(int argc, char **argv) {
auto app = new App(argc, argv); App app(argc, argv);
return app->exec(); return app.exec();
} }