diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 6114da0f..81f0350c 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -9,7 +9,7 @@ formatter="clang-format -i" first=$(git diff $sources) find $sources -type f \( -name '*.cpp' -o -name '*.h' -o -name '*.ipp' \) -print0 | xargs -0 $formatter second=$(git diff $sources) -changes=$(diff <(echo "$first") <(echo "$second") | wc -l) +changes=$(diff <(echo "$first") <(echo "$second") | wc -l | sed -e 's/^[[:space:]]*//') if [ "$changes" != "0" ]; then cat <<\EOF diff --git a/CMakeLists.txt b/CMakeLists.txt index 62f1c599..c5c2602d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,7 @@ if(BUILD_TESTS) unittests/Backend.cpp unittests/Logger.cpp unittests/Config.cpp + unittests/ProfilerTest.cpp unittests/DOSGuard.cpp) include(CMake/deps/gtest.cmake) endif() diff --git a/src/backend/CassandraBackend.cpp b/src/backend/CassandraBackend.cpp index 85da0706..1aeef0d2 100644 --- a/src/backend/CassandraBackend.cpp +++ b/src/backend/CassandraBackend.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -524,32 +525,30 @@ CassandraBackend::fetchTransactions( std::vector results{numHashes}; std::vector>> cbs; cbs.reserve(numHashes); - auto start = std::chrono::system_clock::now(); + auto timeDiff = util::timed([&]() { + for (std::size_t i = 0; i < hashes.size(); ++i) + { + CassandraStatement statement{selectTransaction_}; + statement.bindNextBytes(hashes[i]); - for (std::size_t i = 0; i < hashes.size(); ++i) - { - CassandraStatement statement{selectTransaction_}; - statement.bindNextBytes(hashes[i]); + cbs.push_back(std::make_shared>( + numOutstanding, handler, [i, &results](auto& result) { + if (result.hasResult()) + results[i] = { + result.getBytes(), + result.getBytes(), + result.getUInt32(), + result.getUInt32()}; + })); - cbs.push_back(std::make_shared>( - numOutstanding, handler, [i, &results](auto& result) { - if (result.hasResult()) - results[i] = { - result.getBytes(), - result.getBytes(), - result.getUInt32(), - result.getUInt32()}; - })); + executeAsyncRead(statement, processAsyncRead, *cbs[i]); + } + assert(results.size() == cbs.size()); - executeAsyncRead(statement, processAsyncRead, *cbs[i]); - } - assert(results.size() == cbs.size()); - - // suspend the coroutine until completion handler is called. - result.get(); - numReadRequestsOutstanding_ -= hashes.size(); - - auto end = std::chrono::system_clock::now(); + // suspend the coroutine until completion handler is called. + result.get(); + numReadRequestsOutstanding_ -= hashes.size(); + }); for (auto const& cb : cbs) { if (cb->errored) @@ -557,10 +556,7 @@ CassandraBackend::fetchTransactions( } log_.debug() << "Fetched " << numHashes - << " transactions from Cassandra in " - << std::chrono::duration_cast( - end - start) - .count() + << " transactions from Cassandra in " << timeDiff << " milliseconds"; return results; } diff --git a/src/etl/ETLSource.cpp b/src/etl/ETLSource.cpp index b18460e7..b0cd7e94 100644 --- a/src/etl/ETLSource.cpp +++ b/src/etl/ETLSource.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -807,66 +808,68 @@ ETLSourceImpl::loadInitialLedger( backend_->cache().setFull(); if (!cacheOnly) { - auto start = std::chrono::system_clock::now(); - for (auto& key : edgeKeys) - { - log_.debug() << "Writing edge key = " << ripple::strHex(key); - auto succ = backend_->cache().getSuccessor( - *ripple::uint256::fromVoidChecked(key), sequence); - if (succ) - backend_->writeSuccessor( - std::move(key), sequence, uint256ToString(succ->key)); - } - ripple::uint256 prev = Backend::firstKey; - while (auto cur = backend_->cache().getSuccessor(prev, sequence)) - { - assert(cur); - if (prev == Backend::firstKey) + auto seconds = util::timed([&]() { + for (auto& key : edgeKeys) { - backend_->writeSuccessor( - uint256ToString(prev), - sequence, - uint256ToString(cur->key)); + log_.debug() + << "Writing edge key = " << ripple::strHex(key); + auto succ = backend_->cache().getSuccessor( + *ripple::uint256::fromVoidChecked(key), sequence); + if (succ) + backend_->writeSuccessor( + std::move(key), + sequence, + uint256ToString(succ->key)); } - - if (isBookDir(cur->key, cur->blob)) + ripple::uint256 prev = Backend::firstKey; + while (auto cur = + backend_->cache().getSuccessor(prev, sequence)) { - auto base = getBookBase(cur->key); - // make sure the base is not an actual object - if (!backend_->cache().get(cur->key, sequence)) + assert(cur); + if (prev == Backend::firstKey) { - auto succ = - backend_->cache().getSuccessor(base, sequence); - assert(succ); - if (succ->key == cur->key) - { - log_.debug() << "Writing book successor = " - << ripple::strHex(base) << " - " - << ripple::strHex(cur->key); - - backend_->writeSuccessor( - uint256ToString(base), - sequence, - uint256ToString(cur->key)); - } + backend_->writeSuccessor( + uint256ToString(prev), + sequence, + uint256ToString(cur->key)); } - ++numWrites; + + if (isBookDir(cur->key, cur->blob)) + { + auto base = getBookBase(cur->key); + // make sure the base is not an actual object + if (!backend_->cache().get(cur->key, sequence)) + { + auto succ = + backend_->cache().getSuccessor(base, sequence); + assert(succ); + if (succ->key == cur->key) + { + log_.debug() << "Writing book successor = " + << ripple::strHex(base) << " - " + << ripple::strHex(cur->key); + + backend_->writeSuccessor( + uint256ToString(base), + sequence, + uint256ToString(cur->key)); + } + } + ++numWrites; + } + prev = std::move(cur->key); + if (numWrites % 100000 == 0 && numWrites != 0) + log_.info() + << "Wrote " << numWrites << " book successors"; } - prev = std::move(cur->key); - if (numWrites % 100000 == 0 && numWrites != 0) - log_.info() << "Wrote " << numWrites << " book successors"; - } - backend_->writeSuccessor( - uint256ToString(prev), - sequence, - uint256ToString(Backend::lastKey)); + backend_->writeSuccessor( + uint256ToString(prev), + sequence, + uint256ToString(Backend::lastKey)); - ++numWrites; - auto end = std::chrono::system_clock::now(); - auto seconds = - std::chrono::duration_cast(end - start) - .count(); + ++numWrites; + }); log_.info() << "Looping through cache and submitting all writes took " << seconds diff --git a/src/etl/ReportingETL.cpp b/src/etl/ReportingETL.cpp index 97fee579..afe55adb 100644 --- a/src/etl/ReportingETL.cpp +++ b/src/etl/ReportingETL.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -137,40 +138,39 @@ ReportingETL::loadInitialLedger(uint32_t startingSequence) log_.debug() << "Deserialized ledger header. " << detail::toString(lgrInfo); - auto start = std::chrono::system_clock::now(); + auto timeDiff = util::timed>([&]() { + backend_->startWrites(); - backend_->startWrites(); + log_.debug() << "Started writes"; - log_.debug() << "Started writes"; + backend_->writeLedger( + lgrInfo, std::move(*ledgerData->mutable_ledger_header())); - backend_->writeLedger( - lgrInfo, std::move(*ledgerData->mutable_ledger_header())); + log_.debug() << "Wrote ledger"; + FormattedTransactionsData insertTxResult = + insertTransactions(lgrInfo, *ledgerData); + log_.debug() << "Inserted txns"; - log_.debug() << "Wrote ledger"; - FormattedTransactionsData insertTxResult = - insertTransactions(lgrInfo, *ledgerData); - log_.debug() << "Inserted txns"; + // download the full account state map. This function downloads full + // ledger data and pushes the downloaded data into the writeQueue. + // asyncWriter consumes from the queue and inserts the data into the + // Ledger object. Once the below call returns, all data has been pushed + // into the queue + loadBalancer_->loadInitialLedger(startingSequence); - // download the full account state map. This function downloads full ledger - // data and pushes the downloaded data into the writeQueue. asyncWriter - // consumes from the queue and inserts the data into the Ledger object. - // Once the below call returns, all data has been pushed into the queue - loadBalancer_->loadInitialLedger(startingSequence); + log_.debug() << "Loaded initial ledger"; - log_.debug() << "Loaded initial ledger"; - - if (!stopping_) - { - backend_->writeAccountTransactions( - std::move(insertTxResult.accountTxData)); - backend_->writeNFTs(std::move(insertTxResult.nfTokensData)); - backend_->writeNFTTransactions(std::move(insertTxResult.nfTokenTxData)); - } - backend_->finishWrites(startingSequence); - - auto end = std::chrono::system_clock::now(); - log_.debug() << "Time to download and store ledger = " - << ((end - start).count()) / 1000000000.0; + if (!stopping_) + { + backend_->writeAccountTransactions( + std::move(insertTxResult.accountTxData)); + backend_->writeNFTs(std::move(insertTxResult.nfTokensData)); + backend_->writeNFTTransactions( + std::move(insertTxResult.nfTokenTxData)); + } + backend_->finishWrites(startingSequence); + }); + log_.debug() << "Time to download and store ledger = " << timeDiff; return lgrInfo; } @@ -530,10 +530,8 @@ ReportingETL::buildNextLedger(org::xrpl::rpc::v1::GetLedgerResponse& rawData) backend_->writeNFTTransactions(std::move(insertTxResult.nfTokenTxData)); log_.debug() << "wrote account_tx"; - auto start = std::chrono::system_clock::now(); - bool success = backend_->finishWrites(lgrInfo.seq); - auto end = std::chrono::system_clock::now(); - auto duration = ((end - start).count()) / 1000000000.0; + auto [success, duration] = util::timed>( + [&]() { return backend_->finishWrites(lgrInfo.seq); }); log_.debug() << "Finished writes. took " << std::to_string(duration); log_.debug() << "Finished ledger update. " << detail::toString(lgrInfo); @@ -620,12 +618,10 @@ ReportingETL::runETLPipeline(uint32_t startSequence, int numExtractors) currentSequence) && !writeConflict && !isStopping()) { - auto start = std::chrono::system_clock::now(); - std::optional - fetchResponse{fetchLedgerDataAndDiff(currentSequence)}; - auto end = std::chrono::system_clock::now(); - - auto time = ((end - start).count()) / 1000000000.0; + auto [fetchResponse, time] = + util::timed>([&]() { + return fetchLedgerDataAndDiff(currentSequence); + }); totalTime += time; // if the fetch is unsuccessful, stop. fetchLedger only diff --git a/src/rpc/RPCHelpers.cpp b/src/rpc/RPCHelpers.cpp index 3f152389..30d2955c 100644 --- a/src/rpc/RPCHelpers.cpp +++ b/src/rpc/RPCHelpers.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -798,14 +799,10 @@ traverseOwnedNodes( .count() << " milliseconds"; - start = std::chrono::system_clock::now(); - auto objects = backend.fetchLedgerObjects(keys, sequence, yield); - end = std::chrono::system_clock::now(); + auto [objects, timeDiff] = util::timed( + [&]() { return backend.fetchLedgerObjects(keys, sequence, yield); }); - gLog.debug() << "Time loading owned entries: " - << std::chrono::duration_cast( - end - start) - .count() + gLog.debug() << "Time loading owned entries: " << timeDiff << " milliseconds"; for (auto i = 0; i < objects.size(); ++i) @@ -1652,60 +1649,58 @@ traverseTransactions( boost::json::array txns; auto [blobs, retCursor] = transactionFetcher( context.backend, limit, forward, cursor, context.yield); - auto serializationStart = std::chrono::system_clock::now(); - - if (retCursor) - { - boost::json::object cursorJson; - cursorJson[JS(ledger)] = retCursor->ledgerSequence; - cursorJson[JS(seq)] = retCursor->transactionIndex; - response[JS(marker)] = cursorJson; - } - - for (auto const& txnPlusMeta : blobs) - { - if ((txnPlusMeta.ledgerSequence < minIndex && !forward) || - (txnPlusMeta.ledgerSequence > maxIndex && forward)) + auto timeDiff = util::timed([&, &retCursor = retCursor, &blobs = blobs]() { + if (retCursor) { - response.erase(JS(marker)); - break; - } - else if (txnPlusMeta.ledgerSequence > maxIndex && !forward) - { - gLog.debug() << "Skipping over transactions from incomplete ledger"; - continue; + boost::json::object cursorJson; + cursorJson[JS(ledger)] = retCursor->ledgerSequence; + cursorJson[JS(seq)] = retCursor->transactionIndex; + response[JS(marker)] = cursorJson; } - boost::json::object obj; - - if (!binary) + for (auto const& txnPlusMeta : blobs) { - auto [txn, meta] = toExpandedJson(txnPlusMeta); - obj[JS(meta)] = meta; - obj[JS(tx)] = txn; - obj[JS(tx)].as_object()[JS(ledger_index)] = - txnPlusMeta.ledgerSequence; - obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date; - } - else - { - obj[JS(meta)] = ripple::strHex(txnPlusMeta.metadata); - obj[JS(tx_blob)] = ripple::strHex(txnPlusMeta.transaction); - obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence; - obj[JS(date)] = txnPlusMeta.date; - } - obj[JS(validated)] = true; - txns.push_back(obj); - } + if ((txnPlusMeta.ledgerSequence < minIndex && !forward) || + (txnPlusMeta.ledgerSequence > maxIndex && forward)) + { + response.erase(JS(marker)); + break; + } + else if (txnPlusMeta.ledgerSequence > maxIndex && !forward) + { + gLog.debug() + << "Skipping over transactions from incomplete ledger"; + continue; + } - response[JS(ledger_index_min)] = minIndex; - response[JS(ledger_index_max)] = maxIndex; - response[JS(transactions)] = txns; + boost::json::object obj; + + if (!binary) + { + auto [txn, meta] = toExpandedJson(txnPlusMeta); + obj[JS(meta)] = meta; + obj[JS(tx)] = txn; + obj[JS(tx)].as_object()[JS(ledger_index)] = + txnPlusMeta.ledgerSequence; + obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date; + } + else + { + obj[JS(meta)] = ripple::strHex(txnPlusMeta.metadata); + obj[JS(tx_blob)] = ripple::strHex(txnPlusMeta.transaction); + obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence; + obj[JS(date)] = txnPlusMeta.date; + } + obj[JS(validated)] = true; + txns.push_back(obj); + } + + response[JS(ledger_index_min)] = minIndex; + response[JS(ledger_index_max)] = maxIndex; + response[JS(transactions)] = txns; + }); + gLog.info() << "serialization took " << timeDiff - gLog.info() << "serialization took " - << std::chrono::duration_cast( - std::chrono::system_clock::now() - serializationStart) - .count() << " milliseconds"; return response; diff --git a/src/rpc/handlers/AccountTx.cpp b/src/rpc/handlers/AccountTx.cpp index 74deb48b..59aac6b4 100644 --- a/src/rpc/handlers/AccountTx.cpp +++ b/src/rpc/handlers/AccountTx.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace clio; @@ -37,27 +38,23 @@ doAccountTx(Context const& context) return status; constexpr std::string_view outerFuncName = __func__; - auto const maybeResponse = - traverseTransactions( - context, - [&accountID, &outerFuncName]( - std::shared_ptr const& backend, - std::uint32_t const limit, - bool const forward, - std::optional const& cursorIn, - boost::asio::yield_context& yield) { - auto const start = std::chrono::system_clock::now(); - auto const txnsAndCursor = backend->fetchAccountTransactions( + auto const maybeResponse = traverseTransactions( + context, + [&accountID, &outerFuncName]( + std::shared_ptr const& backend, + std::uint32_t const limit, + bool const forward, + std::optional const& cursorIn, + boost::asio::yield_context& yield) { + auto [txnsAndCursor, timeDiff] = util::timed([&]() { + return backend->fetchAccountTransactions( accountID, limit, forward, cursorIn, yield); - gLog.info() - << outerFuncName << " db fetch took " - << std::chrono::duration_cast( - std::chrono::system_clock::now() - start) - .count() - << " milliseconds - num blobs = " - << txnsAndCursor.txns.size(); - return txnsAndCursor; }); + gLog.info() << outerFuncName << " db fetch took " << timeDiff + << " milliseconds - num blobs = " + << txnsAndCursor.txns.size(); + return txnsAndCursor; + }); if (auto const status = std::get_if(&maybeResponse); status) return *status; diff --git a/src/rpc/handlers/NFTHistory.cpp b/src/rpc/handlers/NFTHistory.cpp index f4a8fc58..d94ae4ab 100644 --- a/src/rpc/handlers/NFTHistory.cpp +++ b/src/rpc/handlers/NFTHistory.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace clio; @@ -38,28 +39,25 @@ doNFTHistory(Context const& context) auto const tokenID = std::get(maybeTokenID); constexpr std::string_view outerFuncName = __func__; - auto const maybeResponse = - traverseTransactions( - context, - [&tokenID, &outerFuncName]( - std::shared_ptr const& backend, - std::uint32_t const limit, - bool const forward, - std::optional const& cursorIn, - boost::asio::yield_context& yield) - -> Backend::TransactionsAndCursor { - auto const start = std::chrono::system_clock::now(); - auto const txnsAndCursor = backend->fetchNFTTransactions( - tokenID, limit, forward, cursorIn, yield); - gLog.info() - << outerFuncName << " db fetch took " - << std::chrono::duration_cast( - std::chrono::system_clock::now() - start) - .count() - << " milliseconds - num blobs = " - << txnsAndCursor.txns.size(); - return txnsAndCursor; - }); + auto const maybeResponse = traverseTransactions( + context, + [&tokenID, &outerFuncName]( + std::shared_ptr const& backend, + std::uint32_t const limit, + bool const forward, + std::optional const& cursorIn, + boost::asio::yield_context& yield) + -> Backend::TransactionsAndCursor { + auto const [txnsAndCursor, timeDiff] = + util::timed([&, &tokenID = tokenID]() { + return backend->fetchNFTTransactions( + tokenID, limit, forward, cursorIn, yield); + }); + gLog.info() << outerFuncName << " db fetch took " << timeDiff + << " milliseconds - num blobs = " + << txnsAndCursor.txns.size(); + return txnsAndCursor; + }); if (auto const status = std::get_if(&maybeResponse); status) return *status; diff --git a/src/util/Profiler.h b/src/util/Profiler.h new file mode 100644 index 00000000..ff89f5bb --- /dev/null +++ b/src/util/Profiler.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2022, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include +#include +#include + +namespace util { + +/** + * @brief Profiler function to measure the time consuming + * @param func function object, can be a lamdba or function wrapper + * @return return a pair if function wrapper has return value: result of + * function wrapper and the elapsed time(ms) during executing the given + * function only return the elapsed time if function wrapper does not have + * return value + */ +template +[[nodiscard]] auto +timed(F&& func) +{ + auto start = std::chrono::system_clock::now(); + + if constexpr (std::is_same_v) + { + func(); + return std::chrono::duration_cast( + std::chrono::system_clock::now() - start) + .count(); + } + else + { + auto ret = func(); + auto elapsed = std::chrono::duration_cast( + std::chrono::system_clock::now() - start) + .count(); + return std::make_pair(ret, elapsed); + } +} + +} // namespace util diff --git a/src/webserver/DOSGuard.h b/src/webserver/DOSGuard.h index 4ca533be..9d5bd4a3 100644 --- a/src/webserver/DOSGuard.h +++ b/src/webserver/DOSGuard.h @@ -108,7 +108,6 @@ public: } { auto it = ipConnCount_.find(ip); - assert(it != ipConnCount_.end()); if (it != ipConnCount_.end()) { connsOk = it->second <= maxConnCount_; diff --git a/src/webserver/HttpBase.h b/src/webserver/HttpBase.h index 3e5aa59e..0e07799f 100644 --- a/src/webserver/HttpBase.h +++ b/src/webserver/HttpBase.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -437,11 +438,10 @@ handle_request( RPC::makeError(RPC::RippledError::rpcBAD_SYNTAX)))); boost::json::object response; - auto start = std::chrono::system_clock::now(); - auto v = RPC::buildResponse(*context); - auto end = std::chrono::system_clock::now(); - auto us = - std::chrono::duration_cast(end - start); + auto [v, timeDiff] = + util::timed([&]() { return RPC::buildResponse(*context); }); + + auto us = std::chrono::duration(timeDiff); RPC::logDuration(*context, us); if (auto status = std::get_if(&v)) diff --git a/src/webserver/WsBase.h b/src/webserver/WsBase.h index a9fb0d1c..e983597d 100644 --- a/src/webserver/WsBase.h +++ b/src/webserver/WsBase.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -343,11 +344,10 @@ public: response = getDefaultWsResponse(id); - auto start = std::chrono::system_clock::now(); - auto v = RPC::buildResponse(*context); - auto end = std::chrono::system_clock::now(); - auto us = std::chrono::duration_cast( - end - start); + auto [v, timeDiff] = + util::timed([&]() { return RPC::buildResponse(*context); }); + + auto us = std::chrono::duration(timeDiff); logDuration(*context, us); if (auto status = std::get_if(&v)) diff --git a/unittests/ProfilerTest.cpp b/unittests/ProfilerTest.cpp new file mode 100644 index 00000000..b9cefd30 --- /dev/null +++ b/unittests/ProfilerTest.cpp @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2022, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include + +using namespace util; +TEST(TimedTest, HasReturnValue) +{ + auto [ret, time] = timed([]() { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return 8; + }); + + ASSERT_EQ(ret, 8); + ASSERT_NE(time, 0); +} + +TEST(TimedTest, ReturnVoid) +{ + auto time = timed( + []() { std::this_thread::sleep_for(std::chrono::milliseconds(5)); }); + + ASSERT_NE(time, 0); +} + +struct FunctorTest +{ + void + operator()() const + { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } +}; + +TEST(TimedTest, Functor) +{ + auto time = timed(FunctorTest()); + + ASSERT_NE(time, 0); +} + +TEST(TimedTest, MovedLambda) +{ + auto f = []() { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return 8; + }; + auto [ret, time] = timed(std::move(f)); + + ASSERT_EQ(ret, 8); + ASSERT_NE(time, 0); +} + +TEST(TimedTest, ChangeToNs) +{ + auto f = []() { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return 8; + }; + auto [ret, time] = timed(std::move(f)); + ASSERT_EQ(ret, 8); + ASSERT_GE(time, 5 * 1000000); +} + +TEST(TimedTest, NestedLambda) +{ + double timeNested; + auto f = [&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + timeNested = timed([]() { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + return 8; + }; + auto [ret, time] = timed(std::move(f)); + ASSERT_EQ(ret, 8); + ASSERT_GE(timeNested, 5); + ASSERT_GE(time, 10 * 1000000); +} + +TEST(TimedTest, FloatSec) +{ + auto f = []() { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return 8; + }; + auto [ret, time] = timed>(std::move(f)); + ASSERT_EQ(ret, 8); + ASSERT_GE(time, 0); +} diff --git a/unittests/util/Fixtures.h b/unittests/util/Fixtures.h index 8146cfbc..53bfb8d0 100644 --- a/unittests/util/Fixtures.h +++ b/unittests/util/Fixtures.h @@ -127,6 +127,7 @@ struct AsyncAsioContextTest : public NoLoggerFixture { work.reset(); ctx.stop(); + runner.join(); } protected: @@ -134,7 +135,7 @@ protected: private: std::optional work; - std::jthread runner{[this] { ctx.run(); }}; + std::thread runner{[this] { ctx.run(); }}; }; /**