From a942890e8d1c41f41933a3860073c07e96d3ece7 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 3 Mar 2010 07:09:04 +0000 Subject: [PATCH] added more detailed instrumentation of the disk I/O thread --- ChangeLog | 1 + docs/manual.rst | 11 ++++ include/libtorrent/disk_io_thread.hpp | 16 ++++++ include/libtorrent/sliding_average.hpp | 70 ++++++++++++++++++++++++++ src/disk_io_thread.cpp | 15 +++++- 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 include/libtorrent/sliding_average.hpp diff --git a/ChangeLog b/ChangeLog index d03954699..9a14c2e74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,7 @@ * support for BitTyrant choker algorithm * support for automatically start torrents when they receive an incoming connection + * added more detailed instrumentation of the disk I/O thread 0.15 release diff --git a/docs/manual.rst b/docs/manual.rst index 8d812c242..40876c45d 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -820,6 +820,9 @@ Returns status of the disk cache for this session. int cache_size; int read_cache_size; int total_used_buffers; + int average_queue_time; + int average_read_time; + int job_queue_length; }; ``blocks_written`` is the total number of 16 KiB blocks written to disk @@ -849,6 +852,14 @@ This includes both read and write cache. This includes the read/write disk cache as well as send and receive buffers used in peer connections. +``average_queue_time`` is the number of microseconds an average disk I/O job +has to wait in the job queue before it get processed. + +``average_read_time`` is the number of microseconds a read job takes to +wait in the queue and complete, in microseconds. + +``job_queue_length`` is the number of jobs in the job queue. + get_cache_info() ---------------- diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index 8a2bd3e73..6edc64f76 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/storage.hpp" #include "libtorrent/allocator.hpp" #include "libtorrent/io_service.hpp" +#include "libtorrent/sliding_average.hpp" #include #include @@ -140,6 +141,10 @@ namespace libtorrent // this is called when operation completes boost::function callback; + + // the time when this job was issued. This is used to + // keep track of disk I/O congestion + ptime start_time; }; // returns true if the fundamental operation @@ -189,6 +194,11 @@ namespace libtorrent // the total number of blocks that are currently in use // this includes send and receive buffers mutable int total_used_buffers; + + // times in microseconds + int average_queue_time; + int average_read_time; + int job_queue_length; }; struct TORRENT_EXPORT disk_buffer_pool : boost::noncopyable @@ -408,6 +418,12 @@ namespace libtorrent // exceed m_cache_size cache_status m_cache_stats; + // keeps average queue time for disk jobs (in microseconds) + sliding_average m_queue_time; + + // average read time for cache misses (in microseconds) + sliding_average m_read_time; + #ifdef TORRENT_DISK_STATS std::ofstream m_log; #endif diff --git a/include/libtorrent/sliding_average.hpp b/include/libtorrent/sliding_average.hpp new file mode 100644 index 000000000..f32c93042 --- /dev/null +++ b/include/libtorrent/sliding_average.hpp @@ -0,0 +1,70 @@ +/* + +Copyright (c) 2010, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +namespace libtorrent +{ +// a sliding average accumulator. Add samples to it and it +// keeps track of a sliding mean value and an average deviation +// from that average. +struct sliding_average +{ + sliding_average(): m_mean(-1), m_average_deviation(-1) {} + + void add_sample(int s) + { + if (m_mean == -1) + { + m_mean = s; + return; + } + int deviation = abs(m_mean - s); + + m_mean = m_mean - m_mean / 16 + s / 16; + + if (m_average_deviation == -1) + { + m_average_deviation = deviation; + return; + } + m_average_deviation = m_average_deviation - m_average_deviation / 16 + deviation / 16; + } + + int mean() const { return m_mean != -1 ? m_mean : 0; } + int avg_deviation() const { return m_average_deviation != -1 ? m_average_deviation : 0; } + +private: + int m_mean; + int m_average_deviation; +}; + +} + diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 8a5bc2a07..fbccafaf0 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -362,7 +362,14 @@ namespace libtorrent mutex::scoped_lock l(m_piece_mutex); m_cache_stats.total_used_buffers = in_use(); m_cache_stats.queued_bytes = m_queue_buffer_size; - return m_cache_stats; + + cache_status ret = m_cache_stats; + + ret.average_queue_time = m_queue_time.mean(); + ret.average_read_time = m_read_time.mean(); + ret.job_queue_length = m_jobs.size(); + + return ret; } // aborts read operations @@ -1315,6 +1322,7 @@ namespace libtorrent { m_jobs.push_back(j); m_jobs.back().callback.swap(const_cast&>(f)); + m_jobs.back().start_time = time_now_hires(); if (j.action == disk_io_job::write) m_queue_buffer_size += j.buffer_size; @@ -1591,6 +1599,9 @@ namespace libtorrent if (j.storage && j.storage->get_storage_impl()->m_settings == 0) j.storage->get_storage_impl()->m_settings = &m_settings; + ptime now = time_now_hires(); + m_queue_time.add_sample(total_microseconds(now - j.start_time)); + switch (j.action) { case disk_io_job::update_settings: @@ -2216,6 +2227,8 @@ namespace libtorrent && j.buffer != 0) rename_buffer(j.buffer, "posted send buffer"); #endif + ptime now = time_now_hires(); + m_read_time.add_sample(total_microseconds(now - j.start_time)); post_callback(j.callback, j, ret); #ifndef BOOST_NO_EXCEPTIONS } catch (std::exception&)