diff options
author | Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com> | 2020-12-29 17:41:08 +0300 |
---|---|---|
committer | Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com> | 2021-03-16 13:21:39 +0300 |
commit | 7eeb88fccc7e7071a8065afbbffc36379e8b7091 (patch) | |
tree | cf7ed48c4f889641b9f8d08c80d9399613ca3e63 /test | |
parent | dfa6771c4f8ba0635a252a39d13a48c7c5c75489 (diff) |
Implement dynamic_thread_pool_group::io_aware_work_item.
Diffstat (limited to 'test')
-rw-r--r-- | test/tests/dynamic_thread_pool_group.cpp | 95 | ||||
-rw-r--r-- | test/tests/statfs.cpp | 6 |
2 files changed, 95 insertions, 6 deletions
diff --git a/test/tests/dynamic_thread_pool_group.cpp b/test/tests/dynamic_thread_pool_group.cpp index 8e068583..9c8c6de8 100644 --- a/test/tests/dynamic_thread_pool_group.cpp +++ b/test/tests/dynamic_thread_pool_group.cpp @@ -231,7 +231,7 @@ static inline void TestDynamicThreadPoolGroupNestingWorks() uint64_t mean = 0, count = 0; for(auto &i : time_bucket) { - mean += i.first*i.second; + mean += i.first * i.second; count += i.second; } mean /= count; @@ -329,7 +329,96 @@ static inline void TestDynamicThreadPoolGroupNestingWorks() BOOST_CHECK(shared_states[MAX_NESTING - 1].stddev < shared_states[MAX_NESTING / 2].stddev / 2); } +static inline void TestDynamicThreadPoolGroupIoAwareWorks() +{ + namespace llfio = LLFIO_V2_NAMESPACE; + static constexpr size_t WORK_ITEMS = 1000; + static constexpr size_t IO_SIZE = 1 * 65536; + struct shared_state_t + { + llfio::file_handle h; + llfio::dynamic_thread_pool_group::io_aware_work_item::io_handle_awareness awareness; + std::atomic<size_t> concurrency{0}, max_concurrency{0}; + std::atomic<uint64_t> current_pacing{0}; + } shared_state; + struct work_item final : public llfio::dynamic_thread_pool_group::io_aware_work_item + { + using _base = llfio::dynamic_thread_pool_group::io_aware_work_item; + shared_state_t *shared_state; + + work_item() = default; + explicit work_item(shared_state_t *_shared_state) + : _base({&_shared_state->awareness, 1}) + , shared_state(_shared_state) + { + } + work_item(work_item &&o) noexcept + : _base(std::move(o)) + , shared_state(o.shared_state) + { + } + + virtual intptr_t io_aware_next(llfio::deadline &d) noexcept override + { + shared_state->current_pacing.store(d.nsecs, std::memory_order_relaxed); + return 1; + } + virtual llfio::result<void> operator()(intptr_t /*unused*/) noexcept override + { + auto concurrency = shared_state->concurrency.fetch_add(1, std::memory_order_relaxed) + 1; + for(size_t expected_ = shared_state->max_concurrency; concurrency > expected_;) + { + shared_state->max_concurrency.compare_exchange_weak(expected_, concurrency); + } + static thread_local std::vector<llfio::byte, llfio::utils::page_allocator<llfio::byte>> buffer(IO_SIZE); + OUTCOME_TRY(shared_state->h.read((concurrency - 1) * IO_SIZE, {{buffer}})); + shared_state->concurrency.fetch_sub(1, std::memory_order_relaxed); + return llfio::success(); + } + // virtual void group_complete(const llfio::result<void> &/*unused*/) noexcept override { } + }; + shared_state.h = llfio::file_handle::temp_file({}, llfio::file_handle::mode::write, llfio::file_handle::creation::only_if_not_exist, + llfio::file_handle::caching::only_metadata) + .value(); + shared_state.awareness.h = &shared_state.h; + shared_state.h.truncate(WORK_ITEMS * IO_SIZE).value(); + alignas(4096) llfio::byte buffer[IO_SIZE]; + llfio::utils::random_fill((char *) buffer, sizeof(buffer)); + std::vector<work_item> workitems; + for(size_t n = 0; n < WORK_ITEMS; n++) + { + workitems.emplace_back(&shared_state); + shared_state.h.write(n * IO_SIZE, {{buffer, sizeof(buffer)}}).value(); + } + auto tpg = llfio::make_dynamic_thread_pool_group().value(); + tpg->submit(llfio::span<work_item>(workitems)).value(); + auto begin = std::chrono::steady_clock::now(); + size_t paced = 0; + while(std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - begin) < std::chrono::seconds(60)) + { + llfio::statfs_t statfs; + statfs.fill(shared_state.h, llfio::statfs_t::want::iosinprogress | llfio::statfs_t::want::iosbusytime | llfio::statfs_t::want::mntonname).value(); + std::cout << "\nStorage device at " << statfs.f_mntonname << " is at " << (100.0f * statfs.f_iosbusytime) << "% utilisation and has an i/o queue depth of " + << statfs.f_iosinprogress << ". Current concurrency is " << shared_state.concurrency.load(std::memory_order_relaxed) << " and current pacing is " + << (shared_state.current_pacing.load(std::memory_order_relaxed) / 1000.0) << " microseconds." << std::endl; + if(shared_state.current_pacing.load(std::memory_order_relaxed) > 0) + { + paced++; + } + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + tpg->stop().value(); + auto r = tpg->wait(); + if(!r && r.error() != llfio::errc::operation_canceled) + { + r.value(); + } + BOOST_CHECK(paced > 0); +} + KERNELTEST_TEST_KERNEL(integration, llfio, dynamic_thread_pool_group, works, "Tests that llfio::dynamic_thread_pool_group works as expected", - TestDynamicThreadPoolGroupWorks()) + TestDynamicThreadPoolGroupWorks()) KERNELTEST_TEST_KERNEL(integration, llfio, dynamic_thread_pool_group, nested, "Tests that nesting of llfio::dynamic_thread_pool_group works as expected", - TestDynamicThreadPoolGroupNestingWorks()) + TestDynamicThreadPoolGroupNestingWorks()) +KERNELTEST_TEST_KERNEL(integration, llfio, dynamic_thread_pool_group, io_aware_work_item, + "Tests that llfio::dynamic_thread_pool_group::io_aware_work_item works as expected", TestDynamicThreadPoolGroupIoAwareWorks()) diff --git a/test/tests/statfs.cpp b/test/tests/statfs.cpp index 6d4d9881..138fd4c1 100644 --- a/test/tests/statfs.cpp +++ b/test/tests/statfs.cpp @@ -49,7 +49,7 @@ static inline void TestStatfsIosInProgress() std::cout << "\n mounted filesystem = " << statfs.f_mntfromname; std::cout << "\n directory on which mounted = " << statfs.f_mntonname; std::cout << "\n i/o's currently in progress (i.e. queue depth) = " << statfs.f_iosinprogress; - std::cout << "\n percentage of time spent doing i/o (1.0 = 100%) = " << statfs.f_ioswaittime; + std::cout << "\n percentage of time spent doing i/o (1.0 = 100%) = " << statfs.f_iosbusytime; std::cout << std::endl; }; llfio::statfs_t s1base, s2base; @@ -78,7 +78,7 @@ static inline void TestStatfsIosInProgress() print_statfs(h1, s1load); print_statfs(h2, s2load); // BOOST_CHECK(s1load.f_iosinprogress > s1base.f_iosinprogress); - BOOST_CHECK(std::isnan(s1base.f_ioswaittime) || s1load.f_ioswaittime > s1base.f_ioswaittime); + BOOST_CHECK(std::isnan(s1base.f_iosbusytime) || s1load.f_iosbusytime > s1base.f_iosbusytime); f.get(); done = false; } @@ -92,7 +92,7 @@ static inline void TestStatfsIosInProgress() print_statfs(h1, s1load); print_statfs(h2, s2load); // BOOST_CHECK(s2load.f_iosinprogress > s2base.f_iosinprogress); - BOOST_CHECK(std::isnan(s2base.f_ioswaittime) || s2load.f_ioswaittime > s2base.f_ioswaittime); + BOOST_CHECK(std::isnan(s2base.f_iosbusytime) || s2load.f_iosbusytime > s2base.f_iosbusytime); f.get(); done = false; } |