diff options
-rw-r--r-- | src/bench/checkqueue.cpp | 7 | ||||
-rw-r--r-- | src/checkqueue.h | 25 | ||||
-rw-r--r-- | src/test/checkqueue_tests.cpp | 51 | ||||
-rw-r--r-- | src/test/fuzz/checkqueue.cpp | 12 | ||||
-rw-r--r-- | src/test/transaction_tests.cpp | 6 | ||||
-rw-r--r-- | src/validation.cpp | 5 | ||||
-rw-r--r-- | src/validation.h | 21 |
7 files changed, 45 insertions, 82 deletions
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp index dfd7275f46..8ad6fde6bf 100644 --- a/src/bench/checkqueue.cpp +++ b/src/bench/checkqueue.cpp @@ -29,7 +29,6 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) struct PrevectorJob { prevector<PREVECTOR_SIZE, uint8_t> p; - PrevectorJob() = default; explicit PrevectorJob(FastRandomContext& insecure_rand){ p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2)); } @@ -37,10 +36,6 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) { return true; } - void swap(PrevectorJob& x) noexcept - { - p.swap(x.p); - }; }; CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE}; // The main thread should be counted to prevent thread oversubscription, and @@ -60,7 +55,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) // Make insecure_rand here so that each iteration is identical. CCheckQueueControl<PrevectorJob> control(&queue); for (auto vChecks : vBatches) { - control.Add(vChecks); + control.Add(std::move(vChecks)); } // control waits for completion by RAII, but // it is done explicitly here for clarity diff --git a/src/checkqueue.h b/src/checkqueue.h index d83f717fb7..2c21e5f7d0 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -11,6 +11,7 @@ #include <util/threadnames.h> #include <algorithm> +#include <iterator> #include <vector> template <typename T> @@ -111,13 +112,9 @@ private: // * Try to account for idle jobs which will instantly start helping. // * Don't do batches smaller than 1 (duh), or larger than nBatchSize. nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1))); - vChecks.resize(nNow); - for (unsigned int i = 0; i < nNow; i++) { - // We want the lock on the m_mutex to be as short as possible, so swap jobs from the global - // queue to the local batch vector instead of copying. - vChecks[i].swap(queue.back()); - queue.pop_back(); - } + auto start_it = queue.end() - nNow; + vChecks.assign(std::make_move_iterator(start_it), std::make_move_iterator(queue.end())); + queue.erase(start_it, queue.end()); // Check whether we need to do work at all fOk = fAllOk; } @@ -165,7 +162,7 @@ public: } //! Add a batch of checks to the queue - void Add(std::vector<T>& vChecks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + void Add(std::vector<T>&& vChecks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { if (vChecks.empty()) { return; @@ -173,10 +170,7 @@ public: { LOCK(m_mutex); - for (T& check : vChecks) { - queue.emplace_back(); - check.swap(queue.back()); - } + queue.insert(queue.end(), std::make_move_iterator(vChecks.begin()), std::make_move_iterator(vChecks.end())); nTodo += vChecks.size(); } @@ -239,10 +233,11 @@ public: return fRet; } - void Add(std::vector<T>& vChecks) + void Add(std::vector<T>&& vChecks) { - if (pqueue != nullptr) - pqueue->Add(vChecks); + if (pqueue != nullptr) { + pqueue->Add(std::move(vChecks)); + } } ~CCheckQueueControl() diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 135f107159..012b0eb321 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -43,7 +43,6 @@ struct FakeCheck { { return true; } - void swap(FakeCheck& x) noexcept {}; }; struct FakeCheckCheckCompletion { @@ -53,7 +52,6 @@ struct FakeCheckCheckCompletion { n_calls.fetch_add(1, std::memory_order_relaxed); return true; } - void swap(FakeCheckCheckCompletion& x) noexcept {}; }; struct FailingCheck { @@ -64,10 +62,6 @@ struct FailingCheck { { return !fails; } - void swap(FailingCheck& x) noexcept - { - std::swap(fails, x.fails); - }; }; struct UniqueCheck { @@ -82,10 +76,6 @@ struct UniqueCheck { results.insert(check_id); return true; } - void swap(UniqueCheck& x) noexcept - { - std::swap(x.check_id, check_id); - }; }; @@ -113,19 +103,13 @@ struct MemoryCheck { { fake_allocated_memory.fetch_sub(b, std::memory_order_relaxed); }; - void swap(MemoryCheck& x) noexcept - { - std::swap(b, x.b); - }; }; struct FrozenCleanupCheck { static std::atomic<uint64_t> nFrozen; static std::condition_variable cv; static std::mutex m; - // Freezing can't be the default initialized behavior given how the queue - // swaps in default initialized Checks. - bool should_freeze {false}; + bool should_freeze{true}; bool operator()() const { return true; @@ -140,10 +124,17 @@ struct FrozenCleanupCheck { cv.wait(l, []{ return nFrozen.load(std::memory_order_relaxed) == 0;}); } } - void swap(FrozenCleanupCheck& x) noexcept + FrozenCleanupCheck(FrozenCleanupCheck&& other) noexcept { - std::swap(should_freeze, x.should_freeze); - }; + should_freeze = other.should_freeze; + other.should_freeze = false; + } + FrozenCleanupCheck& operator=(FrozenCleanupCheck&& other) noexcept + { + should_freeze = other.should_freeze; + other.should_freeze = false; + return *this; + } }; // Static Allocations @@ -173,14 +164,16 @@ static void Correct_Queue_range(std::vector<size_t> range) small_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS); // Make vChecks here to save on malloc (this test can be slow...) std::vector<FakeCheckCheckCompletion> vChecks; + vChecks.reserve(9); for (const size_t i : range) { size_t total = i; FakeCheckCheckCompletion::n_calls = 0; CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get()); while (total) { - vChecks.resize(std::min(total, (size_t) InsecureRandRange(10))); + vChecks.clear(); + vChecks.resize(std::min<size_t>(total, InsecureRandRange(10))); total -= vChecks.size(); - control.Add(vChecks); + control.Add(std::move(vChecks)); } BOOST_REQUIRE(control.Wait()); if (FakeCheckCheckCompletion::n_calls != i) { @@ -242,7 +235,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) vChecks.reserve(r); for (size_t k = 0; k < r && remaining; k++, remaining--) vChecks.emplace_back(remaining == 1); - control.Add(vChecks); + control.Add(std::move(vChecks)); } bool success = control.Wait(); if (i > 0) { @@ -267,7 +260,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) std::vector<FailingCheck> vChecks; vChecks.resize(100, false); vChecks[99] = end_fails; - control.Add(vChecks); + control.Add(std::move(vChecks)); } bool r =control.Wait(); BOOST_REQUIRE(r != end_fails); @@ -293,7 +286,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) std::vector<UniqueCheck> vChecks; for (size_t k = 0; k < r && total; k++) vChecks.emplace_back(--total); - control.Add(vChecks); + control.Add(std::move(vChecks)); } } { @@ -331,7 +324,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) // to catch any sort of deallocation failure vChecks.emplace_back(total == 0 || total == i || total == i/2); } - control.Add(vChecks); + control.Add(std::move(vChecks)); } } BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0U); @@ -349,11 +342,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) std::thread t0([&]() { CCheckQueueControl<FrozenCleanupCheck> control(queue.get()); std::vector<FrozenCleanupCheck> vChecks(1); - // Freezing can't be the default initialized behavior given how the queue - // swaps in default initialized Checks (otherwise freezing destructor - // would get called twice). - vChecks[0].should_freeze = true; - control.Add(vChecks); + control.Add(std::move(vChecks)); bool waitResult = control.Wait(); // Hangs here assert(waitResult); }); diff --git a/src/test/fuzz/checkqueue.cpp b/src/test/fuzz/checkqueue.cpp index 6256aefaa3..429570526f 100644 --- a/src/test/fuzz/checkqueue.cpp +++ b/src/test/fuzz/checkqueue.cpp @@ -13,9 +13,7 @@ namespace { struct DumbCheck { - const bool result = false; - - DumbCheck() = default; + bool result = false; explicit DumbCheck(const bool _result) : result(_result) { @@ -25,10 +23,6 @@ struct DumbCheck { { return result; } - - void swap(DumbCheck& x) noexcept - { - } }; } // namespace @@ -48,7 +42,7 @@ FUZZ_TARGET(checkqueue) checks_2.emplace_back(result); } if (fuzzed_data_provider.ConsumeBool()) { - check_queue_1.Add(checks_1); + check_queue_1.Add(std::move(checks_1)); } if (fuzzed_data_provider.ConsumeBool()) { (void)check_queue_1.Wait(); @@ -56,7 +50,7 @@ FUZZ_TARGET(checkqueue) CCheckQueueControl<DumbCheck> check_queue_control{&check_queue_2}; if (fuzzed_data_provider.ConsumeBool()) { - check_queue_control.Add(checks_2); + check_queue_control.Add(std::move(checks_2)); } if (fuzzed_data_provider.ConsumeBool()) { (void)check_queue_control.Wait(); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 11efb6a5c3..7511dff9e8 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -547,10 +547,8 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) for(uint32_t i = 0; i < mtx.vin.size(); i++) { std::vector<CScriptCheck> vChecks; - CScriptCheck check(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata); - vChecks.push_back(CScriptCheck()); - check.swap(vChecks.back()); - control.Add(vChecks); + vChecks.emplace_back(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata); + control.Add(std::move(vChecks)); } bool controlCheck = control.Wait(); diff --git a/src/validation.cpp b/src/validation.cpp index 2af7e2cc8d..e82fead89e 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1815,8 +1815,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, // Verify signature CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata); if (pvChecks) { - pvChecks->push_back(CScriptCheck()); - check.swap(pvChecks->back()); + pvChecks->emplace_back(std::move(check)); } else if (!check()) { if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { // Check whether the failure was caused by a @@ -2325,7 +2324,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, return error("ConnectBlock(): CheckInputScripts on %s failed with %s", tx.GetHash().ToString(), state.ToString()); } - control.Add(vChecks); + control.Add(std::move(vChecks)); } CTxUndo undoDummy; diff --git a/src/validation.h b/src/validation.h index 53e9a7ee50..aba863db09 100644 --- a/src/validation.h +++ b/src/validation.h @@ -314,26 +314,19 @@ private: unsigned int nIn; unsigned int nFlags; bool cacheStore; - ScriptError error; + ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR}; PrecomputedTransactionData *txdata; public: - CScriptCheck(): ptxTo(nullptr), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) : - m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { } + m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn) { } - bool operator()(); + CScriptCheck(const CScriptCheck&) = delete; + CScriptCheck& operator=(const CScriptCheck&) = delete; + CScriptCheck(CScriptCheck&&) = default; + CScriptCheck& operator=(CScriptCheck&&) = default; - void swap(CScriptCheck& check) noexcept - { - std::swap(ptxTo, check.ptxTo); - std::swap(m_tx_out, check.m_tx_out); - std::swap(nIn, check.nIn); - std::swap(nFlags, check.nFlags); - std::swap(cacheStore, check.cacheStore); - std::swap(error, check.error); - std::swap(txdata, check.txdata); - } + bool operator()(); ScriptError GetScriptError() const { return error; } }; |