summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ConfigEditor.hpp57
-rw-r--r--autoAdjust.hpp154
-rw-r--r--autoAdjustHwloc.hpp195
-rw-r--r--cli-miner.cpp50
-rw-r--r--config.txt280
-rw-r--r--console.cpp16
-rw-r--r--console.h2
-rw-r--r--executor.cpp47
-rw-r--r--executor.h16
-rw-r--r--jconf.cpp145
-rw-r--r--jconf.h11
-rw-r--r--jpsock.cpp3
-rw-r--r--minethd.cpp555
-rw-r--r--minethd.h144
-rw-r--r--msgstruct.h3
-rw-r--r--telemetry.cpp107
-rw-r--r--telemetry.h23
-rw-r--r--version.h4
-rw-r--r--webdesign.cpp2
19 files changed, 374 insertions, 1440 deletions
diff --git a/ConfigEditor.hpp b/ConfigEditor.hpp
new file mode 100644
index 0000000..80607ff
--- /dev/null
+++ b/ConfigEditor.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <atomic>
+#include <string>
+#include <fstream>
+#include <streambuf>
+#include <regex>
+
+
+namespace xmrstak
+{
+
+struct ConfigEditor
+{
+ std::string m_fileContent;
+
+ ConfigEditor()
+ {
+
+ }
+
+ static bool file_exist( const std::string filename)
+ {
+ std::ifstream fstream(filename);
+ return fstream.good();
+ }
+
+ void set( const std::string && content)
+ {
+ m_fileContent = content;
+ }
+
+ bool load(const std::string filename)
+ {
+ std::ifstream fstream(filename);
+ m_fileContent = std::string(
+ (std::istreambuf_iterator<char>(fstream)),
+ std::istreambuf_iterator<char>()
+ );
+ return fstream.good();
+ }
+
+ void write(const std::string filename)
+ {
+ std::ofstream out(filename);
+ out << m_fileContent;
+ out.close();
+ }
+
+ void replace(const std::string search, const std::string substring)
+ {
+ m_fileContent = std::regex_replace(m_fileContent, std::regex(search), substring);
+ }
+
+};
+
+} // namepsace xmrstak
diff --git a/autoAdjust.hpp b/autoAdjust.hpp
deleted file mode 100644
index 93a88e8..0000000
--- a/autoAdjust.hpp
+++ /dev/null
@@ -1,154 +0,0 @@
-#pragma once
-#include "jconf.h"
-#include "console.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif // _WIN32
-
-// Mask bits between h and l and return the value
-// This enables us to put in values exactly like in the manual
-// For example EBX[31:22] is get_masked(cpu_info[1], 31, 22)
-inline int32_t get_masked(int32_t val, int32_t h, int32_t l)
-{
- val &= (0x7FFFFFFF >> (31-(h-l))) << l;
- return val >> l;
-}
-
-class autoAdjust
-{
-public:
-
- autoAdjust()
- {
- }
-
- void printConfig()
- {
- printer::inst()->print_str("The configuration for 'cpu_threads_conf' in your config file is 'null'.\n");
- printer::inst()->print_str("The miner evaluates your system and prints a suggestion for the section `cpu_threads_conf` to the terminal.\n");
- printer::inst()->print_str("The values are not optimal, please try to tweak the values based on notes in config.txt.\n");
- printer::inst()->print_str("Please copy & paste the block within the asterisks to your config.\n\n");
-
- if(!detectL3Size() || L3KB_size < 1024 || L3KB_size > 102400)
- {
- if(L3KB_size < 1024 || L3KB_size > 102400)
- printer::inst()->print_msg(L0, "Autoconf failed: L3 size sanity check failed - %u KB.", L3KB_size);
-
- printer::inst()->print_msg(L0, "Autoconf failed: Printing config for a single thread. Please try to add new ones until the hashrate slows down.");
- printer::inst()->print_str("\n**************** Copy&Paste BEGIN ****************\n\n");
- printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n");
- printer::inst()->print_str(" { \"low_power_mode\" : false, \"no_prefetch\" : true, \"affine_to_cpu\" : false },\n");
- printer::inst()->print_str("],\n\n**************** Copy&Paste END ****************\n");
- return;
- }
-
- printer::inst()->print_msg(L0, "Autoconf L3 size detected at %u KB.", L3KB_size);
-
- detectCPUConf();
-
- printer::inst()->print_msg(L0, "Autoconf core count detected as %u on %s.", corecnt,
- linux_layout ? "Linux" : "Windows");
-
- printer::inst()->print_str("\n**************** Copy&Paste BEGIN ****************\n\n");
- printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n");
-
- uint32_t aff_id = 0;
- char strbuf[256];
- for(uint32_t i=0; i < corecnt; i++)
- {
- bool double_mode;
-
- if(L3KB_size <= 0)
- break;
-
- double_mode = L3KB_size / 2048 > (int32_t)(corecnt-i);
-
- snprintf(strbuf, sizeof(strbuf), " { \"low_power_mode\" : %s, \"no_prefetch\" : true, \"affine_to_cpu\" : %u },\n",
- double_mode ? "true" : "false", aff_id);
- printer::inst()->print_str(strbuf);
-
- if(!linux_layout || old_amd)
- {
- aff_id += 2;
-
- if(aff_id >= corecnt)
- aff_id = 1;
- }
- else
- aff_id++;
-
- if(double_mode)
- L3KB_size -= 4096;
- else
- L3KB_size -= 2048;
- }
-
- printer::inst()->print_str("],\n\n**************** Copy&Paste END ****************\n");
- }
-
-private:
- bool detectL3Size()
- {
- int32_t cpu_info[4];
- char cpustr[13] = {0};
-
- jconf::cpuid(0, 0, cpu_info);
- memcpy(cpustr, &cpu_info[1], 4);
- memcpy(cpustr+4, &cpu_info[3], 4);
- memcpy(cpustr+8, &cpu_info[2], 4);
-
- if(strcmp(cpustr, "GenuineIntel") == 0)
- {
- jconf::cpuid(4, 3, cpu_info);
-
- if(get_masked(cpu_info[0], 7, 5) != 3)
- {
- printer::inst()->print_msg(L0, "Autoconf failed: Couln't find L3 cache page.");
- return false;
- }
-
- L3KB_size = ((get_masked(cpu_info[1], 31, 22) + 1) * (get_masked(cpu_info[1], 21, 12) + 1) *
- (get_masked(cpu_info[1], 11, 0) + 1) * (cpu_info[2] + 1)) / 1024;
-
- return true;
- }
- else if(strcmp(cpustr, "AuthenticAMD") == 0)
- {
- jconf::cpuid(0x80000006, 0, cpu_info);
-
- L3KB_size = get_masked(cpu_info[3], 31, 18) * 512;
-
- jconf::cpuid(1, 0, cpu_info);
- if(get_masked(cpu_info[0], 11, 8) < 0x17) //0x17h is Zen
- old_amd = true;
-
- return true;
- }
- else
- {
- printer::inst()->print_msg(L0, "Autoconf failed: Unknown CPU type: %s.", cpustr);
- return false;
- }
- }
-
- void detectCPUConf()
- {
-#ifdef _WIN32
- SYSTEM_INFO info;
- GetSystemInfo(&info);
- corecnt = info.dwNumberOfProcessors;
- linux_layout = false;
-#else
- corecnt = sysconf(_SC_NPROCESSORS_ONLN);
- linux_layout = true;
-#endif // _WIN32
- }
-
- int32_t L3KB_size = 0;
- uint32_t corecnt;
- bool old_amd = false;
- bool linux_layout;
-};
diff --git a/autoAdjustHwloc.hpp b/autoAdjustHwloc.hpp
deleted file mode 100644
index 92a668a..0000000
--- a/autoAdjustHwloc.hpp
+++ /dev/null
@@ -1,195 +0,0 @@
-#pragma once
-
-#include "console.h"
-#include <hwloc.h>
-#include <stdio.h>
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif // _WIN32
-
-class autoAdjust
-{
-public:
-
- autoAdjust()
- {
- }
-
- void printConfig()
- {
- printer::inst()->print_str("The configuration for 'cpu_threads_conf' in your config file is 'null'.\n");
- printer::inst()->print_str("The miner evaluates your system and prints a suggestion for the section `cpu_threads_conf` to the terminal.\n");
- printer::inst()->print_str("The values are not optimal, please try to tweak the values based on notes in config.txt.\n");
- printer::inst()->print_str("Please copy & paste the block within the asterisks to your config.\n\n");
-
- hwloc_topology_t topology;
- hwloc_topology_init(&topology);
- hwloc_topology_load(topology);
-
- try
- {
- std::vector<hwloc_obj_t> tlcs;
- tlcs.reserve(16);
- results.reserve(16);
-
- findChildrenCaches(hwloc_get_root_obj(topology),
- [&tlcs](hwloc_obj_t found) { tlcs.emplace_back(found); } );
-
- if(tlcs.size() == 0)
- throw(std::runtime_error("The CPU doesn't seem to have a cache."));
-
- for(hwloc_obj_t obj : tlcs)
- proccessTopLevelCache(obj);
-
- printer::inst()->print_str("\n**************** Copy&Paste BEGIN ****************\n\n");
- printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n");
-
- for(uint32_t id : results)
- {
- char str[128];
- snprintf(str, sizeof(str), " { \"low_power_mode\" : %s, \"no_prefetch\" : true, \"affine_to_cpu\" : %u },\n",
- (id & 0x8000000) != 0 ? "true" : "false", id & 0x7FFFFFF);
- printer::inst()->print_str(str);
- }
-
- printer::inst()->print_str("],\n\n**************** Copy&Paste END ****************\n");
- }
- catch(const std::runtime_error& err)
- {
- printer::inst()->print_msg(L0, "Autoconf FAILED: %s", err.what());
- printer::inst()->print_str("\nPrinting config for a single thread. Please try to add new ones until the hashrate slows down.\n");
- printer::inst()->print_str("\n**************** FAILURE Copy&Paste BEGIN ****************\n\n");
- printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n");
- printer::inst()->print_str(" { \"low_power_mode\" : false, \"no_prefetch\" : true, \"affine_to_cpu\" : false },\n");
- printer::inst()->print_str("],\n\n**************** FAILURE Copy&Paste END ****************\n");
- }
-
- /* Destroy topology object. */
- hwloc_topology_destroy(topology);
- }
-
-private:
- static constexpr size_t hashSize = 2 * 1024 * 1024;
- std::vector<uint32_t> results;
-
- template<typename func>
- inline void findChildrenByType(hwloc_obj_t obj, hwloc_obj_type_t type, func lambda)
- {
- for(size_t i=0; i < obj->arity; i++)
- {
- if(obj->children[i]->type == type)
- lambda(obj->children[i]);
- else
- findChildrenByType(obj->children[i], type, lambda);
- }
- }
-
- inline bool isCacheObject(hwloc_obj_t obj)
- {
-#if HWLOC_API_VERSION >= 0x20000
- return hwloc_obj_type_is_cache(obj->type);
-#else
- return obj->type == HWLOC_OBJ_CACHE;
-#endif // HWLOC_API_VERSION
- }
-
- template<typename func>
- inline void findChildrenCaches(hwloc_obj_t obj, func lambda)
- {
- for(size_t i=0; i < obj->arity; i++)
- {
- if(isCacheObject(obj->children[i]))
- lambda(obj->children[i]);
- else
- findChildrenCaches(obj->children[i], lambda);
- }
- }
-
- inline bool isCacheExclusive(hwloc_obj_t obj)
- {
- const char* value = hwloc_obj_get_info_by_name(obj, "Inclusive");
- return value == nullptr || value[0] != '1';
- }
-
- // Top level cache isn't shared with other cores on the same package
- // This will usually be 1 x L3, but can be 2 x L2 per package
- void proccessTopLevelCache(hwloc_obj_t obj)
- {
- if(obj->attr == nullptr)
- throw(std::runtime_error("Cache object hasn't got attributes."));
-
- size_t PUs = 0;
- findChildrenByType(obj, HWLOC_OBJ_PU, [&PUs](hwloc_obj_t found) { PUs++; } );
-
- //Strange case, but we will handle it silently, surely there must be one PU somewhere?
- if(PUs == 0)
- return;
-
- if(obj->attr->cache.size == 0)
- {
- //We will always have one child if PUs > 0
- if(!isCacheObject(obj->children[0]))
- throw(std::runtime_error("The CPU doesn't seem to have a cache."));
-
- //Try our luck with lower level caches
- for(size_t i=0; i < obj->arity; i++)
- proccessTopLevelCache(obj->children[i]);
- return;
- }
-
- size_t cacheSize = obj->attr->cache.size;
- if(isCacheExclusive(obj))
- {
- for(size_t i=0; i < obj->arity; i++)
- {
- hwloc_obj_t l2obj = obj->children[i];
- //If L2 is exclusive and greater or equal to 2MB add room for one more hash
- if(isCacheObject(l2obj) && l2obj->attr != nullptr && l2obj->attr->cache.size >= hashSize)
- cacheSize += hashSize;
- }
- }
-
- std::vector<hwloc_obj_t> cores;
- cores.reserve(16);
- findChildrenByType(obj, HWLOC_OBJ_CORE, [&cores](hwloc_obj_t found) { cores.emplace_back(found); } );
-
- size_t cacheHashes = (cacheSize + hashSize/2) / hashSize;
-
- //Firstly allocate PU 0 of every CORE, then PU 1 etc.
- size_t pu_id = 0;
- while(cacheHashes > 0 && PUs > 0)
- {
- bool allocated_pu = false;
- for(hwloc_obj_t core : cores)
- {
- if(core->arity <= pu_id || core->children[pu_id]->type != HWLOC_OBJ_PU)
- continue;
-
- size_t os_id = core->children[pu_id]->os_index;
-
- if(cacheHashes > PUs)
- {
- cacheHashes -= 2;
- os_id |= 0x8000000; //double hash marker bit
- }
- else
- cacheHashes--;
- PUs--;
-
- allocated_pu = true;
- results.emplace_back(os_id);
-
- if(cacheHashes == 0)
- break;
- }
-
- if(!allocated_pu)
- throw(std::runtime_error("Failed to allocate a PU."));
-
- pu_id++;
- }
- }
-};
diff --git a/cli-miner.cpp b/cli-miner.cpp
index 45d2c16..d7d2781 100644
--- a/cli-miner.cpp
+++ b/cli-miner.cpp
@@ -22,15 +22,13 @@
*/
#include "executor.h"
-#include "minethd.h"
+#include "backend/miner_work.h"
+#include "backend/GlobalStates.hpp"
+#include "backend/BackendConnector.hpp"
#include "jconf.h"
#include "console.h"
#include "donate-level.h"
-#ifndef CONF_NO_HWLOC
-# include "autoAdjustHwloc.hpp"
-#else
-# include "autoAdjust.hpp"
-#endif
+
#include "version.h"
#ifndef CONF_NO_HTTPD
@@ -48,19 +46,9 @@
#include <openssl/err.h>
#endif
-//Do a press any key for the windows folk. *insert any key joke here*
-#ifdef _WIN32
-void win_exit()
-{
- printer::inst()->print_str("Press any key to exit.");
- get_key();
- return;
-}
-
-#define strcasecmp _stricmp
-#else
-void win_exit() { return; }
+#ifdef _WIN32
+# define strcasecmp _stricmp
#endif // _WIN32
void do_benchmark();
@@ -109,15 +97,7 @@ int main(int argc, char *argv[])
return 0;
}
- if(jconf::inst()->NeedsAutoconf())
- {
- autoAdjust adjust;
- adjust.printConfig();
- win_exit();
- return 0;
- }
-
- if (!minethd::self_test())
+ if (!xmrstak::BackendConnector::self_test())
{
win_exit();
return 0;
@@ -144,6 +124,12 @@ int main(int argc, char *argv[])
printer::inst()->print_str("-------------------------------------------------------------------\n");
printer::inst()->print_str( XMR_STAK_NAME" " XMR_STAK_VERSION " mining software, CPU Version.\n");
printer::inst()->print_str("Based on CPU mining code by wolf9466 (heavily optimized by fireice_uk).\n");
+#ifndef CONF_NO_CUDA
+ printer::inst()->print_str("NVIDIA mining code was written by KlausT and psychocrypt.\n");
+#endif
+#ifndef CONF_NO_OPENCL
+ printer::inst()->print_str("AMD mining code was written by wolf9466.\n");
+#endif
printer::inst()->print_str("Brought to you by fireice_uk and psychocrypt under GPLv3.\n\n");
char buffer[64];
snprintf(buffer, sizeof(buffer), "Configurable dev donation level is set to %.1f %%\n\n", fDevDonationLevel * 100.0);
@@ -196,20 +182,20 @@ int main(int argc, char *argv[])
void do_benchmark()
{
using namespace std::chrono;
- std::vector<minethd*>* pvThreads;
+ std::vector<xmrstak::IBackend*>* pvThreads;
printer::inst()->print_msg(L0, "Running a 60 second benchmark...");
uint8_t work[76] = {0};
- minethd::miner_work oWork = minethd::miner_work("", work, sizeof(work), 0, 0, false, 0);
- pvThreads = minethd::thread_starter(oWork);
+ xmrstak::miner_work oWork = xmrstak::miner_work("", work, sizeof(work), 0, 0, 0);
+ pvThreads = xmrstak::BackendConnector::thread_starter(oWork);
uint64_t iStartStamp = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
std::this_thread::sleep_for(std::chrono::seconds(60));
- oWork = minethd::miner_work();
- minethd::switch_work(oWork);
+ oWork = xmrstak::miner_work();
+ xmrstak::GlobalStates::switch_work(oWork);
double fTotalHps = 0.0;
for (uint32_t i = 0; i < pvThreads->size(); i++)
diff --git a/config.txt b/config.txt
index 36d10d4..781f505 100644
--- a/config.txt
+++ b/config.txt
@@ -1,184 +1,96 @@
-/*
- * Thread configuration for each thread. Make sure it matches the number above.
- * low_power_mode - This mode will double the cache usage, and double the single thread performance. It will
- * consume much less power (as less cores are working), but will max out at around 80-85% of
- * the maximum performance.
- *
- * no_prefetch - Some sytems can gain up to extra 5% here, but sometimes it will have no difference or make
- * things slower.
- *
- * affine_to_cpu - This can be either false (no affinity), or the CPU core number. Note that on hyperthreading
- * systems it is better to assign threads to physical cores. On Windows this usually means selecting
- * even or odd numbered cpu numbers. For Linux it will be usually the lower CPU numbers, so for a 4
- * physical core CPU you should select cpu numbers 0-3.
- *
- * On the first run the miner will look at your system and suggest a basic configuration that will work,
- * you can try to tweak it from there to get the best performance.
- *
- * A filled out configuration should look like this:
- * "cpu_threads_conf" :
- * [
- * { "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 0 },
- * { "low_power_mode" : false, "no_prefetch" : true, "affine_to_cpu" : 1 },
- * ],
- */
-"cpu_threads_conf" :
-null,
-
-/*
- * LARGE PAGE SUPPORT
- * Large pages need a properly set up OS. It can be difficult if you are not used to systems administration,
- * but the performance results are worth the trouble - you will get around 20% boost. Slow memory mode is
- * meant as a backup, you won't get stellar results there. If you are running into trouble, especially
- * on Windows, please read the common issues in the README.
- *
- * By default we will try to allocate large pages. This means you need to "Run As Administrator" on Windows.
- * You need to edit your system's group policies to enable locking large pages. Here are the steps from MSDN
- *
- * 1. On the Start menu, click Run. In the Open box, type gpedit.msc.
- * 2. On the Local Group Policy Editor console, expand Computer Configuration, and then expand Windows Settings.
- * 3. Expand Security Settings, and then expand Local Policies.
- * 4. Select the User Rights Assignment folder.
- * 5. The policies will be displayed in the details pane.
- * 6. In the pane, double-click Lock pages in memory.
- * 7. In the Local Security Setting – Lock pages in memory dialog box, click Add User or Group.
- * 8. In the Select Users, Service Accounts, or Groups dialog box, add an account that you will run the miner on
- * 9. Reboot for change to take effect.
- *
- * Windows also tends to fragment memory a lot. If you are running on a system with 4-8GB of RAM you might need
- * to switch off all the auto-start applications and reboot to have a large enough chunk of contiguous memory.
- *
- * On Linux you will need to configure large page support "sudo sysctl -w vm.nr_hugepages=128" and increase your
- * ulimit -l. To do do this you need to add following lines to /etc/security/limits.conf - "* soft memlock 262144"
- * and "* hard memlock 262144". You can also do it Windows-style and simply run-as-root, but this is NOT
- * recommended for security reasons.
- *
- * Memory locking means that the kernel can't swap out the page to disk - something that is unlikely to happen on a
- * command line system that isn't starved of memory. I haven't observed any difference on a CLI Linux system between
- * locked and unlocked memory. If that is your setup see option "no_mlck".
- */
-
-/*
- * use_slow_memory defines our behavior with regards to large pages. There are three possible options here:
- * always - Don't even try to use large pages. Always use slow memory.
- * warn - We will try to use large pages, but fall back to slow memory if that fails.
- * no_mlck - This option is only relevant on Linux, where we can use large pages without locking memory.
- * It will never use slow memory, but it won't attempt to mlock
- * never - If we fail to allocate large pages we will print an error and exit.
- */
-"use_slow_memory" : "warn",
-
-/*
- * NiceHash mode
- * nicehash_nonce - Limit the nonce to 3 bytes as required by nicehash. This cuts all the safety margins, and
- * if a block isn't found within 30 minutes then you might run into nonce collisions. Number
- * of threads in this mode is hard-limited to 32.
- */
-"nicehash_nonce" : false,
-
-/*
- * Manual hardware AES override
- *
- * Some VMs don't report AES capability correctly. You can set this value to true to enforce hardware AES or
- * to false to force disable AES or null to let the miner decide if AES is used.
- *
- * WARNING: setting this to true on a CPU that doesn't support hardware AES will crash the miner.
- */
-"aes_override" : null,
-
-/*
- * TLS Settings
- * If you need real security, make sure tls_secure_algo is enabled (otherwise MITM attack can downgrade encryption
- * to trivially breakable stuff like DES and MD5), and verify the server's fingerprint through a trusted channel.
- *
- * use_tls - This option will make us connect using Transport Layer Security.
- * tls_secure_algo - Use only secure algorithms. This will make us quit with an error if we can't negotiate a secure algo.
- * tls_fingerprint - Server's SHA256 fingerprint. If this string is non-empty then we will check the server's cert against it.
- */
-"use_tls" : false,
-"tls_secure_algo" : true,
-"tls_fingerprint" : "",
-
-/*
- * pool_address - Pool address should be in the form "pool.supportxmr.com:3333". Only stratum pools are supported.
- * wallet_address - Your wallet, or pool login.
- * pool_password - Can be empty in most cases or "x".
- *
- * We feature pools up to 1MH/s. For a more complete list see M5M400's pool list at www.moneropools.com
- */
-"pool_address" : "pool.usxmrpool.com:3333",
-"wallet_address" : "",
-"pool_password" : "",
-
-/*
- * Network timeouts.
- * Because of the way this client is written it doesn't need to constantly talk (keep-alive) to the server to make
- * sure it is there. We detect a buggy / overloaded server by the call timeout. The default values will be ok for
- * nearly all cases. If they aren't the pool has most likely overload issues. Low call timeout values are preferable -
- * long timeouts mean that we waste hashes on potentially stale jobs. Connection report will tell you how long the
- * server usually takes to process our calls.
- *
- * call_timeout - How long should we wait for a response from the server before we assume it is dead and drop the connection.
- * retry_time - How long should we wait before another connection attempt.
- * Both values are in seconds.
- * giveup_limit - Limit how many times we try to reconnect to the pool. Zero means no limit. Note that stak miners
- * don't mine while the connection is lost, so your computer's power usage goes down to idle.
- */
-"call_timeout" : 10,
-"retry_time" : 10,
-"giveup_limit" : 0,
-
-/*
- * Output control.
- * Since most people are used to miners printing all the time, that's what we do by default too. This is suboptimal
- * really, since you cannot see errors under pages and pages of text and performance stats. Given that we have internal
- * performance monitors, there is very little reason to spew out pages of text instead of concise reports.
- * Press 'h' (hashrate), 'r' (results) or 'c' (connection) to print reports.
- *
- * verbose_level - 0 - Don't print anything.
- * 1 - Print intro, connection event, disconnect event
- * 2 - All of level 1, and new job (block) event if the difficulty is different from the last job
- * 3 - All of level 1, and new job (block) event in all cases, result submission event.
- * 4 - All of level 3, and automatic hashrate report printing
- */
-"verbose_level" : 3,
-
-/*
- * Automatic hashrate report
- *
- * h_print_time - How often, in seconds, should we print a hashrate report if verbose_level is set to 4.
- * This option has no effect if verbose_level is not 4.
- */
-"h_print_time" : 60,
-
-/*
- * Daemon mode
- *
- * If you are running the process in the background and you don't need the keyboard reports, set this to true.
- * This should solve the hashrate problems on some emulated terminals.
- */
-"daemon_mode" : false,
-
-/*
- * Output file
- *
- * output_file - This option will log all output to a file.
- *
- */
-"output_file" : "",
-
-/*
- * Built-in web server
- * I like checking my hashrate on my phone. Don't you?
- * Keep in mind that you will need to set up port forwarding on your router if you want to access it from
- * outside of your home network. Ports lower than 1024 on Linux systems will require root.
- *
- * httpd_port - Port we should listen on. Default, 0, will switch off the server.
- */
-"httpd_port" : 0,
-
-/*
- * prefer_ipv4 - IPv6 preference. If the host is available on both IPv4 and IPv6 net, which one should be choose?
- * This setting will only be needed in 2020's. No need to worry about it now.
- */
-"prefer_ipv4" : true,
+/*
+ * TLS Settings
+ * If you need real security, make sure tls_secure_algo is enabled (otherwise MITM attack can downgrade encryption
+ * to trivially breakable stuff like DES and MD5), and verify the server's fingerprint through a trusted channel.
+ *
+ * use_tls - This option will make us connect using Transport Layer Security.
+ * tls_secure_algo - Use only secure algorithms. This will make us quit with an error if we can't negotiate a secure algo.
+ * tls_fingerprint - Server's SHA256 fingerprint. If this string is non-empty then we will check the server's cert against it.
+ */
+"use_tls" : false,
+"tls_secure_algo" : true,
+"tls_fingerprint" : "",
+
+/*
+ * pool_address - Pool address should be in the form "pool.supportxmr.com:3333". Only stratum pools are supported.
+ * wallet_address - Your wallet, or pool login.
+ * pool_password - Can be empty in most cases or "x".
+ *
+ * We feature pools up to 1MH/s. For a more complete list see M5M400's pool list at www.moneropools.com
+ */
+"pool_address" : "pool.usxmrpool.com:3333",
+"wallet_address" : "",
+"pool_password" : "",
+
+/*
+ * Network timeouts.
+ * Because of the way this client is written it doesn't need to constantly talk (keep-alive) to the server to make
+ * sure it is there. We detect a buggy / overloaded server by the call timeout. The default values will be ok for
+ * nearly all cases. If they aren't the pool has most likely overload issues. Low call timeout values are preferable -
+ * long timeouts mean that we waste hashes on potentially stale jobs. Connection report will tell you how long the
+ * server usually takes to process our calls.
+ *
+ * call_timeout - How long should we wait for a response from the server before we assume it is dead and drop the connection.
+ * retry_time - How long should we wait before another connection attempt.
+ * Both values are in seconds.
+ * giveup_limit - Limit how many times we try to reconnect to the pool. Zero means no limit. Note that stak miners
+ * don't mine while the connection is lost, so your computer's power usage goes down to idle.
+ */
+"call_timeout" : 10,
+"retry_time" : 10,
+"giveup_limit" : 0,
+
+/*
+ * Output control.
+ * Since most people are used to miners printing all the time, that's what we do by default too. This is suboptimal
+ * really, since you cannot see errors under pages and pages of text and performance stats. Given that we have internal
+ * performance monitors, there is very little reason to spew out pages of text instead of concise reports.
+ * Press 'h' (hashrate), 'r' (results) or 'c' (connection) to print reports.
+ *
+ * verbose_level - 0 - Don't print anything.
+ * 1 - Print intro, connection event, disconnect event
+ * 2 - All of level 1, and new job (block) event if the difficulty is different from the last job
+ * 3 - All of level 1, and new job (block) event in all cases, result submission event.
+ * 4 - All of level 3, and automatic hashrate report printing
+ */
+"verbose_level" : 3,
+
+/*
+ * Automatic hashrate report
+ *
+ * h_print_time - How often, in seconds, should we print a hashrate report if verbose_level is set to 4.
+ * This option has no effect if verbose_level is not 4.
+ */
+"h_print_time" : 60,
+
+/*
+ * Daemon mode
+ *
+ * If you are running the process in the background and you don't need the keyboard reports, set this to true.
+ * This should solve the hashrate problems on some emulated terminals.
+ */
+"daemon_mode" : false,
+
+/*
+ * Output file
+ *
+ * output_file - This option will log all output to a file.
+ *
+ */
+"output_file" : "",
+
+/*
+ * Built-in web server
+ * I like checking my hashrate on my phone. Don't you?
+ * Keep in mind that you will need to set up port forwarding on your router if you want to access it from
+ * outside of your home network. Ports lower than 1024 on Linux systems will require root.
+ *
+ * httpd_port - Port we should listen on. Default, 0, will switch off the server.
+ */
+"httpd_port" : 0,
+
+/*
+ * prefer_ipv4 - IPv6 preference. If the host is available on both IPv4 and IPv6 net, which one should be choose?
+ * This setting will only be needed in 2020's. No need to worry about it now.
+ */
+"prefer_ipv4" : true,
diff --git a/console.cpp b/console.cpp
index 6a2555b..c6b7d4d 100644
--- a/console.cpp
+++ b/console.cpp
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <cstdlib>
#ifdef _WIN32
#include <windows.h>
@@ -211,3 +212,18 @@ void printer::print_str(const char* str)
fflush(logfile);
}
}
+
+//Do a press any key for the windows folk. *insert any key joke here*
+#ifdef _WIN32
+void win_exit()
+{
+ printer::inst()->print_str("Press any key to exit.");
+ get_key();
+ std::exit(1);
+}
+
+#else
+void win_exit() {
+ std::exit(1);
+}
+#endif // _WIN32
diff --git a/console.h b/console.h
index 47c3c94..51efaef 100644
--- a/console.h
+++ b/console.h
@@ -41,3 +41,5 @@ private:
verbosity verbose_level;
FILE* logfile;
};
+
+void win_exit();
diff --git a/executor.cpp b/executor.cpp
index 948b156..99f7ad5 100644
--- a/executor.cpp
+++ b/executor.cpp
@@ -29,7 +29,12 @@
#include <time.h>
#include "executor.h"
#include "jpsock.h"
-#include "minethd.h"
+
+#include "telemetry.h"
+#include "backend/miner_work.h"
+#include "backend/GlobalStates.hpp"
+#include "backend/BackendConnector.hpp"
+
#include "jconf.h"
#include "console.h"
#include "donate-level.h"
@@ -116,8 +121,8 @@ void executor::sched_reconnect()
printer::inst()->print_msg(L1, "Pool connection lost. Waiting %lld s before retry (attempt %llu).",
rt, int_port(iReconnectAttempts));
- auto work = minethd::miner_work();
- minethd::switch_work(work);
+ auto work = xmrstak::miner_work();
+ xmrstak::GlobalStates::switch_work(work);
push_timed_event(ex_event(EV_RECONNECT, usr_pool_id), rt);
}
@@ -229,12 +234,13 @@ void executor::on_pool_have_job(size_t pool_id, pool_job& oPoolJob)
jpsock* pool = pick_pool_by_id(pool_id);
- minethd::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob,
+ xmrstak::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob,
oPoolJob.iWorkLen, oPoolJob.iResumeCnt, oPoolJob.iTarget,
- pool_id != dev_pool_id && jconf::inst()->NiceHashMode(),
pool_id);
- minethd::switch_work(oWork);
+ oWork.iTarget32 = oPoolJob.iTarget32;
+
+ xmrstak::GlobalStates::switch_work(oWork);
if(pool_id == dev_pool_id)
return;
@@ -350,11 +356,13 @@ void executor::on_switch_pool(size_t pool_id)
return;
}
- minethd::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob,
+ xmrstak::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob,
oPoolJob.iWorkLen, oPoolJob.iResumeCnt, oPoolJob.iTarget,
- jconf::inst()->NiceHashMode(), pool_id);
+ pool_id);
+
+ oWork.iTarget32 = oPoolJob.iTarget32;
- minethd::switch_work(oWork);
+ xmrstak::GlobalStates::switch_work(oWork);
if(dev_pool->is_running())
push_timed_event(ex_event(EV_DEV_POOL_EXIT), 5);
@@ -365,9 +373,18 @@ void executor::ex_main()
{
assert(1000 % iTickTime == 0);
- minethd::miner_work oWork = minethd::miner_work();
- pvThreads = minethd::thread_starter(oWork);
- telem = new telemetry(pvThreads->size());
+ xmrstak::miner_work oWork = xmrstak::miner_work();
+
+ // \todo collect all backend threads
+ pvThreads = xmrstak::BackendConnector::thread_starter(oWork);
+
+ if(pvThreads->size()==0)
+ {
+ printer::inst()->print_msg(L1, "ERROR: No miner backend enabled.");
+ win_exit();
+ }
+
+ telem = new xmrstak::telemetry(pvThreads->size());
current_pool_id = usr_pool_id;
usr_pool = new jpsock(usr_pool_id, jconf::inst()->GetTlsSetting());
@@ -499,9 +516,9 @@ void executor::hashrate_report(std::string& out)
size_t i;
out.append("HASHRATE REPORT\n");
- out.append("| ID | 2.5s | 60s | 15m |");
+ out.append("| ID | 10s | 60s | 15m |");
if(nthd != 1)
- out.append(" ID | 2.5s | 60s | 15m |\n");
+ out.append(" ID | 10s | 60s | 15m |\n");
else
out.append(1, '\n');
@@ -509,7 +526,7 @@ void executor::hashrate_report(std::string& out)
{
double fHps[3];
- fHps[0] = telem->calc_telemetry_data(2500, i);
+ fHps[0] = telem->calc_telemetry_data(10000, i);
fHps[1] = telem->calc_telemetry_data(60000, i);
fHps[2] = telem->calc_telemetry_data(900000, i);
diff --git a/executor.h b/executor.h
index 968db06..57e435f 100644
--- a/executor.h
+++ b/executor.h
@@ -5,10 +5,20 @@
#include <array>
#include <list>
#include <future>
+#include "telemetry.h"
+#include "backend/IBackend.hpp"
class jpsock;
+
+
+namespace xmrstak
+{
+namespace cpu
+{
class minethd;
-class telemetry;
+
+} // namespace cpu
+} // namepsace xmrstak
class executor
{
@@ -50,8 +60,8 @@ private:
std::mutex timed_event_mutex;
thdq<ex_event> oEventQ;
- telemetry* telem;
- std::vector<minethd*>* pvThreads;
+ xmrstak::telemetry* telem;
+ std::vector<xmrstak::IBackend*>* pvThreads;
size_t current_pool_id;
diff --git a/jconf.cpp b/jconf.cpp
index 4ac4c13..60075d9 100644
--- a/jconf.cpp
+++ b/jconf.cpp
@@ -45,7 +45,7 @@ using namespace rapidjson;
/*
* This enum needs to match index in oConfigValues, otherwise we will get a runtime error
*/
-enum configEnum { aCpuThreadsConf, sUseSlowMem, bNiceHashMode, bAesOverride,
+enum configEnum {
bTlsMode, bTlsSecureAlgo, sTlsFingerprint, sPoolAddr, sWalletAddr, sPoolPwd,
iCallTimeout, iNetRetry, iGiveUpLimit, iVerboseLevel, iAutohashTime,
bDaemonMode, sOutputFile, iHttpdPort, bPreferIpv4 };
@@ -59,10 +59,6 @@ struct configVal {
// Same order as in configEnum, as per comment above
// kNullType means any type
configVal oConfigValues[] = {
- { aCpuThreadsConf, "cpu_threads_conf", kNullType },
- { sUseSlowMem, "use_slow_memory", kStringType },
- { bNiceHashMode, "nicehash_nonce", kTrueType },
- { bAesOverride, "aes_override", kNullType },
{ bTlsMode, "use_tls", kTrueType },
{ bTlsSecureAlgo, "tls_secure_algo", kTrueType },
{ sTlsFingerprint, "tls_fingerprint", kStringType },
@@ -113,63 +109,6 @@ jconf::jconf()
prv = new opaque_private();
}
-bool jconf::GetThreadConfig(size_t id, thd_cfg &cfg)
-{
- if(!prv->configValues[aCpuThreadsConf]->IsArray())
- return false;
-
- if(id >= prv->configValues[aCpuThreadsConf]->Size())
- return false;
-
- const Value& oThdConf = prv->configValues[aCpuThreadsConf]->GetArray()[id];
-
- if(!oThdConf.IsObject())
- return false;
-
- const Value *mode, *no_prefetch, *aff;
- mode = GetObjectMember(oThdConf, "low_power_mode");
- no_prefetch = GetObjectMember(oThdConf, "no_prefetch");
- aff = GetObjectMember(oThdConf, "affine_to_cpu");
-
- if(mode == nullptr || no_prefetch == nullptr || aff == nullptr)
- return false;
-
- if(!mode->IsBool() || !no_prefetch->IsBool())
- return false;
-
- if(!aff->IsNumber() && !aff->IsBool())
- return false;
-
- if(aff->IsNumber() && aff->GetInt64() < 0)
- return false;
-
- cfg.bDoubleMode = mode->GetBool();
- cfg.bNoPrefetch = no_prefetch->GetBool();
-
- if(aff->IsNumber())
- cfg.iCpuAff = aff->GetInt64();
- else
- cfg.iCpuAff = -1;
-
- return true;
-}
-
-jconf::slow_mem_cfg jconf::GetSlowMemSetting()
-{
- const char* opt = prv->configValues[sUseSlowMem]->GetString();
-
- if(strcasecmp(opt, "always") == 0)
- return always_use;
- else if(strcasecmp(opt, "no_mlck") == 0)
- return no_mlck;
- else if(strcasecmp(opt, "warn") == 0)
- return print_warning;
- else if(strcasecmp(opt, "never") == 0)
- return never_use;
- else
- return unknown_value;
-}
-
bool jconf::GetTlsSetting()
{
return prv->configValues[bTlsMode]->GetBool();
@@ -205,19 +144,6 @@ bool jconf::PreferIpv4()
return prv->configValues[bPreferIpv4]->GetBool();
}
-size_t jconf::GetThreadCount()
-{
- if(prv->configValues[aCpuThreadsConf]->IsArray())
- return prv->configValues[aCpuThreadsConf]->Size();
- else
- return 0;
-}
-
-bool jconf::NeedsAutoconf()
-{
- return !prv->configValues[aCpuThreadsConf]->IsArray();
-}
-
uint64_t jconf::GetCallTimeout()
{
return prv->configValues[iCallTimeout]->GetUint64();
@@ -248,11 +174,6 @@ uint16_t jconf::GetHttpdPort()
return prv->configValues[iHttpdPort]->GetUint();
}
-bool jconf::NiceHashMode()
-{
- return prv->configValues[bNiceHashMode]->GetBool();
-}
-
bool jconf::DaemonMode()
{
return prv->configValues[bDaemonMode]->GetBool();
@@ -263,44 +184,12 @@ const char* jconf::GetOutputFile()
return prv->configValues[sOutputFile]->GetString();
}
-void jconf::cpuid(uint32_t eax, int32_t ecx, int32_t val[4])
-{
- memset(val, 0, sizeof(int32_t)*4);
-
-#ifdef _WIN32
- __cpuidex(val, eax, ecx);
-#else
- __cpuid_count(eax, ecx, val[0], val[1], val[2], val[3]);
-#endif
-}
-
-bool jconf::check_cpu_features()
-{
- constexpr int AESNI_BIT = 1 << 25;
- constexpr int SSE2_BIT = 1 << 26;
- int32_t cpu_info[4];
- bool bHaveSse2;
-
- cpuid(1, 0, cpu_info);
-
- bHaveAes = (cpu_info[2] & AESNI_BIT) != 0;
- bHaveSse2 = (cpu_info[3] & SSE2_BIT) != 0;
-
- return bHaveSse2;
-}
-
bool jconf::parse_config(const char* sFilename)
{
FILE * pFile;
char * buffer;
size_t flen;
- if(!check_cpu_features())
- {
- printer::inst()->print_msg(L0, "CPU support of SSE2 is required.");
- return false;
- }
-
pFile = fopen(sFilename, "rb");
if (pFile == NULL)
{
@@ -389,29 +278,6 @@ bool jconf::parse_config(const char* sFilename)
}
}
- thd_cfg c;
- for(size_t i=0; i < GetThreadCount(); i++)
- {
- if(!GetThreadConfig(i, c))
- {
- printer::inst()->print_msg(L0, "Thread %llu has invalid config.", int_port(i));
- return false;
- }
- }
-
- if(NiceHashMode() && GetThreadCount() >= 32)
- {
- printer::inst()->print_msg(L0, "You need to use less than 32 threads in NiceHash mode.");
- return false;
- }
-
- if(GetSlowMemSetting() == unknown_value)
- {
- printer::inst()->print_msg(L0,
- "Invalid config file. use_slow_memory must be \"always\", \"no_mlck\", \"warn\" or \"never\"");
- return false;
- }
-
if(!prv->configValues[iCallTimeout]->IsUint64() ||
!prv->configValues[iNetRetry]->IsUint64() ||
!prv->configValues[iGiveUpLimit]->IsUint64())
@@ -454,14 +320,5 @@ bool jconf::parse_config(const char* sFilename)
printer::inst()->set_verbose_level(prv->configValues[iVerboseLevel]->GetUint64());
- if(NeedsAutoconf())
- return true;
-
- if(prv->configValues[bAesOverride]->IsBool())
- bHaveAes = prv->configValues[bAesOverride]->GetBool();
-
- if(!bHaveAes)
- printer::inst()->print_msg(L0, "Your CPU doesn't support hardware AES. Don't expect high hashrates.");
-
return true;
}
diff --git a/jconf.h b/jconf.h
index c42fbe0..dd6a010 100644
--- a/jconf.h
+++ b/jconf.h
@@ -27,12 +27,6 @@ public:
unknown_value
};
- size_t GetThreadCount();
- bool GetThreadConfig(size_t id, thd_cfg &cfg);
- bool NeedsAutoconf();
-
- slow_mem_cfg GetSlowMemSetting();
-
bool GetTlsSetting();
bool TlsSecureAlgos();
const char* GetTlsFingerprint();
@@ -52,15 +46,10 @@ public:
uint16_t GetHttpdPort();
- bool NiceHashMode();
-
bool DaemonMode();
bool PreferIpv4();
- inline bool HaveHardwareAes() { return bHaveAes; }
-
- static void cpuid(uint32_t eax, int32_t ecx, int32_t val[4]);
private:
jconf();
diff --git a/jpsock.cpp b/jpsock.cpp
index d179f2a..d287375 100644
--- a/jpsock.cpp
+++ b/jpsock.cpp
@@ -394,7 +394,10 @@ bool jpsock::process_pool_job(const opq_json_val* params)
if(!hex2bin(sTempStr, 8, (unsigned char*)&iTempInt) || iTempInt == 0)
return set_socket_error("PARSE error: Invalid target");
+
oPoolJob.iTarget = t32_to_t64(iTempInt);
+ oPoolJob.iTarget32 = iTempInt;
+
}
else if(target_slen <= 16)
{
diff --git a/minethd.cpp b/minethd.cpp
deleted file mode 100644
index fac9fb4..0000000
--- a/minethd.cpp
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * 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
- * 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/>.
- *
- * Additional permission under GNU GPL version 3 section 7
- *
- * If you modify this Program, or any covered work, by linking or combining
- * it with OpenSSL (or a modified version of that library), containing parts
- * covered by the terms of OpenSSL License and SSLeay License, the licensors
- * of this Program grant you additional permission to convey the resulting work.
- *
- */
-
-#include <assert.h>
-#include <cmath>
-#include <chrono>
-#include <cstring>
-#include <thread>
-#include <bitset>
-#include "console.h"
-
-#ifdef _WIN32
-#include <windows.h>
-
-void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id)
-{
- SetThreadAffinityMask(h, 1ULL << cpu_id);
-}
-#else
-#include <pthread.h>
-
-#if defined(__APPLE__)
-#include <mach/thread_policy.h>
-#include <mach/thread_act.h>
-#define SYSCTL_CORE_COUNT "machdep.cpu.core_count"
-#elif defined(__FreeBSD__)
-#include <pthread_np.h>
-#endif
-
-
-void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id)
-{
-#if defined(__APPLE__)
- thread_port_t mach_thread;
- thread_affinity_policy_data_t policy = { static_cast<integer_t>(cpu_id) };
- mach_thread = pthread_mach_thread_np(h);
- thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1);
-#elif defined(__FreeBSD__)
- cpuset_t mn;
- CPU_ZERO(&mn);
- CPU_SET(cpu_id, &mn);
- pthread_setaffinity_np(h, sizeof(cpuset_t), &mn);
-#else
- cpu_set_t mn;
- CPU_ZERO(&mn);
- CPU_SET(cpu_id, &mn);
- pthread_setaffinity_np(h, sizeof(cpu_set_t), &mn);
-#endif
-}
-#endif // _WIN32
-
-#include "executor.h"
-#include "minethd.h"
-#include "jconf.h"
-#include "crypto/cryptonight_aesni.h"
-#include "hwlocMemory.hpp"
-
-telemetry::telemetry(size_t iThd)
-{
- ppHashCounts = new uint64_t*[iThd];
- ppTimestamps = new uint64_t*[iThd];
- iBucketTop = new uint32_t[iThd];
-
- for (size_t i = 0; i < iThd; i++)
- {
- ppHashCounts[i] = new uint64_t[iBucketSize];
- ppTimestamps[i] = new uint64_t[iBucketSize];
- iBucketTop[i] = 0;
- memset(ppHashCounts[0], 0, sizeof(uint64_t) * iBucketSize);
- memset(ppTimestamps[0], 0, sizeof(uint64_t) * iBucketSize);
- }
-}
-
-double telemetry::calc_telemetry_data(size_t iLastMilisec, size_t iThread)
-{
- using namespace std::chrono;
- uint64_t iTimeNow = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
-
- uint64_t iEarliestHashCnt = 0;
- uint64_t iEarliestStamp = 0;
- uint64_t iLastestStamp = 0;
- uint64_t iLastestHashCnt = 0;
- bool bHaveFullSet = false;
-
- //Start at 1, buckettop points to next empty
- for (size_t i = 1; i < iBucketSize; i++)
- {
- size_t idx = (iBucketTop[iThread] - i) & iBucketMask; //overflow expected here
-
- if (ppTimestamps[iThread][idx] == 0)
- break; //That means we don't have the data yet
-
- if (iLastestStamp == 0)
- {
- iLastestStamp = ppTimestamps[iThread][idx];
- iLastestHashCnt = ppHashCounts[iThread][idx];
- }
-
- if (iTimeNow - ppTimestamps[iThread][idx] > iLastMilisec)
- {
- bHaveFullSet = true;
- break; //We are out of the requested time period
- }
-
- iEarliestStamp = ppTimestamps[iThread][idx];
- iEarliestHashCnt = ppHashCounts[iThread][idx];
- }
-
- if (!bHaveFullSet || iEarliestStamp == 0 || iLastestStamp == 0)
- return nan("");
-
- //Don't think that can happen, but just in case
- if (iLastestStamp - iEarliestStamp == 0)
- return nan("");
-
- double fHashes, fTime;
- fHashes = iLastestHashCnt - iEarliestHashCnt;
- fTime = iLastestStamp - iEarliestStamp;
- fTime /= 1000.0;
-
- return fHashes / fTime;
-}
-
-void telemetry::push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTimestamp)
-{
- size_t iTop = iBucketTop[iThd];
- ppHashCounts[iThd][iTop] = iHashCount;
- ppTimestamps[iThd][iTop] = iTimestamp;
-
- iBucketTop[iThd] = (iTop + 1) & iBucketMask;
-}
-
-minethd::minethd(miner_work& pWork, size_t iNo, bool double_work, bool no_prefetch, int64_t affinity)
-{
- oWork = pWork;
- bQuit = 0;
- iThreadNo = (uint8_t)iNo;
- iJobNo = 0;
- iHashCount = 0;
- iTimestamp = 0;
- bNoPrefetch = no_prefetch;
- this->affinity = affinity;
-
- std::lock_guard<std::mutex> lock(work_thd_mtx);
- if(double_work)
- oWorkThd = std::thread(&minethd::double_work_main, this);
- else
- oWorkThd = std::thread(&minethd::work_main, this);
-}
-
-std::atomic<uint64_t> minethd::iGlobalJobNo;
-std::atomic<uint64_t> minethd::iConsumeCnt; //Threads get jobs as they are initialized
-minethd::miner_work minethd::oGlobalWork;
-uint64_t minethd::iThreadCount = 0;
-
-cryptonight_ctx* minethd_alloc_ctx()
-{
- cryptonight_ctx* ctx;
- alloc_msg msg = { 0 };
-
- switch (jconf::inst()->GetSlowMemSetting())
- {
- case jconf::never_use:
- ctx = cryptonight_alloc_ctx(1, 1, &msg);
- if (ctx == NULL)
- printer::inst()->print_msg(L0, "MEMORY ALLOC FAILED: %s", msg.warning);
- return ctx;
-
- case jconf::no_mlck:
- ctx = cryptonight_alloc_ctx(1, 0, &msg);
- if (ctx == NULL)
- printer::inst()->print_msg(L0, "MEMORY ALLOC FAILED: %s", msg.warning);
- return ctx;
-
- case jconf::print_warning:
- ctx = cryptonight_alloc_ctx(1, 1, &msg);
- if (msg.warning != NULL)
- printer::inst()->print_msg(L0, "MEMORY ALLOC FAILED: %s", msg.warning);
- if (ctx == NULL)
- ctx = cryptonight_alloc_ctx(0, 0, NULL);
- return ctx;
-
- case jconf::always_use:
- return cryptonight_alloc_ctx(0, 0, NULL);
-
- case jconf::unknown_value:
- return NULL; //Shut up compiler
- }
-
- return nullptr; //Should never happen
-}
-
-bool minethd::self_test()
-{
- alloc_msg msg = { 0 };
- size_t res;
- bool fatal = false;
-
- switch (jconf::inst()->GetSlowMemSetting())
- {
- case jconf::never_use:
- res = cryptonight_init(1, 1, &msg);
- fatal = true;
- break;
-
- case jconf::no_mlck:
- res = cryptonight_init(1, 0, &msg);
- fatal = true;
- break;
-
- case jconf::print_warning:
- res = cryptonight_init(1, 1, &msg);
- break;
-
- case jconf::always_use:
- res = cryptonight_init(0, 0, &msg);
- break;
-
- case jconf::unknown_value:
- default:
- return false; //Shut up compiler
- }
-
- if(msg.warning != nullptr)
- printer::inst()->print_msg(L0, "MEMORY INIT ERROR: %s", msg.warning);
-
- if(res == 0 && fatal)
- return false;
-
- cryptonight_ctx *ctx0, *ctx1;
- if((ctx0 = minethd_alloc_ctx()) == nullptr)
- return false;
-
- if((ctx1 = minethd_alloc_ctx()) == nullptr)
- {
- cryptonight_free_ctx(ctx0);
- return false;
- }
-
- unsigned char out[64];
- bool bResult;
-
- cn_hash_fun hashf;
- cn_hash_fun_dbl hashdf;
-
- hashf = func_selector(jconf::inst()->HaveHardwareAes(), false);
- hashf("This is a test", 14, out, ctx0);
- bResult = memcmp(out, "\xa0\x84\xf0\x1d\x14\x37\xa0\x9c\x69\x85\x40\x1b\x60\xd4\x35\x54\xae\x10\x58\x02\xc5\xf5\xd8\xa9\xb3\x25\x36\x49\xc0\xbe\x66\x05", 32) == 0;
-
- hashf = func_selector(jconf::inst()->HaveHardwareAes(), true);
- hashf("This is a test", 14, out, ctx0);
- bResult &= memcmp(out, "\xa0\x84\xf0\x1d\x14\x37\xa0\x9c\x69\x85\x40\x1b\x60\xd4\x35\x54\xae\x10\x58\x02\xc5\xf5\xd8\xa9\xb3\x25\x36\x49\xc0\xbe\x66\x05", 32) == 0;
-
- hashdf = func_dbl_selector(jconf::inst()->HaveHardwareAes(), false);
- hashdf("The quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy log", 43, out, ctx0, ctx1);
- bResult &= memcmp(out, "\x3e\xbb\x7f\x9f\x7d\x27\x3d\x7c\x31\x8d\x86\x94\x77\x55\x0c\xc8\x00\xcf\xb1\x1b\x0c\xad\xb7\xff\xbd\xf6\xf8\x9f\x3a\x47\x1c\x59"
- "\xb4\x77\xd5\x02\xe4\xd8\x48\x7f\x42\xdf\xe3\x8e\xed\x73\x81\x7a\xda\x91\xb7\xe2\x63\xd2\x91\x71\xb6\x5c\x44\x3a\x01\x2a\x41\x22", 64) == 0;
-
- hashdf = func_dbl_selector(jconf::inst()->HaveHardwareAes(), true);
- hashdf("The quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy log", 43, out, ctx0, ctx1);
- bResult &= memcmp(out, "\x3e\xbb\x7f\x9f\x7d\x27\x3d\x7c\x31\x8d\x86\x94\x77\x55\x0c\xc8\x00\xcf\xb1\x1b\x0c\xad\xb7\xff\xbd\xf6\xf8\x9f\x3a\x47\x1c\x59"
- "\xb4\x77\xd5\x02\xe4\xd8\x48\x7f\x42\xdf\xe3\x8e\xed\x73\x81\x7a\xda\x91\xb7\xe2\x63\xd2\x91\x71\xb6\x5c\x44\x3a\x01\x2a\x41\x22", 64) == 0;
-
- cryptonight_free_ctx(ctx0);
- cryptonight_free_ctx(ctx1);
-
- if(!bResult)
- printer::inst()->print_msg(L0,
- "Cryptonight hash self-test failed. This might be caused by bad compiler optimizations.");
-
- return bResult;
-}
-
-std::vector<minethd*>* minethd::thread_starter(miner_work& pWork)
-{
- iGlobalJobNo = 0;
- iConsumeCnt = 0;
- std::vector<minethd*>* pvThreads = new std::vector<minethd*>;
-
- //Launch the requested number of single and double threads, to distribute
- //load evenly we need to alternate single and double threads
- size_t i, n = jconf::inst()->GetThreadCount();
- pvThreads->reserve(n);
-
- jconf::thd_cfg cfg;
- for (i = 0; i < n; i++)
- {
- jconf::inst()->GetThreadConfig(i, cfg);
-
- minethd* thd = new minethd(pWork, i, cfg.bDoubleMode, cfg.bNoPrefetch, cfg.iCpuAff);
- pvThreads->push_back(thd);
-
- if(cfg.iCpuAff >= 0)
- printer::inst()->print_msg(L1, "Starting %s thread, affinity: %d.", cfg.bDoubleMode ? "double" : "single", (int)cfg.iCpuAff);
- else
- printer::inst()->print_msg(L1, "Starting %s thread, no affinity.", cfg.bDoubleMode ? "double" : "single");
- }
-
- iThreadCount = n;
- return pvThreads;
-}
-
-void minethd::switch_work(miner_work& pWork)
-{
- // iConsumeCnt is a basic lock-like polling mechanism just in case we happen to push work
- // faster than threads can consume them. This should never happen in real life.
- // Pool cant physically send jobs faster than every 250ms or so due to net latency.
-
- while (iConsumeCnt.load(std::memory_order_seq_cst) < iThreadCount)
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
- oGlobalWork = pWork;
- iConsumeCnt.store(0, std::memory_order_seq_cst);
- iGlobalJobNo++;
-}
-
-void minethd::consume_work()
-{
- memcpy(&oWork, &oGlobalWork, sizeof(miner_work));
- iJobNo++;
- iConsumeCnt++;
-}
-
-minethd::cn_hash_fun minethd::func_selector(bool bHaveAes, bool bNoPrefetch)
-{
- // We have two independent flag bits in the functions
- // therefore we will build a binary digit and select the
- // function as a two digit binary
- // Digit order SOFT_AES, NO_PREFETCH
-
- static const cn_hash_fun func_table[4] = {
- cryptonight_hash<0x80000, MEMORY, false, false>,
- cryptonight_hash<0x80000, MEMORY, false, true>,
- cryptonight_hash<0x80000, MEMORY, true, false>,
- cryptonight_hash<0x80000, MEMORY, true, true>
- };
-
- std::bitset<2> digit;
- digit.set(0, !bNoPrefetch);
- digit.set(1, !bHaveAes);
-
- return func_table[digit.to_ulong()];
-}
-
-void minethd::pin_thd_affinity()
-{
- //Lock is needed because we need to use oWorkThd
- std::lock_guard<std::mutex> lock(work_thd_mtx);
-
- // pin memory to NUMA node
- bindMemoryToNUMANode(affinity);
-
-#if defined(__APPLE__)
- printer::inst()->print_msg(L1, "WARNING on MacOS thread affinity is only advisory.");
-#endif
- thd_setaffinity(oWorkThd.native_handle(), affinity);
-}
-
-void minethd::work_main()
-{
- if(affinity >= 0) //-1 means no affinity
- pin_thd_affinity();
-
- cn_hash_fun hash_fun;
- cryptonight_ctx* ctx;
- uint64_t iCount = 0;
- uint64_t* piHashVal;
- uint32_t* piNonce;
- job_result result;
-
- hash_fun = func_selector(jconf::inst()->HaveHardwareAes(), bNoPrefetch);
- ctx = minethd_alloc_ctx();
-
- piHashVal = (uint64_t*)(result.bResult + 24);
- piNonce = (uint32_t*)(oWork.bWorkBlob + 39);
- iConsumeCnt++;
-
- while (bQuit == 0)
- {
- if (oWork.bStall)
- {
- /* We are stalled here because the executor didn't find a job for us yet,
- either because of network latency, or a socket problem. Since we are
- raison d'etre of this software it us sensible to just wait until we have something*/
-
- while (iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo)
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
- consume_work();
- continue;
- }
-
- if(oWork.bNiceHash)
- result.iNonce = calc_nicehash_nonce(*piNonce, oWork.iResumeCnt);
- else
- result.iNonce = calc_start_nonce(oWork.iResumeCnt);
-
- assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID));
- memcpy(result.sJobID, oWork.sJobID, sizeof(job_result::sJobID));
-
- while(iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo)
- {
- if ((iCount & 0xF) == 0) //Store stats every 16 hashes
- {
- using namespace std::chrono;
- uint64_t iStamp = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
- iHashCount.store(iCount, std::memory_order_relaxed);
- iTimestamp.store(iStamp, std::memory_order_relaxed);
- }
- iCount++;
-
- *piNonce = ++result.iNonce;
-
- hash_fun(oWork.bWorkBlob, oWork.iWorkSize, result.bResult, ctx);
-
- if (*piHashVal < oWork.iTarget)
- executor::inst()->push_event(ex_event(result, oWork.iPoolId));
-
- std::this_thread::yield();
- }
-
- consume_work();
- }
-
- cryptonight_free_ctx(ctx);
-}
-
-minethd::cn_hash_fun_dbl minethd::func_dbl_selector(bool bHaveAes, bool bNoPrefetch)
-{
- // We have two independent flag bits in the functions
- // therefore we will build a binary digit and select the
- // function as a two digit binary
- // Digit order SOFT_AES, NO_PREFETCH
-
- static const cn_hash_fun_dbl func_table[4] = {
- cryptonight_double_hash<0x80000, MEMORY, false, false>,
- cryptonight_double_hash<0x80000, MEMORY, false, true>,
- cryptonight_double_hash<0x80000, MEMORY, true, false>,
- cryptonight_double_hash<0x80000, MEMORY, true, true>
- };
-
- std::bitset<2> digit;
- digit.set(0, !bNoPrefetch);
- digit.set(1, !bHaveAes);
-
- return func_table[digit.to_ulong()];
-}
-
-void minethd::double_work_main()
-{
- if(affinity >= 0) //-1 means no affinity
- pin_thd_affinity();
-
- cn_hash_fun_dbl hash_fun;
- cryptonight_ctx* ctx0;
- cryptonight_ctx* ctx1;
- uint64_t iCount = 0;
- uint64_t *piHashVal0, *piHashVal1;
- uint32_t *piNonce0, *piNonce1;
- uint8_t bDoubleHashOut[64];
- uint8_t bDoubleWorkBlob[sizeof(miner_work::bWorkBlob) * 2];
- uint32_t iNonce;
- job_result res;
-
- hash_fun = func_dbl_selector(jconf::inst()->HaveHardwareAes(), bNoPrefetch);
- ctx0 = minethd_alloc_ctx();
- ctx1 = minethd_alloc_ctx();
-
- piHashVal0 = (uint64_t*)(bDoubleHashOut + 24);
- piHashVal1 = (uint64_t*)(bDoubleHashOut + 32 + 24);
- piNonce0 = (uint32_t*)(bDoubleWorkBlob + 39);
- piNonce1 = nullptr;
-
- iConsumeCnt++;
-
- while (bQuit == 0)
- {
- if (oWork.bStall)
- {
- /* We are stalled here because the executor didn't find a job for us yet,
- either because of network latency, or a socket problem. Since we are
- raison d'etre of this software it us sensible to just wait until we have something*/
-
- while (iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo)
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
- consume_work();
- memcpy(bDoubleWorkBlob, oWork.bWorkBlob, oWork.iWorkSize);
- memcpy(bDoubleWorkBlob + oWork.iWorkSize, oWork.bWorkBlob, oWork.iWorkSize);
- piNonce1 = (uint32_t*)(bDoubleWorkBlob + oWork.iWorkSize + 39);
- continue;
- }
-
- if(oWork.bNiceHash)
- iNonce = calc_nicehash_nonce(*piNonce0, oWork.iResumeCnt);
- else
- iNonce = calc_start_nonce(oWork.iResumeCnt);
-
- assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID));
-
- while (iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo)
- {
- if ((iCount & 0x7) == 0) //Store stats every 16 hashes
- {
- using namespace std::chrono;
- uint64_t iStamp = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
- iHashCount.store(iCount, std::memory_order_relaxed);
- iTimestamp.store(iStamp, std::memory_order_relaxed);
- }
-
- iCount += 2;
-
- *piNonce0 = ++iNonce;
- *piNonce1 = ++iNonce;
-
- hash_fun(bDoubleWorkBlob, oWork.iWorkSize, bDoubleHashOut, ctx0, ctx1);
-
- if (*piHashVal0 < oWork.iTarget)
- executor::inst()->push_event(ex_event(job_result(oWork.sJobID, iNonce-1, bDoubleHashOut), oWork.iPoolId));
-
- if (*piHashVal1 < oWork.iTarget)
- executor::inst()->push_event(ex_event(job_result(oWork.sJobID, iNonce, bDoubleHashOut + 32), oWork.iPoolId));
-
- std::this_thread::yield();
- }
-
- consume_work();
- memcpy(bDoubleWorkBlob, oWork.bWorkBlob, oWork.iWorkSize);
- memcpy(bDoubleWorkBlob + oWork.iWorkSize, oWork.bWorkBlob, oWork.iWorkSize);
- piNonce1 = (uint32_t*)(bDoubleWorkBlob + oWork.iWorkSize + 39);
- }
-
- cryptonight_free_ctx(ctx0);
- cryptonight_free_ctx(ctx1);
-}
diff --git a/minethd.h b/minethd.h
deleted file mode 100644
index 293e8de..0000000
--- a/minethd.h
+++ /dev/null
@@ -1,144 +0,0 @@
-#pragma once
-#include <thread>
-#include <atomic>
-#include <mutex>
-#include "crypto/cryptonight.h"
-
-class telemetry
-{
-public:
- telemetry(size_t iThd);
- void push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTimestamp);
- double calc_telemetry_data(size_t iLastMilisec, size_t iThread);
-
-private:
- constexpr static size_t iBucketSize = 2 << 11; //Power of 2 to simplify calculations
- constexpr static size_t iBucketMask = iBucketSize - 1;
- uint32_t* iBucketTop;
- uint64_t** ppHashCounts;
- uint64_t** ppTimestamps;
-};
-
-class minethd
-{
-public:
- struct miner_work
- {
- char sJobID[64];
- uint8_t bWorkBlob[112];
- uint32_t iWorkSize;
- uint32_t iResumeCnt;
- uint64_t iTarget;
- bool bNiceHash;
- bool bStall;
- size_t iPoolId;
-
- miner_work() : iWorkSize(0), bStall(true), iPoolId(0) { }
-
- miner_work(const char* sJobID, const uint8_t* bWork, uint32_t iWorkSize, uint32_t iResumeCnt,
- uint64_t iTarget, bool bNiceHash, size_t iPoolId) : iWorkSize(iWorkSize), iResumeCnt(iResumeCnt),
- iTarget(iTarget), bNiceHash(bNiceHash), bStall(false), iPoolId(iPoolId)
- {
- assert(iWorkSize <= sizeof(bWorkBlob));
- memcpy(this->sJobID, sJobID, sizeof(miner_work::sJobID));
- memcpy(this->bWorkBlob, bWork, iWorkSize);
- }
-
- miner_work(miner_work const&) = delete;
-
- miner_work& operator=(miner_work const& from)
- {
- assert(this != &from);
-
- iWorkSize = from.iWorkSize;
- iResumeCnt = from.iResumeCnt;
- iTarget = from.iTarget;
- bNiceHash = from.bNiceHash;
- bStall = from.bStall;
- iPoolId = from.iPoolId;
-
- assert(iWorkSize <= sizeof(bWorkBlob));
- memcpy(sJobID, from.sJobID, sizeof(sJobID));
- memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
-
- return *this;
- }
-
- miner_work(miner_work&& from) : iWorkSize(from.iWorkSize), iTarget(from.iTarget),
- bStall(from.bStall), iPoolId(from.iPoolId)
- {
- assert(iWorkSize <= sizeof(bWorkBlob));
- memcpy(sJobID, from.sJobID, sizeof(sJobID));
- memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
- }
-
- miner_work& operator=(miner_work&& from)
- {
- assert(this != &from);
-
- iWorkSize = from.iWorkSize;
- iResumeCnt = from.iResumeCnt;
- iTarget = from.iTarget;
- bNiceHash = from.bNiceHash;
- bStall = from.bStall;
- iPoolId = from.iPoolId;
-
- assert(iWorkSize <= sizeof(bWorkBlob));
- memcpy(sJobID, from.sJobID, sizeof(sJobID));
- memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
-
- return *this;
- }
- };
-
- static void switch_work(miner_work& pWork);
- static std::vector<minethd*>* thread_starter(miner_work& pWork);
- static bool self_test();
-
- std::atomic<uint64_t> iHashCount;
- std::atomic<uint64_t> iTimestamp;
-
-private:
- typedef void (*cn_hash_fun)(const void*, size_t, void*, cryptonight_ctx*);
- typedef void (*cn_hash_fun_dbl)(const void*, size_t, void*, cryptonight_ctx* __restrict, cryptonight_ctx* __restrict);
-
- minethd(miner_work& pWork, size_t iNo, bool double_work, bool no_prefetch, int64_t affinity);
-
- // We use the top 10 bits of the nonce for thread and resume
- // This allows us to resume up to 128 threads 4 times before
- // we get nonce collisions
- // Bottom 22 bits allow for an hour of work at 1000 H/s
- inline uint32_t calc_start_nonce(uint32_t resume)
- { return (resume * iThreadCount + iThreadNo) << 22; }
-
- // Limited version of the nonce calc above
- inline uint32_t calc_nicehash_nonce(uint32_t start, uint32_t resume)
- { return start | (resume * iThreadCount + iThreadNo) << 18; }
-
- static cn_hash_fun func_selector(bool bHaveAes, bool bNoPrefetch);
- static cn_hash_fun_dbl func_dbl_selector(bool bHaveAes, bool bNoPrefetch);
-
- void work_main();
- void double_work_main();
- void consume_work();
-
- static std::atomic<uint64_t> iGlobalJobNo;
- static std::atomic<uint64_t> iConsumeCnt;
- static uint64_t iThreadCount;
- uint64_t iJobNo;
-
- static miner_work oGlobalWork;
- miner_work oWork;
-
- void pin_thd_affinity();
- // Held by the creating context to prevent a race cond with oWorkThd = std::thread(...)
- std::mutex work_thd_mtx;
-
- std::thread oWorkThd;
- uint8_t iThreadNo;
- int64_t affinity;
-
- bool bQuit;
- bool bNoPrefetch;
-};
-
diff --git a/msgstruct.h b/msgstruct.h
index 6f4a6fb..f3a39b2 100644
--- a/msgstruct.h
+++ b/msgstruct.h
@@ -11,6 +11,8 @@ struct pool_job
char sJobID[64];
uint8_t bWorkBlob[112];
uint64_t iTarget;
+ // \todo remove workaround needed for amd
+ uint32_t iTarget32;
uint32_t iWorkLen;
uint32_t iResumeCnt;
@@ -38,6 +40,7 @@ struct job_result
}
};
+
enum ex_event_name { EV_INVALID_VAL, EV_SOCK_READY, EV_SOCK_ERROR,
EV_POOL_HAVE_JOB, EV_MINER_HAVE_RESULT, EV_PERF_TICK, EV_RECONNECT,
EV_SWITCH_POOL, EV_DEV_POOL_EXIT, EV_USR_HASHRATE, EV_USR_RESULTS, EV_USR_CONNSTAT,
diff --git a/telemetry.cpp b/telemetry.cpp
new file mode 100644
index 0000000..fafccd5
--- /dev/null
+++ b/telemetry.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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
+ * 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/>.
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
+ */
+
+#include <cmath>
+#include <cstring>
+#include <chrono>
+#include "telemetry.h"
+
+namespace xmrstak
+{
+
+telemetry::telemetry(size_t iThd)
+{
+ ppHashCounts = new uint64_t*[iThd];
+ ppTimestamps = new uint64_t*[iThd];
+ iBucketTop = new uint32_t[iThd];
+
+ for (size_t i = 0; i < iThd; i++)
+ {
+ ppHashCounts[i] = new uint64_t[iBucketSize];
+ ppTimestamps[i] = new uint64_t[iBucketSize];
+ iBucketTop[i] = 0;
+ memset(ppHashCounts[i], 0, sizeof(uint64_t) * iBucketSize);
+ memset(ppTimestamps[i], 0, sizeof(uint64_t) * iBucketSize);
+ }
+}
+
+double telemetry::calc_telemetry_data(size_t iLastMilisec, size_t iThread)
+{
+ using namespace std::chrono;
+ uint64_t iTimeNow = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
+
+ uint64_t iEarliestHashCnt = 0;
+ uint64_t iEarliestStamp = 0;
+ uint64_t iLastestStamp = 0;
+ uint64_t iLastestHashCnt = 0;
+ bool bHaveFullSet = false;
+
+ //Start at 1, buckettop points to next empty
+ for (size_t i = 1; i < iBucketSize; i++)
+ {
+ size_t idx = (iBucketTop[iThread] - i) & iBucketMask; //overflow expected here
+
+ if (ppTimestamps[iThread][idx] == 0)
+ break; //That means we don't have the data yet
+
+ if (iLastestStamp == 0)
+ {
+ iLastestStamp = ppTimestamps[iThread][idx];
+ iLastestHashCnt = ppHashCounts[iThread][idx];
+ }
+
+ if (iTimeNow - ppTimestamps[iThread][idx] > iLastMilisec)
+ {
+ bHaveFullSet = true;
+ break; //We are out of the requested time period
+ }
+
+ iEarliestStamp = ppTimestamps[iThread][idx];
+ iEarliestHashCnt = ppHashCounts[iThread][idx];
+ }
+
+ if (!bHaveFullSet || iEarliestStamp == 0 || iLastestStamp == 0)
+ return nan("");
+
+ //Don't think that can happen, but just in case
+ if (iLastestStamp - iEarliestStamp == 0)
+ return nan("");
+
+ double fHashes, fTime;
+ fHashes = iLastestHashCnt - iEarliestHashCnt;
+ fTime = iLastestStamp - iEarliestStamp;
+ fTime /= 1000.0;
+
+ return fHashes / fTime;
+}
+
+void telemetry::push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTimestamp)
+{
+ size_t iTop = iBucketTop[iThd];
+ ppHashCounts[iThd][iTop] = iHashCount;
+ ppTimestamps[iThd][iTop] = iTimestamp;
+
+ iBucketTop[iThd] = (iTop + 1) & iBucketMask;
+}
+
+} // namepsace xmrstak
diff --git a/telemetry.h b/telemetry.h
new file mode 100644
index 0000000..0538090
--- /dev/null
+++ b/telemetry.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <cstdint>
+
+namespace xmrstak
+{
+
+class telemetry
+{
+public:
+ telemetry(size_t iThd);
+ void push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTimestamp);
+ double calc_telemetry_data(size_t iLastMilisec, size_t iThread);
+
+private:
+ constexpr static size_t iBucketSize = 2 << 11; //Power of 2 to simplify calculations
+ constexpr static size_t iBucketMask = iBucketSize - 1;
+ uint32_t* iBucketTop;
+ uint64_t** ppHashCounts;
+ uint64_t** ppTimestamps;
+};
+
+} // namepsace xmrstak
diff --git a/version.h b/version.h
index 04a6ced..44214c8 100644
--- a/version.h
+++ b/version.h
@@ -1,4 +1,4 @@
#pragma once
-#define XMR_STAK_NAME "xmr-stak-cpu"
-#define XMR_STAK_VERSION "1.3.0-1.5.0-dev"
+#define XMR_STAK_NAME "xmr-stak"
+#define XMR_STAK_VERSION "2.0.0-predev"
diff --git a/webdesign.cpp b/webdesign.cpp
index e07b015..4dfd3c2 100644
--- a/webdesign.cpp
+++ b/webdesign.cpp
@@ -115,7 +115,7 @@ extern const char sHtmlCommonHeader [] =
extern const char sHtmlHashrateBodyHigh [] =
"<div class=data>"
"<table>"
- "<tr><th>Thread ID</th><th>2.5s</th><th>60s</th><th>15m</th><th rowspan='%u'>H/s</td></tr>";
+ "<tr><th>Thread ID</th><th>10s</th><th>60s</th><th>15m</th><th rowspan='%u'>H/s</td></tr>";
extern const char sHtmlHashrateTableRow [] =
"<tr><th>%u</th><td>%s</td><td>%s</td><td>%s</td></tr>";
OpenPOWER on IntegriCloud