From 1b8fc18377dc959a3cb069bec1fb4cebe9955e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 2 Jul 2015 17:49:13 +0200 Subject: [PATCH] New strategy do SmartVM: JIT worker in the background. --- libevm/SmartVM.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 7 deletions(-) diff --git a/libevm/SmartVM.cpp b/libevm/SmartVM.cpp index f8785b6df..3fb5be8c5 100644 --- a/libevm/SmartVM.cpp +++ b/libevm/SmartVM.cpp @@ -20,6 +20,10 @@ #include "SmartVM.h" #include +#include +#include +#include +#include #include #include #include @@ -32,6 +36,8 @@ namespace eth { namespace { + struct JitInfo: LogChannel { static const char* name() { return "JIT"; }; static const int verbosity = 0; }; + using HitMap = std::unordered_map; HitMap& getHitMap() @@ -39,30 +45,97 @@ namespace static HitMap s_hitMap; return s_hitMap; } + + struct JitTask + { + bytes code; + h256 codeHash; + }; + + class JitWorker + { + bool m_finished = false; + std::mutex x_mutex; + std::condition_variable m_cv; + std::thread m_worker; + std::queue m_queue; + + bool pop(JitTask& o_task) + { + std::unique_lock lock{x_mutex}; + m_cv.wait(lock, [this]{ return m_finished || !m_queue.empty(); }); + if (m_finished) + return false; + + assert(!m_queue.empty()); + o_task = std::move(m_queue.front()); + m_queue.pop(); + return true; + } + + void work() + { + clog(JitInfo) << "JIT worker started."; + JitTask task; + while (pop(task)) + { + clog(JitInfo) << "Compilation... " << task.codeHash; + evmjit::JIT::compile(task.code.data(), task.code.size(), eth2jit(task.codeHash)); + clog(JitInfo) << " ...finished " << task.codeHash; + } + clog(JitInfo) << "JIT worker finished."; + } + + public: + JitWorker() noexcept: m_worker([this]{ work(); }) + {} + + ~JitWorker() + { + { + std::lock_guard lock{x_mutex}; + m_finished = true; + } + m_cv.notify_one(); + m_worker.join(); + } + + void push(JitTask&& _task) + { + { + std::lock_guard lock(x_mutex); + m_queue.push(std::move(_task)); + } + m_cv.notify_one(); + } + }; } bytesConstRef SmartVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) { - auto codeHash = sha3(_ext.code); + auto codeHash = _ext.codeHash; auto vmKind = VMKind::Interpreter; // default VM // Jitted EVM code already in memory? - if (evmjit::JIT::isCodeReady(eth2jit(codeHash))) + if (evmjit::JIT::isCodeReady(eth2jit(codeHash))) // FIXME: JIT::isCodeReady is not thread-safe { - cnote << "Jitted"; + clog(JitInfo) << "JIT: " << codeHash; vmKind = VMKind::JIT; } else { + static JitWorker s_worker; + // Check EVM code hit count - static const uint64_t c_hitTreshold = 1; + static const uint64_t c_hitTreshold = 2; auto& hits = getHitMap()[codeHash]; ++hits; - if (hits > c_hitTreshold) + if (hits == c_hitTreshold) { - cnote << "JIT selected"; - vmKind = VMKind::JIT; + clog(JitInfo) << "Schedule: " << codeHash; + s_worker.push({_ext.code, codeHash}); } + clog(JitInfo) << "Interpreter: " << codeHash; } // TODO: Selected VM must be kept only because it returns reference to its internal memory.