From 94b84f8e0c4150e7aa2cb0ac2e707bd4545085fc Mon Sep 17 00:00:00 2001 From: R E Broadley Date: Thu, 23 Apr 2020 16:43:41 +0800 Subject: [PATCH] Add io priority to reduce impact of ActivateChain on IBD and impact of historical block serving. Based on #9245 --- configure.ac | 40 +++++++++++++++++++++++++++++ src/Makefile.am | 2 ++ src/net_processing.cpp | 3 ++- src/utilioprio.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++ src/utilioprio.h | 57 ++++++++++++++++++++++++++++++++++++++++++ src/validation.cpp | 18 +++++++++---- src/validation.h | 4 +-- 7 files changed, 173 insertions(+), 8 deletions(-) mode change 100644 => 100755 configure.ac mode change 100644 => 100755 src/Makefile.am create mode 100644 src/utilioprio.cpp create mode 100644 src/utilioprio.h diff --git a/configure.ac b/configure.ac old mode 100644 new mode 100755 index 0894c7197c55ba..86908d69df1f9d --- a/configure.ac +++ b/configure.ac @@ -549,6 +549,44 @@ AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,, #include #endif]) +AC_MSG_CHECKING(for iopolicy functions) +AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #include + ]],[[ + int x = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD); + setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, x); + ]]) +],[ + have_iopolicy=yes + AC_DEFINE(HAVE_IOPOLICY,1,[Define this symbol if you have iopolicy functions]) +],[ + have_iopolicy=no +]) +AC_MSG_RESULT($have_iopolicy) + +if test x$have_iopolicy = xno; then + AC_MSG_CHECKING(for ioprio syscalls) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #define _GNU_SOURCE + #include + #include + ]],[[ + int x = syscall(SYS_ioprio_get, 1, 0); + syscall(SYS_ioprio_set, 1, 0, x); + ]]) + ],[ + have_ioprio_syscall=yes + AC_DEFINE(HAVE_IOPRIO_SYSCALL,1,[Define this symbol if you have ioprio syscalls]) + ],[ + have_ioprio_syscall=no + ]) + AC_MSG_RESULT($have_ioprio_syscall) +else + have_ioprio_syscall=no +fi + dnl Check for MSG_NOSIGNAL AC_MSG_CHECKING(for MSG_NOSIGNAL) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], @@ -1063,6 +1101,8 @@ AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes]) AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) +AM_CONDITIONAL([HAVE_IOPOLICY],[test x$have_iopolicy = xyes]) +AM_CONDITIONAL([HAVE_IOPRIO_SYSCALL],[test x$have_ioprio_syscall = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) diff --git a/src/Makefile.am b/src/Makefile.am old mode 100644 new mode 100755 index 29d4c14d5dd6ea..ffba5ab02580f4 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -149,6 +149,7 @@ BITCOIN_CORE_H = \ ui_interface.h \ undo.h \ util.h \ + utilioprio.h \ utilmoneystr.h \ utiltime.h \ validation.h \ @@ -337,6 +338,7 @@ libbitcoin_util_a_SOURCES = \ sync.cpp \ threadinterrupt.cpp \ util.cpp \ + utilioprio.cpp \ utilmoneystr.cpp \ utilstrencodings.cpp \ utiltime.cpp \ diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a3e63718add0cf..e2054d3816b414 100755 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1172,7 +1172,8 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // Send block from disk CBlock block; int nSize = 0; - if (!ReadBlockFromDisk(block, (*mi).second, consensusParams)) + // Read block with low priority if not recent (i.e. historical) + if (!ReadBlockFromDisk(block, (*mi).second, consensusParams, !fRecent)) assert(!"cannot load block from disk"); if (inv.type == MSG_BLOCK) nSize += connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block)); diff --git a/src/utilioprio.cpp b/src/utilioprio.cpp new file mode 100644 index 00000000000000..a1e58703d4c814 --- /dev/null +++ b/src/utilioprio.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include "utilioprio.h" + +#ifdef HAVE_IOPRIO_SYSCALL + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include + +#ifndef IOPRIO_WHO_PROCESS +#define IOPRIO_WHO_PROCESS 1 +#endif +#ifndef IOPRIO_CLASS_IDLE +#define IOPRIO_CLASS_IDLE 3 +#endif +#ifndef IOPRIO_CLASS_SHIFT +#define IOPRIO_CLASS_SHIFT 13 +#endif + +int ioprio_get() { + return syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, 0); +} + +int ioprio_set(const int ioprio) { + return syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, 0, ioprio); +} + +int ioprio_set_idle() { + return ioprio_set(7 | (IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT)); +} + +#elif HAVE_IOPOLICY + +#include + +int ioprio_get() { + return getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD); +} + +int ioprio_set(const int ioprio) { + return setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, ioprio); +} + +int ioprio_set_idle() { + return ioprio_set(IOPOL_UTILITY); +} + +#endif diff --git a/src/utilioprio.h b/src/utilioprio.h new file mode 100644 index 00000000000000..e9fdf71ffc1667 --- /dev/null +++ b/src/utilioprio.h @@ -0,0 +1,57 @@ +// Copyright (c) 2016 Satoshi Nakamoto +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_IOPRIO_H +#define BITCOIN_UTIL_IOPRIO_H + +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include "util.h" + +#if defined(HAVE_IOPRIO_SYSCALL) || defined(HAVE_IOPOLICY) +int ioprio_get(); +int ioprio_set(int ioprio); +int ioprio_set_idle(); + +class ioprio_idler { +private: + int orig; + +public: + ioprio_idler(const bool actually_idle) { + if (!actually_idle) { + orig = -1; + return; + } + + orig = ioprio_get(); + if (orig == -1) { + return; + } + if (ioprio_set_idle() == -1) { + orig = -1; + } + } + + ~ioprio_idler() { + if (orig == -1) { + return; + } + if (ioprio_set(orig) == -1) { + LogPrintf("failed to restore ioprio\n"); + } + } +}; +#define IOPRIO_IDLER(actually_idle) ioprio_idler ioprio_idler_(actually_idle) + +#else +#define ioprio_get() ((void)-1) +#define ioprio_set(ioprio) ((void)-1) +#define ioprio_set_idle() ((void)-1) +#define IOPRIO_IDLER(actually_idle) (void)actually_idle; +#endif + +#endif // BITCOIN_UTIL_IOPRIO_H diff --git a/src/validation.cpp b/src/validation.cpp index 9feab178e1a944..0629d620ce6e72 100755 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -31,6 +31,7 @@ #include "ui_interface.h" #include "undo.h" #include "util.h" +#include "utilioprio.h" #include "utilmoneystr.h" #include "utilstrencodings.h" #include "validationinterface.h" @@ -1093,7 +1094,8 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus if (pindexSlow) { CBlock block; - if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { + // Read block with low priority if during IBD + if (ReadBlockFromDisk(block, pindexSlow, consensusParams, IsInitialBlockDownload())) { for (const auto& tx : block.vtx) { if (tx->GetHash() == hash) { txOut = tx; @@ -1138,10 +1140,13 @@ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHea return true; } -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams, const bool lowprio /*=false*/) { block.SetNull(); + { + IOPRIO_IDLER(lowprio); + // Open history file to read CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); if (filein.IsNull()) @@ -1155,6 +1160,8 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus: return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); } + } // end IOPRIO_IDLER scope + // Check the header if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); @@ -1162,9 +1169,9 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus: return true; } -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams, const bool lowprio /*=false*/) { - if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams)) + if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams, lowprio)) return false; if (block.GetHash() != pindex->GetBlockHash()) return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", @@ -2317,7 +2324,8 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, if (!pblock) { std::shared_ptr pblockNew = std::make_shared(); connectTrace.blocksConnected.emplace_back(pindexNew, pblockNew); - if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams.GetConsensus())) + // Read from disk with low priority during IBD + if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams.GetConsensus(), IsInitialBlockDownload())) return AbortNode(state, "Failed to read block"); } else { connectTrace.blocksConnected.emplace_back(pindexNew, pblock); diff --git a/src/validation.h b/src/validation.h index 15b9a8938846a8..93b96407ac6861 100755 --- a/src/validation.h +++ b/src/validation.h @@ -481,8 +481,8 @@ class CScriptCheck /** Functions for disk access for blocks */ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams); -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams, bool lowprio = false); +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams, bool lowprio = false); /** Functions for validating blocks and updating the block tree */