/* 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 2018-2019 SChernykh * Copyright 2016-2019 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 "backend/opencl/runners/tools/OclSharedData.h" #include "backend/opencl/wrappers/OclLib.h" #include "base/io/log/Log.h" #include "base/tools/Chrono.h" #include "crypto/rx/Rx.h" #include "crypto/rx/RxDataset.h" #include #include #include uint64_t xmrig::OclSharedData::adjustDelay(size_t id) { if (m_threads < 2) { return 0; } const uint64_t t0 = Chrono::steadyMSecs(); uint64_t delay = 0; { std::lock_guard lock(m_mutex); const uint64_t dt = t0 - m_timestamp; m_timestamp = t0; // The perfect interleaving is when N threads on the same GPU start with T/N interval between each other // If a thread starts earlier than 0.75*T/N ms after the previous thread, delay it to restore perfect interleaving if ((dt > 0) && (dt < m_threshold * (m_averageRunTime / m_threads))) { delay = static_cast(m_averageRunTime / m_threads - dt); m_threshold = 0.75; } } if (delay == 0) { return 0; } if (delay >= 400) { delay = 200; } std::this_thread::sleep_for(std::chrono::milliseconds(delay)); # ifdef XMRIG_INTERLEAVE_DEBUG LOG_WARN("Thread #%zu was paused for %" PRIu64 " ms to adjust interleaving", id, delay); # endif return delay; } uint64_t xmrig::OclSharedData::resumeDelay(size_t id) { if (m_threads < 2) { return 0; } uint64_t delay = 0; { constexpr const double firstThreadSpeedupCoeff = 1.25; std::lock_guard lock(m_mutex); delay = static_cast(m_resumeCounter * m_averageRunTime / m_threads / firstThreadSpeedupCoeff); ++m_resumeCounter; } if (delay == 0) { return 0; } if (delay > 1000) { delay = 1000; } # ifdef XMRIG_INTERLEAVE_DEBUG LOG_WARN("Thread #%zu will be paused for %" PRIu64 " ms to before resuming", id, delay); # endif std::this_thread::sleep_for(std::chrono::milliseconds(delay)); return delay; } void xmrig::OclSharedData::release() { # ifdef XMRIG_ALGO_RANDOMX OclLib::release(m_dataset); # endif } void xmrig::OclSharedData::setResumeCounter(uint32_t value) { if (m_threads < 2) { return; } std::lock_guard lock(m_mutex); m_resumeCounter = value; } void xmrig::OclSharedData::setRunTime(uint64_t time) { // averagingBias = 1.0 - only the last delta time is taken into account // averagingBias = 0.5 - the last delta time has the same weight as all the previous ones combined // averagingBias = 0.1 - the last delta time has 10% weight of all the previous ones combined constexpr double averagingBias = 0.1; std::lock_guard lock(m_mutex); m_averageRunTime = m_averageRunTime * (1.0 - averagingBias) + time * averagingBias; } #ifdef XMRIG_ALGO_RANDOMX cl_mem xmrig::OclSharedData::dataset() const { if (!m_dataset) { throw std::runtime_error("RandomX dataset is not available"); } return m_dataset; } void xmrig::OclSharedData::createDataset(cl_context ctx, const Job &job, bool host) { if (m_dataset) { return; } cl_int ret; if (host) { auto dataset = Rx::dataset(job, 0); m_dataset = OclLib::createBuffer(ctx, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, RxDataset::maxSize(), dataset->raw(), &ret); } else { m_dataset = OclLib::createBuffer(ctx, CL_MEM_READ_ONLY, RxDataset::maxSize(), nullptr, &ret); } } #endif