From 1e3a7cf0f44881813f72ae2ae18337b60dabdf85 Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 21 Jun 2018 17:46:52 +0200 Subject: [PATCH 1/2] fix hash-job fast-path --- src/disk_io_thread.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 7b69f55fe..79cf1c169 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -2441,20 +2441,18 @@ namespace libtorrent ret = m_disk_cache.allocate_iovec(iov, blocks_left); if (ret >= 0) { - // this is the offset that's aligned to block boundaries - boost::int64_t adjusted_offset = j->d.io.offset & ~(block_size-1); - // if this is the last piece, adjust the size of the // last buffer to match up - iov[blocks_left-1].iov_len = std::min(int(piece_size - adjusted_offset) - - (blocks_left - 1) * block_size, block_size); + iov[blocks_left-1].iov_len = int(piece_size) + - (blocks_in_piece - 1) * block_size; TORRENT_ASSERT(iov[blocks_left-1].iov_len > 0); + TORRENT_ASSERT(iov[blocks_left-1].iov_len <= block_size); time_point const start_time = clock_type::now(); ret = j->storage->get_storage_impl()->readv(iov, blocks_left , j->piece, offset, file_flags, j->error); - if (ret >= 0) + if (ret == piece_size - offset) { boost::uint32_t const read_time = total_microseconds(clock_type::now() - start_time); @@ -2469,6 +2467,8 @@ namespace libtorrent offset += iov[i].iov_len; ph->h.update(static_cast(iov[i].iov_base), iov[i].iov_len); } + TORRENT_ASSERT(offset == piece_size); + slow_path = false; l.lock(); @@ -2477,7 +2477,6 @@ namespace libtorrent } else { - TORRENT_ASSERT(j->error.ec && j->error.operation != 0); m_disk_cache.free_iovec(iov, blocks_left); } } From b7f230316cd850c03f8f98a4b4e84e18729537f4 Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Wed, 20 Jun 2018 20:37:49 -0700 Subject: [PATCH 2/2] set the minimum number of checking jobs based on the number of hasher threads To effectively mask the latency of generating more hash jobs there need to be at least two jobs in-flight for each hasher thread. --- include/libtorrent/disk_io_thread.hpp | 6 ++++++ src/disk_io_thread.cpp | 5 ++--- src/torrent.cpp | 7 +++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index 37da2d310..d0c1d027e 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -388,6 +388,12 @@ namespace libtorrent hasher_thread }; + enum + { + hasher_thread_mask = 3, + hasher_thread_divisor + }; + void thread_fun(int thread_id, thread_type_t type , boost::shared_ptr w); diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 79cf1c169..373d8e2dc 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -220,9 +220,8 @@ namespace libtorrent boost::shared_ptr work = boost::make_shared(boost::ref(m_ios)); - // the magic number 3 is also used in add_job() // every 4:th thread is a hasher thread - if ((thread_id & 0x3) == 3) type = hasher_thread; + if ((thread_id & hasher_thread_mask) == hasher_thread_mask) type = hasher_thread; m_threads.push_back(boost::shared_ptr( new thread(boost::bind(&disk_io_thread::thread_fun, this , thread_id, type, work)))); @@ -3245,7 +3244,7 @@ namespace libtorrent // if there are at least 3 threads, there's a hasher thread // and the hash jobs go into a separate queue // see set_num_threads() - if (m_num_threads > 3 && j->action == disk_io_job::hash) + if (m_num_threads > hasher_thread_mask && j->action == disk_io_job::hash) { m_queued_hash_jobs.push_back(j); } diff --git a/src/torrent.cpp b/src/torrent.cpp index 2f7e02811..d7ff04bac 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -2770,8 +2770,11 @@ namespace { / m_torrent_file->piece_length(); // if we only keep a single read operation in-flight at a time, we suffer // significant performance degradation. Always keep at least two jobs - // outstanding - if (num_outstanding < 2) num_outstanding = 2; + // outstanding per hasher thread + int const min_outstanding = 2 + * std::max(1, settings().get_int(settings_pack::aio_threads) + / disk_io_thread::hasher_thread_divisor); + if (num_outstanding < min_outstanding) num_outstanding = min_outstanding; // we might already have some outstanding jobs, if we were paused and // resumed quickly, before the outstanding jobs completed