mirror of
https://github.com/xmrig/xmrig.git
synced 2025-01-22 02:34:58 +00:00
ICpuInfo refactoring.
This commit is contained in:
parent
39ae24b138
commit
628506e266
10 changed files with 110 additions and 206 deletions
|
@ -60,32 +60,7 @@ xmrig::ICpuInfo *xmrig::Cpu::info()
|
|||
|
||||
rapidjson::Value xmrig::Cpu::toJSON(rapidjson::Document &doc)
|
||||
{
|
||||
using namespace rapidjson;
|
||||
auto &allocator = doc.GetAllocator();
|
||||
|
||||
ICpuInfo *i = info();
|
||||
Value cpu(kObjectType);
|
||||
Assembly assembly(i->assembly());
|
||||
|
||||
cpu.AddMember("brand", StringRef(i->brand()), allocator);
|
||||
cpu.AddMember("aes", i->hasAES(), allocator);
|
||||
cpu.AddMember("avx2", i->hasAVX2(), allocator);
|
||||
cpu.AddMember("x64", ICpuInfo::isX64(), allocator);
|
||||
cpu.AddMember("l2", static_cast<uint64_t>(i->L2()), allocator);
|
||||
cpu.AddMember("l3", static_cast<uint64_t>(i->L3()), allocator);
|
||||
cpu.AddMember("cores", static_cast<uint64_t>(i->cores()), allocator);
|
||||
cpu.AddMember("threads", static_cast<uint64_t>(i->threads()), allocator);
|
||||
cpu.AddMember("packages", static_cast<uint64_t>(i->packages()), allocator);
|
||||
cpu.AddMember("nodes", static_cast<uint64_t>(i->nodes()), allocator);
|
||||
cpu.AddMember("backend", StringRef(i->backend()), allocator);
|
||||
|
||||
# ifdef XMRIG_FEATURE_ASM
|
||||
cpu.AddMember("assembly", StringRef(assembly.toString()), allocator);
|
||||
# else
|
||||
cpu.AddMember("assembly", "none", allocator);
|
||||
# endif
|
||||
|
||||
return cpu;
|
||||
return info()->toJSON(doc);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -70,11 +70,8 @@ else()
|
|||
)
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT WITH_LIBCPUID)
|
||||
if (XMRIG_ARM)
|
||||
set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo_arm.cpp)
|
||||
list(APPEND SOURCES_CPUID src/backend/cpu/platform/BasicCpuInfo_arm.cpp)
|
||||
else()
|
||||
set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo.cpp)
|
||||
endif()
|
||||
list(APPEND SOURCES_CPUID src/backend/cpu/platform/BasicCpuInfo.cpp)
|
||||
endif()
|
||||
|
|
|
@ -51,6 +51,19 @@ public:
|
|||
MSR_MOD_MAX
|
||||
};
|
||||
|
||||
enum Flag : uint32_t {
|
||||
FLAG_AES,
|
||||
FLAG_AVX2,
|
||||
FLAG_AVX512F,
|
||||
FLAG_BMI2,
|
||||
FLAG_OSXSAVE,
|
||||
FLAG_PDPE1GB,
|
||||
FLAG_SSE2,
|
||||
FLAG_SSSE3,
|
||||
FLAG_XOP,
|
||||
FLAG_MAX
|
||||
};
|
||||
|
||||
virtual ~ICpuInfo() = default;
|
||||
|
||||
# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__)
|
||||
|
@ -60,6 +73,7 @@ public:
|
|||
# endif
|
||||
|
||||
virtual Assembly::Id assembly() const = 0;
|
||||
virtual bool has(Flag feature) const = 0;
|
||||
virtual bool hasAES() const = 0;
|
||||
virtual bool hasAVX2() const = 0;
|
||||
virtual bool hasBMI2() const = 0;
|
||||
|
@ -68,6 +82,7 @@ public:
|
|||
virtual const char *brand() const = 0;
|
||||
virtual CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const = 0;
|
||||
virtual MsrMod msrMod() const = 0;
|
||||
virtual rapidjson::Value toJSON(rapidjson::Document &doc) const = 0;
|
||||
virtual size_t cores() const = 0;
|
||||
virtual size_t L2() const = 0;
|
||||
virtual size_t L3() const = 0;
|
||||
|
|
|
@ -26,13 +26,6 @@
|
|||
#include "3rdparty/libcpuid/libcpuid.h"
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <intrin.h>
|
||||
#else
|
||||
# include <cpuid.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
@ -40,59 +33,7 @@
|
|||
#include <cstring>
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
static inline void cpu_brand_string(char out[64], const char *in) {
|
||||
size_t pos = 0;
|
||||
const size_t size = strlen(in);
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (in[i] == ' ' && ((pos > 0 && out[pos - 1] == ' ') || pos == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
out[pos++] = in[i];
|
||||
}
|
||||
|
||||
if (pos > 0 && out[pos - 1] == ' ') {
|
||||
out[pos - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void cpuid(uint32_t level, int32_t output[4])
|
||||
{
|
||||
memset(output, 0, sizeof(int32_t) * 4);
|
||||
|
||||
# ifdef _MSC_VER
|
||||
__cpuid(output, static_cast<int>(level));
|
||||
# else
|
||||
__cpuid_count(level, 0, output[0], output[1], output[2], output[3]);
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
static inline bool has_feature(uint32_t level, uint32_t reg, int32_t bit)
|
||||
{
|
||||
int32_t cpu_info[4] = { 0 };
|
||||
cpuid(level, cpu_info);
|
||||
|
||||
return (cpu_info[reg] & bit) != 0;
|
||||
}
|
||||
|
||||
|
||||
static inline bool has_pdpe1gb()
|
||||
{
|
||||
return has_feature(0x80000001, 3, 1 << 26);
|
||||
}
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
|
||||
|
||||
xmrig::AdvancedCpuInfo::AdvancedCpuInfo() :
|
||||
m_pdpe1gb(has_pdpe1gb())
|
||||
xmrig::AdvancedCpuInfo::AdvancedCpuInfo()
|
||||
{
|
||||
struct cpu_raw_data_t raw = {};
|
||||
struct cpu_id_t data = {};
|
||||
|
@ -100,18 +41,10 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() :
|
|||
cpuid_get_raw_data(&raw);
|
||||
cpu_identify(&raw, &data);
|
||||
|
||||
cpu_brand_string(m_brand, data.brand_str);
|
||||
snprintf(m_backend, sizeof m_backend, "libcpuid/%s", cpuid_lib_version());
|
||||
|
||||
if (data.vendor == ::VENDOR_INTEL) {
|
||||
m_vendor = VENDOR_INTEL;
|
||||
}
|
||||
else if (data.vendor == ::VENDOR_AMD) {
|
||||
m_vendor = VENDOR_AMD;
|
||||
}
|
||||
|
||||
m_threads = static_cast<size_t>(data.total_logical_cpus);
|
||||
m_packages = std::max<size_t>(threads() / static_cast<size_t>(data.num_logical_cpus), 1);
|
||||
m_packages = std::max<size_t>(m_threads / static_cast<size_t>(data.num_logical_cpus), 1);
|
||||
m_cores = static_cast<size_t>(data.num_cores) * m_packages;
|
||||
m_L3 = data.l3_cache > 0 ? static_cast<size_t>(data.l3_cache) * m_packages : 0;
|
||||
|
||||
|
@ -134,26 +67,6 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() :
|
|||
|
||||
m_L2 *= 1024;
|
||||
m_L3 *= 1024;
|
||||
|
||||
if (data.flags[CPU_FEATURE_AES]) {
|
||||
m_aes = true;
|
||||
|
||||
if (m_vendor == VENDOR_AMD) {
|
||||
if (data.ext_family >= 23) {
|
||||
m_assembly = Assembly::RYZEN;
|
||||
m_msrMod = MSR_MOD_RYZEN;
|
||||
}
|
||||
else {
|
||||
m_assembly = Assembly::BULLDOZER;
|
||||
}
|
||||
}
|
||||
else if (m_vendor == VENDOR_INTEL) {
|
||||
m_assembly = Assembly::INTEL;
|
||||
}
|
||||
}
|
||||
|
||||
m_avx2 = data.flags[CPU_FEATURE_AVX2] && data.flags[CPU_FEATURE_OSXSAVE];
|
||||
m_bmi2 = data.flags[CPU_FEATURE_BMI2];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,13 +26,13 @@
|
|||
#define XMRIG_ADVANCEDCPUINFO_H
|
||||
|
||||
|
||||
#include "backend/cpu/interfaces/ICpuInfo.h"
|
||||
#include "backend/cpu/platform/BasicCpuInfo.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
class AdvancedCpuInfo : public ICpuInfo
|
||||
class AdvancedCpuInfo : public BasicCpuInfo
|
||||
{
|
||||
public:
|
||||
AdvancedCpuInfo();
|
||||
|
@ -40,38 +40,20 @@ public:
|
|||
protected:
|
||||
CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
|
||||
|
||||
inline Assembly::Id assembly() const override { return m_assembly; }
|
||||
inline bool hasAES() const override { return m_aes; }
|
||||
inline bool hasAVX2() const override { return m_avx2; }
|
||||
inline bool hasBMI2() const override { return m_bmi2; }
|
||||
inline bool hasOneGbPages() const override { return m_pdpe1gb; }
|
||||
inline const char *backend() const override { return m_backend; }
|
||||
inline const char *brand() const override { return m_brand; }
|
||||
inline MsrMod msrMod() const override { return m_msrMod; }
|
||||
inline size_t cores() const override { return m_cores; }
|
||||
inline size_t L2() const override { return m_L2; }
|
||||
inline size_t L3() const override { return m_L3; }
|
||||
inline size_t nodes() const override { return 0; }
|
||||
inline size_t packages() const override { return m_packages; }
|
||||
inline size_t threads() const override { return m_threads; }
|
||||
inline Vendor vendor() const override { return m_vendor; }
|
||||
|
||||
private:
|
||||
Assembly m_assembly;
|
||||
bool m_aes = false;
|
||||
bool m_avx2 = false;
|
||||
bool m_bmi2 = false;
|
||||
bool m_L2_exclusive = false;
|
||||
char m_backend[32]{};
|
||||
char m_brand[64 + 5]{};
|
||||
const bool m_pdpe1gb = false;
|
||||
MsrMod m_msrMod = MSR_MOD_NONE;
|
||||
size_t m_cores = 0;
|
||||
size_t m_L2 = 0;
|
||||
size_t m_L3 = 0;
|
||||
size_t m_packages = 1;
|
||||
size_t m_threads = 0;
|
||||
Vendor m_vendor = VENDOR_UNKNOWN;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -33,28 +33,9 @@
|
|||
# include <cpuid.h>
|
||||
#endif
|
||||
|
||||
#ifndef bit_AES
|
||||
# define bit_AES (1 << 25)
|
||||
#endif
|
||||
|
||||
#ifndef bit_OSXSAVE
|
||||
# define bit_OSXSAVE (1 << 27)
|
||||
#endif
|
||||
|
||||
#ifndef bit_AVX2
|
||||
# define bit_AVX2 (1 << 5)
|
||||
#endif
|
||||
|
||||
#ifndef bit_BMI2
|
||||
# define bit_BMI2 (1 << 8)
|
||||
#endif
|
||||
|
||||
#ifndef bit_PDPE1GB
|
||||
# define bit_PDPE1GB (1 << 26)
|
||||
#endif
|
||||
|
||||
|
||||
#include "backend/cpu/platform/BasicCpuInfo.h"
|
||||
#include "3rdparty/rapidjson/document.h"
|
||||
#include "crypto/common/Assembly.h"
|
||||
|
||||
|
||||
|
@ -75,6 +56,11 @@
|
|||
namespace xmrig {
|
||||
|
||||
|
||||
static const std::array<const char *, ICpuInfo::FLAG_MAX> flagNames = { "aes", "avx2", "avx512f", "bmi2", "osxsave", "pdpe1gb", "sse2", "ssse3", "xop" };
|
||||
static const std::array<const char *, ICpuInfo::MSR_MOD_MAX> msrNames = { "none", "ryzen", "intel", "custom" };
|
||||
std::bitset<ICpuInfo::FLAG_MAX> BasicCpuInfo::m_flags;
|
||||
|
||||
|
||||
static inline void cpuid(uint32_t level, int32_t output[4])
|
||||
{
|
||||
memset(output, 0, sizeof(int32_t) * 4);
|
||||
|
@ -133,42 +119,35 @@ static inline int32_t get_masked(int32_t val, int32_t h, int32_t l)
|
|||
}
|
||||
|
||||
|
||||
static inline bool has_aes_ni()
|
||||
{
|
||||
return has_feature(PROCESSOR_INFO, ECX_Reg, bit_AES);
|
||||
}
|
||||
|
||||
|
||||
static inline bool has_avx2()
|
||||
{
|
||||
return has_feature(EXTENDED_FEATURES, EBX_Reg, bit_AVX2) && has_feature(PROCESSOR_INFO, ECX_Reg, bit_OSXSAVE);
|
||||
}
|
||||
|
||||
|
||||
static inline bool has_bmi2()
|
||||
{
|
||||
return has_feature(EXTENDED_FEATURES, EBX_Reg, bit_BMI2);
|
||||
}
|
||||
|
||||
|
||||
static inline bool has_pdpe1gb()
|
||||
{
|
||||
return has_feature(PROCESSOR_EXT_INFO, EDX_Reg, bit_PDPE1GB);
|
||||
}
|
||||
static inline bool has_osxsave() { return has_feature(PROCESSOR_INFO, ECX_Reg, 1 << 27); }
|
||||
static inline bool has_aes_ni() { return has_feature(PROCESSOR_INFO, ECX_Reg, 1 << 25); }
|
||||
static inline bool has_avx2() { return has_feature(EXTENDED_FEATURES, EBX_Reg, 1 << 5) && has_osxsave(); }
|
||||
static inline bool has_avx512f() { return has_feature(EXTENDED_FEATURES, EBX_Reg, 1 << 16) && has_osxsave(); }
|
||||
static inline bool has_bmi2() { return has_feature(EXTENDED_FEATURES, EBX_Reg, 1 << 8); }
|
||||
static inline bool has_pdpe1gb() { return has_feature(PROCESSOR_EXT_INFO, EDX_Reg, 1 << 26); }
|
||||
static inline bool has_sse2() { return has_feature(PROCESSOR_INFO, EDX_Reg, 1 << 26); }
|
||||
static inline bool has_ssse3() { return has_feature(PROCESSOR_INFO, ECX_Reg, 1 << 9); }
|
||||
static inline bool has_xop() { return has_feature(0x80000001, ECX_Reg, 1 << 11); }
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
|
||||
|
||||
xmrig::BasicCpuInfo::BasicCpuInfo() :
|
||||
m_threads(std::thread::hardware_concurrency()),
|
||||
m_aes(has_aes_ni()),
|
||||
m_avx2(has_avx2()),
|
||||
m_bmi2(has_bmi2()),
|
||||
m_pdpe1gb(has_pdpe1gb())
|
||||
m_threads(std::thread::hardware_concurrency())
|
||||
{
|
||||
cpu_brand_string(m_brand);
|
||||
|
||||
m_flags.set(FLAG_AES, has_aes_ni());
|
||||
m_flags.set(FLAG_AVX2, has_avx2());
|
||||
m_flags.set(FLAG_AVX512F, has_avx512f());
|
||||
m_flags.set(FLAG_BMI2, has_bmi2());
|
||||
m_flags.set(FLAG_OSXSAVE, has_osxsave());
|
||||
m_flags.set(FLAG_PDPE1GB, has_pdpe1gb());
|
||||
m_flags.set(FLAG_SSE2, has_sse2());
|
||||
m_flags.set(FLAG_SSSE3, has_ssse3());
|
||||
m_flags.set(FLAG_XOP, has_xop());
|
||||
|
||||
# ifdef XMRIG_FEATURE_ASM
|
||||
if (hasAES()) {
|
||||
char vendor[13] = { 0 };
|
||||
|
@ -206,7 +185,7 @@ xmrig::BasicCpuInfo::BasicCpuInfo() :
|
|||
|
||||
const char *xmrig::BasicCpuInfo::backend() const
|
||||
{
|
||||
return "basic";
|
||||
return "basic/1";
|
||||
}
|
||||
|
||||
|
||||
|
@ -270,3 +249,43 @@ xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm, uint3
|
|||
|
||||
return CpuThreads(std::max<size_t>(count / 2, 1), 1);
|
||||
}
|
||||
|
||||
|
||||
rapidjson::Value xmrig::BasicCpuInfo::toJSON(rapidjson::Document &doc) const
|
||||
{
|
||||
using namespace rapidjson;
|
||||
auto &allocator = doc.GetAllocator();
|
||||
|
||||
Value out(kObjectType);
|
||||
|
||||
out.AddMember("brand", StringRef(brand()), allocator);
|
||||
out.AddMember("aes", hasAES(), allocator);
|
||||
out.AddMember("avx2", hasAVX2(), allocator);
|
||||
out.AddMember("x64", ICpuInfo::isX64(), allocator);
|
||||
out.AddMember("l2", static_cast<uint64_t>(L2()), allocator);
|
||||
out.AddMember("l3", static_cast<uint64_t>(L3()), allocator);
|
||||
out.AddMember("cores", static_cast<uint64_t>(cores()), allocator);
|
||||
out.AddMember("threads", static_cast<uint64_t>(threads()), allocator);
|
||||
out.AddMember("packages", static_cast<uint64_t>(packages()), allocator);
|
||||
out.AddMember("nodes", static_cast<uint64_t>(nodes()), allocator);
|
||||
out.AddMember("backend", StringRef(backend()), allocator);
|
||||
out.AddMember("msr", StringRef(msrNames[msrMod()]), allocator);
|
||||
|
||||
# ifdef XMRIG_FEATURE_ASM
|
||||
out.AddMember("assembly", StringRef(Assembly(assembly()).toString()), allocator);
|
||||
# else
|
||||
cpu.AddMember("assembly", "none", allocator);
|
||||
# endif
|
||||
|
||||
Value flags(kArrayType);
|
||||
|
||||
for (size_t i = 0; i < flagNames.size(); ++i) {
|
||||
if (m_flags.test(i)) {
|
||||
flags.PushBack(StringRef(flagNames[i]), allocator);
|
||||
}
|
||||
}
|
||||
|
||||
out.AddMember("flags", flags, allocator);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#include "backend/cpu/interfaces/ICpuInfo.h"
|
||||
|
||||
|
||||
#include <bitset>
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
|
@ -40,12 +43,14 @@ public:
|
|||
protected:
|
||||
const char *backend() const override;
|
||||
CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
|
||||
rapidjson::Value toJSON(rapidjson::Document &doc) const override;
|
||||
|
||||
inline Assembly::Id assembly() const override { return m_assembly; }
|
||||
inline bool hasAES() const override { return m_aes; }
|
||||
inline bool hasAVX2() const override { return m_avx2; }
|
||||
inline bool hasBMI2() const override { return m_bmi2; }
|
||||
inline bool hasOneGbPages() const override { return m_pdpe1gb; }
|
||||
inline bool has(Flag flag) const override { return m_flags.test(flag); }
|
||||
inline bool hasAES() const override { return has(FLAG_AES); }
|
||||
inline bool hasAVX2() const override { return has(FLAG_AVX2); }
|
||||
inline bool hasBMI2() const override { return has(FLAG_BMI2); }
|
||||
inline bool hasOneGbPages() const override { return has(FLAG_PDPE1GB); }
|
||||
inline const char *brand() const override { return m_brand; }
|
||||
inline MsrMod msrMod() const override { return m_msrMod; }
|
||||
inline size_t cores() const override { return 0; }
|
||||
|
@ -59,15 +64,13 @@ protected:
|
|||
protected:
|
||||
char m_brand[64 + 6]{};
|
||||
size_t m_threads;
|
||||
Vendor m_vendor = VENDOR_UNKNOWN;
|
||||
|
||||
private:
|
||||
static std::bitset<FLAG_MAX> m_flags;
|
||||
|
||||
Assembly m_assembly = Assembly::NONE;
|
||||
bool m_aes = false;
|
||||
const bool m_avx2 = false;
|
||||
const bool m_bmi2 = false;
|
||||
const bool m_pdpe1gb = false;
|
||||
MsrMod m_msrMod = MSR_MOD_NONE;
|
||||
Vendor m_vendor = VENDOR_UNKNOWN;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ xmrig::BasicCpuInfo::BasicCpuInfo() :
|
|||
|
||||
# if __ARM_FEATURE_CRYPTO
|
||||
# if !defined(__APPLE__)
|
||||
m_aes = getauxval(AT_HWCAP) & HWCAP_AES;
|
||||
m_flags.set(FLAG_AES, getauxval(AT_HWCAP) & HWCAP_AES);
|
||||
# else
|
||||
m_aes = true;
|
||||
m_flags.set(FLAG_AES, true);
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2019 XMRig <support@xmrig.com>
|
||||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2020 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
|
||||
|
@ -313,7 +313,7 @@ void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorith
|
|||
size_t cacheHashes = ((L3 + extra) + (scratchpad / 2)) / scratchpad;
|
||||
|
||||
# ifdef XMRIG_ALGO_CN_PICO
|
||||
if (algorithm == Algorithm::CN_PICO_0 && (cacheHashes / PUs) >= 2) {
|
||||
if (intensity && algorithm == Algorithm::CN_PICO_0 && (cacheHashes / PUs) >= 2) {
|
||||
intensity = 2;
|
||||
}
|
||||
# endif
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2019 XMRig <support@xmrig.com>
|
||||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2020 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
|
||||
|
|
Loading…
Reference in a new issue