From c2fcf2385526223e804dc729847d7534223fd293 Mon Sep 17 00:00:00 2001 From: XMRig Date: Mon, 24 Sep 2018 14:19:26 +0300 Subject: [PATCH] Implemented "asm" option. --- CMakeLists.txt | 2 +- cmake/asm.cmake | 2 + src/Summary.cpp | 29 +++++++++ src/common/interfaces/IConfig.h | 1 + src/common/xmrig.h | 3 +- src/core/Config.cpp | 21 +++++-- src/core/Config.h | 9 +-- src/core/ConfigLoader_platform.h | 2 + src/core/cpu/AdvancedCpuInfo.cpp | 2 +- src/crypto/Asm.cpp | 100 +++++++++++++++++++++++++++++++ src/crypto/Asm.h | 50 ++++++++++++++++ src/crypto/CryptoNight_x86.h | 2 + src/workers/CpuThread.cpp | 71 +++++++++++++++++----- src/workers/CpuThread.h | 15 +++-- 14 files changed, 275 insertions(+), 34 deletions(-) create mode 100644 src/crypto/Asm.cpp create mode 100644 src/crypto/Asm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b3fe6f2c..1becac5ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,5 +255,5 @@ if (WITH_DEBUG_LOG) add_definitions(/DAPP_DEBUG) endif() -add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES} ${TLS_SOURCES}) +add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES} ${TLS_SOURCES} ${XMRIG_ASM_SOURCES}) target_link_libraries(${PROJECT_NAME} ${XMRIG_ASM_LIBRARY} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) diff --git a/cmake/asm.cmake b/cmake/asm.cmake index 3a0bc8945..a9b76ffda 100644 --- a/cmake/asm.cmake +++ b/cmake/asm.cmake @@ -15,8 +15,10 @@ if (WITH_ASM AND NOT XMRIG_ARM) ) endif() + set(XMRIG_ASM_SOURCES src/crypto/Asm.h src/crypto/Asm.cpp) set_property(TARGET ${XMRIG_ASM_LIBRARY} PROPERTY LINKER_LANGUAGE C) else() + set(XMRIG_ASM_SOURCES "") set(XMRIG_ASM_LIBRARY "") add_definitions(/DXMRIG_NO_ASM) endif() diff --git a/src/Summary.cpp b/src/Summary.cpp index ba220e5b1..3c1d06a70 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -32,11 +32,28 @@ #include "common/net/Pool.h" #include "core/Config.h" #include "core/Controller.h" +#include "crypto/Asm.h" #include "Mem.h" #include "Summary.h" #include "version.h" +#ifndef XMRIG_NO_ASM +static const char *coloredAsmNames[] = { + "\x1B[1;31mnone\x1B[0m", + "auto", + "\x1B[1;32mintel\x1B[0m", + "\x1B[1;32mryzen\x1B[0m" +}; + + +inline static const char *asmName(xmrig::Assembly assembly, bool colors) +{ + return colors ? coloredAsmNames[assembly] : xmrig::Asm::toString(assembly); +} +#endif + + static void print_memory(xmrig::Config *config) { # ifdef _WIN32 if (config->isColors()) { @@ -101,6 +118,18 @@ static void print_threads(xmrig::Config *config) config->isColors() && config->donateLevel() == 0 ? "\x1B[1;31m" : "", config->donateLevel()); } + +# ifndef XMRIG_NO_ASM + if (config->assembly() == xmrig::ASM_AUTO) { + const xmrig::Assembly assembly = xmrig::Cpu::info()->assembly(); + + Log::i()->text(config->isColors() ? GREEN_BOLD(" * ") WHITE_BOLD("%-13sauto:%s") + : " * %-13sauto:%s", "ASSEMBLY", asmName(assembly, config->isColors())); + } + else { + Log::i()->text(config->isColors() ? GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s") : " * %-13s%s", "ASSEMBLY", asmName(config->assembly(), config->isColors())); + } +# endif } diff --git a/src/common/interfaces/IConfig.h b/src/common/interfaces/IConfig.h index d35931634..0fcac2d15 100644 --- a/src/common/interfaces/IConfig.h +++ b/src/common/interfaces/IConfig.h @@ -80,6 +80,7 @@ public: SafeKey = 1005, ThreadsKey = 't', HardwareAESKey = 1011, + AssemblyKey = 1015, // xmrig amd OclPlatformKey = 1400, diff --git a/src/common/xmrig.h b/src/common/xmrig.h index 820bc4fbe..52650f0d2 100644 --- a/src/common/xmrig.h +++ b/src/common/xmrig.h @@ -98,7 +98,8 @@ enum Assembly { ASM_NONE, ASM_AUTO, ASM_INTEL, - ASM_RYZEN + ASM_RYZEN, + ASM_MAX }; diff --git a/src/core/Config.cpp b/src/core/Config.cpp index d99bfb095..20a3aece0 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -30,6 +30,7 @@ #include "common/cpu/Cpu.h" #include "core/Config.h" #include "core/ConfigCreator.h" +#include "crypto/Asm.h" #include "crypto/CryptoNight_constants.h" #include "rapidjson/document.h" #include "rapidjson/filewritestream.h" @@ -43,6 +44,7 @@ static char affinity_tmp[20] = { 0 }; xmrig::Config::Config() : xmrig::CommonConfig(), m_aesMode(AES_AUTO), m_algoVariant(AV_AUTO), + m_assembly(ASM_AUTO), m_hugePages(true), m_safe(false), m_maxCpuUsage(75), @@ -51,11 +53,6 @@ xmrig::Config::Config() : xmrig::CommonConfig(), } -xmrig::Config::~Config() -{ -} - - bool xmrig::Config::reload(const char *json) { return xmrig::ConfigLoader::reload(this, json); @@ -178,7 +175,7 @@ bool xmrig::Config::finalize() } for (size_t i = 0; i < m_threads.count; ++i) { - m_threads.list.push_back(CpuThread::createFromAV(i, m_algorithm.algo(), av, m_threads.mask, m_priority)); + m_threads.list.push_back(CpuThread::createFromAV(i, m_algorithm.algo(), av, m_threads.mask, m_priority, m_assembly)); } return true; @@ -204,6 +201,12 @@ bool xmrig::Config::parseBoolean(int key, bool enable) m_aesMode = enable ? AES_HW : AES_SOFT; break; +# ifndef XMRIG_NO_ASM + case AssemblyKey: + m_assembly = Asm::parse(enable); + break; +# endif + default: break; } @@ -244,6 +247,12 @@ bool xmrig::Config::parseString(int key, const char *arg) return parseUint64(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10)); } +# ifndef XMRIG_NO_ASM + case AssemblyKey: /* --asm */ + m_assembly = Asm::parse(arg); + break; +# endif + default: break; } diff --git a/src/core/Config.h b/src/core/Config.h index f0f1404fb..95afc34cd 100644 --- a/src/core/Config.h +++ b/src/core/Config.h @@ -21,8 +21,8 @@ * along with this program. If not, see . */ -#ifndef __CONFIG_H__ -#define __CONFIG_H__ +#ifndef XMRIG_CONFIG_H +#define XMRIG_CONFIG_H #include @@ -69,7 +69,6 @@ public: Config(); - ~Config(); bool reload(const char *json); @@ -77,6 +76,7 @@ public: inline AesMode aesMode() const { return m_aesMode; } inline AlgoVariant algoVariant() const { return m_algoVariant; } + inline Assembly assembly() const { return m_assembly; } inline bool isHugePages() const { return m_hugePages; } inline const std::vector &threads() const { return m_threads.list; } inline int priority() const { return m_priority; } @@ -116,6 +116,7 @@ private: AesMode m_aesMode; AlgoVariant m_algoVariant; + Assembly m_assembly; bool m_hugePages; bool m_safe; int m_maxCpuUsage; @@ -126,4 +127,4 @@ private: } /* namespace xmrig */ -#endif /* __CONFIG_H__ */ +#endif /* XMRIG_CONFIG_H */ diff --git a/src/core/ConfigLoader_platform.h b/src/core/ConfigLoader_platform.h index c034f3e75..3b95a90fc 100644 --- a/src/core/ConfigLoader_platform.h +++ b/src/core/ConfigLoader_platform.h @@ -135,6 +135,7 @@ static struct option const options[] = { { "tls", 0, nullptr, xmrig::IConfig::TlsKey }, { "tls-fingerprint", 1, nullptr, xmrig::IConfig::FingerprintKey }, { "version", 0, nullptr, xmrig::IConfig::VersionKey }, + { "asm", 1, nullptr, xmrig::IConfig::AssemblyKey }, { nullptr, 0, nullptr, 0 } }; @@ -159,6 +160,7 @@ static struct option const config_options[] = { { "threads", 1, nullptr, xmrig::IConfig::ThreadsKey }, { "user-agent", 1, nullptr, xmrig::IConfig::UserAgentKey }, { "hw-aes", 0, nullptr, xmrig::IConfig::HardwareAESKey }, + { "asm", 1, nullptr, xmrig::IConfig::AssemblyKey }, { nullptr, 0, nullptr, 0 } }; diff --git a/src/core/cpu/AdvancedCpuInfo.cpp b/src/core/cpu/AdvancedCpuInfo.cpp index ac5508c38..1f86a4205 100644 --- a/src/core/cpu/AdvancedCpuInfo.cpp +++ b/src/core/cpu/AdvancedCpuInfo.cpp @@ -47,7 +47,7 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : cpuid_get_raw_data(&raw); cpu_identify(&raw, &data); - strncpy(m_brand, data.brand_str, sizeof(m_brand) - 1); + strncpy(m_brand, data.brand_str, sizeof(m_brand)); m_sockets = threads() / data.num_logical_cpus; if (m_sockets == 0) { diff --git a/src/crypto/Asm.cpp b/src/crypto/Asm.cpp new file mode 100644 index 000000000..79dd1cc9c --- /dev/null +++ b/src/crypto/Asm.cpp @@ -0,0 +1,100 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * 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 . + */ + + +#include +#include + + +#ifdef _MSC_VER +# define strncasecmp _strnicmp +# define strcasecmp _stricmp +#endif + + +#include "crypto/Asm.h" +#include "rapidjson/document.h" + + +static const char *asmNames[] = { + "none", + "auto", + "intel", + "ryzen" +}; + + +xmrig::Assembly xmrig::Asm::parse(const char *assembly, Assembly defaultValue) +{ + constexpr size_t const size = sizeof(asmNames) / sizeof((asmNames)[0]); + assert(assembly != nullptr); + assert(ASM_MAX == size); + + if (assembly == nullptr) { + return defaultValue; + } + + for (size_t i = 0; i < size; i++) { + if (strcasecmp(assembly, asmNames[i]) == 0) { + return static_cast(i); + } + } + + return defaultValue; +} + + +xmrig::Assembly xmrig::Asm::parse(const rapidjson::Value &value, Assembly defaultValue) +{ + if (value.IsBool()) { + return parse(value.IsBool()); + } + + if (value.IsString()) { + return parse(value.GetString(), defaultValue); + } + + return defaultValue; +} + + +const char *xmrig::Asm::toString(Assembly assembly) +{ + return asmNames[assembly]; +} + + +rapidjson::Value xmrig::Asm::toJSON(Assembly assembly) +{ + using namespace rapidjson; + + if (assembly == ASM_NONE) { + return Value(false); + } + + if (assembly == ASM_AUTO) { + return Value(true); + } + + return Value(StringRef(toString(assembly))); +} diff --git a/src/crypto/Asm.h b/src/crypto/Asm.h new file mode 100644 index 000000000..3b755fd64 --- /dev/null +++ b/src/crypto/Asm.h @@ -0,0 +1,50 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_ASM_H +#define XMRIG_ASM_H + + +#include "common/xmrig.h" +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class Asm +{ +public: + static Assembly parse(const char *assembly, Assembly defaultValue = ASM_AUTO); + static Assembly parse(const rapidjson::Value &value, Assembly defaultValue = ASM_AUTO); + static const char *toString(Assembly assembly); + static rapidjson::Value toJSON(Assembly assembly); + + inline static Assembly parse(bool enable) { return enable ? ASM_AUTO : ASM_NONE; } +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_ASM_H */ diff --git a/src/crypto/CryptoNight_x86.h b/src/crypto/CryptoNight_x86.h index 064dbdc28..42ea37b55 100644 --- a/src/crypto/CryptoNight_x86.h +++ b/src/crypto/CryptoNight_x86.h @@ -561,6 +561,7 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si } +#ifndef XMRIG_NO_ASM extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx *ctx); extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx *ctx); @@ -584,6 +585,7 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ xmrig::keccakf(reinterpret_cast(ctx[0]->state), 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } +#endif template diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThread.cpp index d9d60f51c..ff6be5859 100644 --- a/src/workers/CpuThread.cpp +++ b/src/workers/CpuThread.cpp @@ -24,8 +24,10 @@ #include +#include "common/cpu/Cpu.h" #include "common/log/Log.h" #include "common/net/Pool.h" +#include "crypto/Asm.h" #include "rapidjson/document.h" #include "workers/CpuThread.h" @@ -37,9 +39,10 @@ #endif -xmrig::CpuThread::CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch) : +xmrig::CpuThread::CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : m_algorithm(algorithm), m_av(av), + m_assembly(assembly), m_prefetch(prefetch), m_softAES(softAES), m_priority(priority), @@ -50,23 +53,23 @@ xmrig::CpuThread::CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiw } -xmrig::CpuThread::~CpuThread() -{ -} - - bool xmrig::CpuThread::isSoftAES(AlgoVariant av) { return av == AV_SINGLE_SOFT || av == AV_DOUBLE_SOFT || av > AV_PENTA; } -xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant av, Variant variant) +xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant av, Variant variant, Assembly assembly) { assert(variant >= VARIANT_0 && variant < VARIANT_MAX); +# ifndef XMRIG_NO_ASM + constexpr const size_t count = VARIANT_MAX * 10 * 3 + 2; +# else constexpr const size_t count = VARIANT_MAX * 10 * 3; - static const cn_hash_fun func_table[count + 2] = { +# endif + + static const cn_hash_fun func_table[count] = { cryptonight_single_hash, cryptonight_double_hash, cryptonight_single_hash, @@ -243,13 +246,14 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, # endif +# ifndef XMRIG_NO_ASM cryptonight_single_hash_asm, cryptonight_single_hash_asm +# endif }; - const size_t index = VARIANT_MAX * 10 * algorithm + 10 * variant + av - 1; - # ifndef NDEBUG + const size_t index = fnIndex(algorithm, av, variant, assembly); cn_hash_fun func = func_table[index]; assert(index < sizeof(func_table) / sizeof(func_table[0])); @@ -257,12 +261,12 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a return func; # else - return func_table[index]; + return func_table[fnIndex(algorithm, av, variant, assembly)]; # endif } -xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority) +xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly) { assert(av > AV_AUTO && av < AV_MAX); @@ -285,7 +289,7 @@ xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, Algo algorithm, A } } - return new CpuThread(index, algorithm, av, multiway(av), cpuId, priority, isSoftAES(av), false); + return new CpuThread(index, algorithm, av, multiway(av), cpuId, priority, isSoftAES(av), false, assembly); } @@ -303,7 +307,7 @@ xmrig::CpuThread *xmrig::CpuThread::createFromData(size_t index, Algo algorithm, assert(av > AV_AUTO && av < AV_MAX); - return new CpuThread(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false); + return new CpuThread(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false, data.assembly); } @@ -325,11 +329,14 @@ xmrig::CpuThread::Data xmrig::CpuThread::parse(const rapidjson::Value &object) } const auto &affinity = object["affine_to_cpu"]; - if (affinity.IsUint64()) { data.affinity = affinity.GetInt64(); } +# ifndef XMRIG_NO_ASM + data.assembly = Asm::parse(object["asm"]); +# endif + return data; } @@ -371,7 +378,11 @@ void xmrig::CpuThread::print() const LOG_DEBUG(GREEN_BOLD("CPU thread: ") " index " WHITE_BOLD("%zu") ", multiway " WHITE_BOLD("%d") ", av " WHITE_BOLD("%d") ",", index(), static_cast(multiway()), static_cast(m_av)); +# ifndef XMRIG_NO_ASM + LOG_DEBUG(" assembly: %s, affine_to_cpu: %" PRId64, Asm::toString(m_assembly), affinity()); +# else LOG_DEBUG(" affine_to_cpu: %" PRId64, affinity()); +# endif } #endif @@ -406,5 +417,35 @@ rapidjson::Value xmrig::CpuThread::toConfig(rapidjson::Document &doc) const obj.AddMember("low_power_mode", multiway(), allocator); obj.AddMember("affine_to_cpu", affinity() == -1L ? Value(kFalseType) : Value(affinity()), allocator); +# ifndef XMRIG_NO_ASM + obj.AddMember("asm", Asm::toJSON(m_assembly), allocator); +# endif + return obj; } + + +size_t xmrig::CpuThread::fnIndex(Algo algorithm, AlgoVariant av, Variant variant, Assembly assembly) +{ + const size_t index = VARIANT_MAX * 10 * algorithm + 10 * variant + av - 1; + +# ifndef XMRIG_NO_ASM + if (assembly == ASM_AUTO) { + assembly = Cpu::info()->assembly(); + } + + if (assembly == ASM_NONE) { + return index; + } + + constexpr const size_t offset = VARIANT_MAX * 10 * 3; + + if (algorithm == CRYPTONIGHT && variant == VARIANT_2) { + if (av == AV_SINGLE) { + return offset + assembly - 2; + } + } +# endif + + return index; +} diff --git a/src/workers/CpuThread.h b/src/workers/CpuThread.h index 622dc3a25..29ab96964 100644 --- a/src/workers/CpuThread.h +++ b/src/workers/CpuThread.h @@ -40,7 +40,7 @@ class CpuThread : public IThread public: struct Data { - inline Data() : valid(false), affinity(-1L), multiway(SingleWay) {} + inline Data() : assembly(ASM_AUTO), valid(false), affinity(-1L), multiway(SingleWay) {} inline void setMultiway(int value) { @@ -50,27 +50,27 @@ public: } } + Assembly assembly; bool valid; int64_t affinity; Multiway multiway; }; - CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch); - ~CpuThread(); + CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx **ctx); static bool isSoftAES(AlgoVariant av); - static cn_hash_fun fn(Algo algorithm, AlgoVariant av, Variant variant); - static CpuThread *createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority); + static cn_hash_fun fn(Algo algorithm, AlgoVariant av, Variant variant, Assembly assembly); + static CpuThread *createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly); static CpuThread *createFromData(size_t index, Algo algorithm, const CpuThread::Data &data, int priority, bool softAES); static Data parse(const rapidjson::Value &object); static Multiway multiway(AlgoVariant av); inline bool isPrefetch() const { return m_prefetch; } inline bool isSoftAES() const { return m_softAES; } - inline cn_hash_fun fn(Variant variant) const { return fn(m_algorithm, m_av, variant); } + inline cn_hash_fun fn(Variant variant) const { return fn(m_algorithm, m_av, variant, m_assembly); } inline Algo algorithm() const override { return m_algorithm; } inline int priority() const override { return m_priority; } @@ -91,8 +91,11 @@ protected: rapidjson::Value toConfig(rapidjson::Document &doc) const override; private: + static size_t fnIndex(Algo algorithm, AlgoVariant av, Variant variant, Assembly assembly); + const Algo m_algorithm; const AlgoVariant m_av; + const Assembly m_assembly; const bool m_prefetch; const bool m_softAES; const int m_priority;