REDACTED-rig/src/crypto/rx/RxMsr.cpp

183 lines
5.2 KiB
C++

/* XMRig
* Copyright (c) 2018-2019 tevador <tevador@gmail.com>
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "crypto/rx/RxMsr.h"
#include "backend/cpu/Cpu.h"
#include "backend/cpu/CpuThread.h"
#include "base/io/log/Log.h"
#include "base/tools/Chrono.h"
#include "crypto/rx/RxConfig.h"
#include "hw/msr/Msr.h"
#include <algorithm>
#include <set>
namespace xmrig {
bool RxMsr::m_cacheQoS = false;
bool RxMsr::m_enabled = false;
bool RxMsr::m_initialized = false;
static MsrItems items;
#ifdef XMRIG_OS_WIN
static constexpr inline int32_t get_cpu(int32_t) { return -1; }
#else
static constexpr inline int32_t get_cpu(int32_t cpu) { return cpu; }
#endif
static bool wrmsr(const MsrItems &preset, const std::vector<CpuThread> &threads, bool cache_qos, bool save)
{
auto msr = Msr::get();
if (!msr) {
return false;
}
if (save) {
items.reserve(preset.size());
for (const auto &i : preset) {
auto item = msr->read(i.reg());
if (!item.isValid()) {
items.clear();
return false;
}
LOG_VERBOSE("%s " CYAN_BOLD("0x%08" PRIx32) CYAN(":0x%016" PRIx64) CYAN_BOLD(" -> 0x%016" PRIx64), Msr::tag(), i.reg(), item.value(), MsrItem::maskedValue(item.value(), i.value(), i.mask()));
items.emplace_back(item);
}
}
// Which CPU cores will have access to the full L3 cache
std::set<int32_t> cacheEnabled;
bool cacheQoSDisabled = threads.empty();
if (cache_qos) {
const auto &units = Cpu::info()->units();
for (const auto &t : threads) {
const auto affinity = static_cast<int32_t>(t.affinity());
// If some thread has no affinity or wrong affinity, disable cache QoS
if (affinity < 0 || std::find(units.begin(), units.end(), affinity) == units.end()) {
cacheQoSDisabled = true;
LOG_WARN("%s " YELLOW_BOLD("cache QoS can only be enabled when all mining threads have affinity set"), Msr::tag());
break;
}
cacheEnabled.insert(affinity);
}
}
return msr->write([&msr, &preset, cache_qos, &cacheEnabled, cacheQoSDisabled](int32_t cpu) {
for (const auto &item : preset) {
if (!msr->write(item, get_cpu(cpu))) {
return false;
}
}
if (!cache_qos) {
return true;
}
// Assign Class Of Service 0 to current CPU core (default, full L3 cache available)
if (cacheQoSDisabled || cacheEnabled.count(cpu)) {
return msr->write(0xC8F, 0, get_cpu(cpu));
}
// Disable L3 cache for Class Of Service 1
if (!msr->write(0xC91, 0, get_cpu(cpu))) {
// Some CPUs don't let set it to all zeros
if (!msr->write(0xC91, 1, get_cpu(cpu))) {
return false;
}
}
// Assign Class Of Service 1 to current CPU core
return msr->write(0xC8F, 1ULL << 32, get_cpu(cpu));
});
}
} // namespace xmrig
bool xmrig::RxMsr::init(const RxConfig &config, const std::vector<CpuThread> &threads)
{
if (isInitialized()) {
return isEnabled();
}
m_initialized = true;
m_enabled = false;
const auto &preset = config.msrPreset();
if (preset.empty()) {
return false;
}
const uint64_t ts = Chrono::steadyMSecs();
m_cacheQoS = config.cacheQoS();
if (m_cacheQoS && !Cpu::info()->hasCatL3()) {
LOG_WARN("%s " YELLOW_BOLD("this CPU doesn't support cat_l3, cache QoS is unavailable"), Msr::tag());
m_cacheQoS = false;
}
if ((m_enabled = wrmsr(preset, threads, m_cacheQoS, config.rdmsr()))) {
LOG_NOTICE("%s " GREEN_BOLD("register values for \"%s\" preset have been set successfully") BLACK_BOLD(" (%" PRIu64 " ms)"), Msr::tag(), config.msrPresetName(), Chrono::steadyMSecs() - ts);
}
else {
LOG_ERR("%s " RED_BOLD("FAILED TO APPLY MSR MOD, HASHRATE WILL BE LOW"), Msr::tag());
}
return isEnabled();
}
void xmrig::RxMsr::destroy()
{
if (!isInitialized()) {
return;
}
m_initialized = false;
m_enabled = false;
if (items.empty()) {
return;
}
const uint64_t ts = Chrono::steadyMSecs();
if (!wrmsr(items, std::vector<CpuThread>(), m_cacheQoS, false)) {
LOG_ERR("%s " RED_BOLD("failed to restore initial state" BLACK_BOLD(" (%" PRIu64 " ms)")), Msr::tag(), Chrono::steadyMSecs() - ts);
}
}