changed the double send buffers to a chained buffer using iovec send operations. buffers are recycled (saves memory and cpu) and memory copies are avoided (saves cpu). More statistics is added to track buffer usage
This commit is contained in:
parent
09c1e0f007
commit
b48948e231
|
@ -168,6 +168,10 @@ namespace libtorrent
|
||||||
// thread started to run the main downloader loop
|
// thread started to run the main downloader loop
|
||||||
struct session_impl: boost::noncopyable
|
struct session_impl: boost::noncopyable
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// the size of each allocation that is chained in the send buffer
|
||||||
|
enum { send_buffer_size = 200 };
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
friend class ::libtorrent::peer_connection;
|
friend class ::libtorrent::peer_connection;
|
||||||
#endif
|
#endif
|
||||||
|
@ -329,6 +333,24 @@ namespace libtorrent
|
||||||
{ return m_dht_proxy; }
|
{ return m_dht_proxy; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
void log_buffer_usage()
|
||||||
|
{
|
||||||
|
int send_buffer_capacity = 0;
|
||||||
|
int used_send_buffer = 0;
|
||||||
|
for (connection_map::const_iterator i = m_connections.begin()
|
||||||
|
, end(m_connections.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
send_buffer_capacity += i->second->send_buffer_capacity();
|
||||||
|
used_send_buffer += i->second->send_buffer_size();
|
||||||
|
}
|
||||||
|
assert(send_buffer_capacity >= used_send_buffer);
|
||||||
|
m_buffer_usage_logger << log_time() << " send_buffer_size: " << send_buffer_capacity << std::endl;
|
||||||
|
m_buffer_usage_logger << log_time() << " used_send_buffer: " << used_send_buffer << std::endl;
|
||||||
|
m_buffer_usage_logger << log_time() << " send_buffer_utilization: "
|
||||||
|
<< (used_send_buffer * 100.f / send_buffer_capacity) << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
void start_lsd();
|
void start_lsd();
|
||||||
void start_natpmp();
|
void start_natpmp();
|
||||||
void start_upnp();
|
void start_upnp();
|
||||||
|
@ -339,11 +361,25 @@ namespace libtorrent
|
||||||
|
|
||||||
// handles delayed alerts
|
// handles delayed alerts
|
||||||
alert_manager m_alerts;
|
alert_manager m_alerts;
|
||||||
|
|
||||||
|
std::pair<char*, int> allocate_buffer(int size);
|
||||||
|
void free_buffer(char* buf, int size);
|
||||||
|
void free_disk_buffer(char* buf);
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
|
|
||||||
void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih);
|
void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih);
|
||||||
|
|
||||||
|
// handles disk io requests asynchronously
|
||||||
|
// peers have pointers into the disk buffer
|
||||||
|
// pool, and must be destructed before this
|
||||||
|
// object.
|
||||||
|
disk_io_thread m_disk_thread;
|
||||||
|
|
||||||
|
// this pool is used to allocate and recycle send
|
||||||
|
// buffers from.
|
||||||
|
boost::pool<> m_send_buffers;
|
||||||
|
|
||||||
// this is where all active sockets are stored.
|
// this is where all active sockets are stored.
|
||||||
// the selector can sleep while there's no activity on
|
// the selector can sleep while there's no activity on
|
||||||
// them
|
// them
|
||||||
|
@ -358,9 +394,6 @@ namespace libtorrent
|
||||||
// when they are destructed.
|
// when they are destructed.
|
||||||
file_pool m_files;
|
file_pool m_files;
|
||||||
|
|
||||||
// handles disk io requests asynchronously
|
|
||||||
disk_io_thread m_disk_thread;
|
|
||||||
|
|
||||||
// this is a list of half-open tcp connections
|
// this is a list of half-open tcp connections
|
||||||
// (only outgoing connections)
|
// (only outgoing connections)
|
||||||
// this has to be one of the last
|
// this has to be one of the last
|
||||||
|
@ -526,6 +559,10 @@ namespace libtorrent
|
||||||
// logger used to write bandwidth usage statistics
|
// logger used to write bandwidth usage statistics
|
||||||
std::ofstream m_stats_logger;
|
std::ofstream m_stats_logger;
|
||||||
int m_second_counter;
|
int m_second_counter;
|
||||||
|
// used to log send buffer usage statistics
|
||||||
|
std::ofstream m_buffer_usage_logger;
|
||||||
|
// the number of send buffers that are allocated
|
||||||
|
int m_buffer_allocations;
|
||||||
#endif
|
#endif
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
boost::shared_ptr<logger> create_log(std::string const& name
|
boost::shared_ptr<logger> create_log(std::string const& name
|
||||||
|
|
|
@ -208,7 +208,7 @@ namespace libtorrent
|
||||||
void write_cancel(peer_request const& r);
|
void write_cancel(peer_request const& r);
|
||||||
void write_bitfield(std::vector<bool> const& bitfield);
|
void write_bitfield(std::vector<bool> const& bitfield);
|
||||||
void write_have(int index);
|
void write_have(int index);
|
||||||
void write_piece(peer_request const& r, char const* buffer);
|
void write_piece(peer_request const& r, char* buffer);
|
||||||
void write_handshake();
|
void write_handshake();
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
void write_extensions();
|
void write_extensions();
|
||||||
|
@ -270,8 +270,17 @@ namespace libtorrent
|
||||||
// these functions encrypt the send buffer if m_rc4_encrypted
|
// these functions encrypt the send buffer if m_rc4_encrypted
|
||||||
// is true, otherwise it passes the call to the
|
// is true, otherwise it passes the call to the
|
||||||
// peer_connection functions of the same names
|
// peer_connection functions of the same names
|
||||||
void send_buffer(char* begin, char* end);
|
void send_buffer(char* buf, int size);
|
||||||
buffer::interval allocate_send_buffer(int size);
|
buffer::interval allocate_send_buffer(int size);
|
||||||
|
template <class Destructor>
|
||||||
|
void append_send_buffer(char* buffer, int size, Destructor const& destructor)
|
||||||
|
{
|
||||||
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
|
if (m_rc4_encrypted)
|
||||||
|
m_RC4_handler->encrypt(buffer, size);
|
||||||
|
#endif
|
||||||
|
peer_connection::append_send_buffer(buffer, size, destructor);
|
||||||
|
}
|
||||||
void setup_send();
|
void setup_send();
|
||||||
|
|
||||||
// Returns offset at which bytestream (src, src + src_size)
|
// Returns offset at which bytestream (src, src + src_size)
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2007, 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_CHAINED_BUFFER_HPP_INCLUDED
|
||||||
|
#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <asio.hpp>
|
||||||
|
#include <list>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
struct chained_buffer
|
||||||
|
{
|
||||||
|
chained_buffer(): m_bytes(0), m_capacity(0) {}
|
||||||
|
|
||||||
|
struct buffer_t
|
||||||
|
{
|
||||||
|
boost::function<void(char*)> free; // destructs the buffer
|
||||||
|
char* buf; // the first byte of the buffer
|
||||||
|
int size; // the total size of the buffer
|
||||||
|
|
||||||
|
char* start; // the first byte to send/receive in the buffer
|
||||||
|
int used_size; // this is the number of bytes to send/receive
|
||||||
|
};
|
||||||
|
|
||||||
|
bool empty() const { return m_bytes == 0; }
|
||||||
|
int size() const { return m_bytes; }
|
||||||
|
int capacity() const { return m_capacity; }
|
||||||
|
|
||||||
|
void pop_front(int bytes_to_pop)
|
||||||
|
{
|
||||||
|
assert(bytes_to_pop <= m_bytes);
|
||||||
|
while (bytes_to_pop > 0 && !m_vec.empty())
|
||||||
|
{
|
||||||
|
buffer_t& b = m_vec.front();
|
||||||
|
if (b.used_size > bytes_to_pop)
|
||||||
|
{
|
||||||
|
b.start += bytes_to_pop;
|
||||||
|
b.used_size -= bytes_to_pop;
|
||||||
|
m_bytes -= bytes_to_pop;
|
||||||
|
assert(m_bytes <= m_capacity);
|
||||||
|
assert(m_bytes >= 0);
|
||||||
|
assert(m_capacity >= 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.free(b.buf);
|
||||||
|
m_bytes -= b.used_size;
|
||||||
|
m_capacity -= b.size;
|
||||||
|
bytes_to_pop -= b.used_size;
|
||||||
|
assert(m_bytes >= 0);
|
||||||
|
assert(m_capacity >= 0);
|
||||||
|
assert(m_bytes <= m_capacity);
|
||||||
|
m_vec.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class D>
|
||||||
|
void append_buffer(char* buffer, int size, int used_size, D const& destructor)
|
||||||
|
{
|
||||||
|
assert(size >= used_size);
|
||||||
|
buffer_t b;
|
||||||
|
b.buf = buffer;
|
||||||
|
b.size = size;
|
||||||
|
b.start = buffer;
|
||||||
|
b.used_size = used_size;
|
||||||
|
b.free = destructor;
|
||||||
|
m_vec.push_back(b);
|
||||||
|
|
||||||
|
m_bytes += used_size;
|
||||||
|
m_capacity += size;
|
||||||
|
assert(m_bytes <= m_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the number of bytes available at the
|
||||||
|
// end of the last chained buffer.
|
||||||
|
int space_in_last_buffer()
|
||||||
|
{
|
||||||
|
if (m_vec.empty()) return 0;
|
||||||
|
buffer_t& b = m_vec.back();
|
||||||
|
return b.size - b.used_size - (b.start - b.buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tries to copy the given buffer to the end of the
|
||||||
|
// last chained buffer. If there's not enough room
|
||||||
|
// it returns false
|
||||||
|
bool append(char const* buf, int size)
|
||||||
|
{
|
||||||
|
char* insert = allocate_appendix(size);
|
||||||
|
if (insert == 0) return false;
|
||||||
|
std::memcpy(insert, buf, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tries to allocate memory from the end
|
||||||
|
// of the last buffer. If there isn't
|
||||||
|
// enough room, returns 0
|
||||||
|
char* allocate_appendix(int size)
|
||||||
|
{
|
||||||
|
if (m_vec.empty()) return 0;
|
||||||
|
buffer_t& b = m_vec.back();
|
||||||
|
char* insert = b.start + b.used_size;
|
||||||
|
if (insert + size > b.buf + b.size) return 0;
|
||||||
|
b.used_size += size;
|
||||||
|
m_bytes += size;
|
||||||
|
assert(m_bytes <= m_capacity);
|
||||||
|
return insert;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<asio::const_buffer> const& build_iovec(int to_send)
|
||||||
|
{
|
||||||
|
m_tmp_vec.clear();
|
||||||
|
|
||||||
|
for (std::list<buffer_t>::iterator i = m_vec.begin()
|
||||||
|
, end(m_vec.end()); to_send > 0 && i != end; ++i)
|
||||||
|
{
|
||||||
|
if (i->used_size > to_send)
|
||||||
|
{
|
||||||
|
assert(to_send > 0);
|
||||||
|
m_tmp_vec.push_back(asio::const_buffer(i->start, to_send));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(i->used_size > 0);
|
||||||
|
m_tmp_vec.push_back(asio::const_buffer(i->start, i->used_size));
|
||||||
|
to_send -= i->used_size;
|
||||||
|
}
|
||||||
|
return m_tmp_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
~chained_buffer()
|
||||||
|
{
|
||||||
|
for (std::list<buffer_t>::iterator i = m_vec.begin()
|
||||||
|
, end(m_vec.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
i->free(i->buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// this is the list of all the buffers we want to
|
||||||
|
// send
|
||||||
|
std::list<buffer_t> m_vec;
|
||||||
|
|
||||||
|
// this is the number of bytes in the send buf.
|
||||||
|
// this will always be equal to the sum of the
|
||||||
|
// size of all buffers in vec
|
||||||
|
int m_bytes;
|
||||||
|
|
||||||
|
// the total size of all buffers in the chain
|
||||||
|
// including unused space
|
||||||
|
int m_capacity;
|
||||||
|
|
||||||
|
// this is the vector of buffers used when
|
||||||
|
// invoking the async write call
|
||||||
|
std::list<asio::const_buffer> m_tmp_vec;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -94,6 +94,11 @@ namespace libtorrent
|
||||||
disk_io_thread(int block_size = 16 * 1024);
|
disk_io_thread(int block_size = 16 * 1024);
|
||||||
~disk_io_thread();
|
~disk_io_thread();
|
||||||
|
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
int disk_allocations() const
|
||||||
|
{ return m_allocations; }
|
||||||
|
#endif
|
||||||
|
|
||||||
// aborts read operations
|
// aborts read operations
|
||||||
void stop(boost::intrusive_ptr<piece_manager> s);
|
void stop(boost::intrusive_ptr<piece_manager> s);
|
||||||
void add_job(disk_io_job const& j
|
void add_job(disk_io_job const& j
|
||||||
|
@ -110,6 +115,7 @@ namespace libtorrent
|
||||||
void operator()();
|
void operator()();
|
||||||
|
|
||||||
char* allocate_buffer();
|
char* allocate_buffer();
|
||||||
|
void free_buffer(char* buf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -129,6 +135,9 @@ namespace libtorrent
|
||||||
#ifdef TORRENT_DISK_STATS
|
#ifdef TORRENT_DISK_STATS
|
||||||
std::ofstream m_log;
|
std::ofstream m_log;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
int m_allocations;
|
||||||
|
#endif
|
||||||
|
|
||||||
// thread for performing blocking disk io operations
|
// thread for performing blocking disk io operations
|
||||||
boost::thread m_disk_io_thread;
|
boost::thread m_disk_io_thread;
|
||||||
|
|
|
@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <boost/array.hpp>
|
#include <boost/array.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
|
#include <boost/pool/pool.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
@ -73,6 +74,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/socket_type.hpp"
|
#include "libtorrent/socket_type.hpp"
|
||||||
#include "libtorrent/intrusive_ptr_base.hpp"
|
#include "libtorrent/intrusive_ptr_base.hpp"
|
||||||
#include "libtorrent/assert.hpp"
|
#include "libtorrent/assert.hpp"
|
||||||
|
#include "libtorrent/chained_buffer.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -356,14 +358,23 @@ namespace libtorrent
|
||||||
virtual boost::optional<piece_block_progress>
|
virtual boost::optional<piece_block_progress>
|
||||||
downloading_piece_progress() const
|
downloading_piece_progress() const
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << "downloading_piece_progress() dispatched to the base class!\n";
|
(*m_logger) << "downloading_piece_progress() dispatched to the base class!\n";
|
||||||
#endif
|
#endif
|
||||||
return boost::optional<piece_block_progress>();
|
return boost::optional<piece_block_progress>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_buffer(char const* begin, char const* end);
|
void send_buffer(char const* begin, int size);
|
||||||
buffer::interval allocate_send_buffer(int size);
|
buffer::interval allocate_send_buffer(int size);
|
||||||
|
template <class Destructor>
|
||||||
|
void append_send_buffer(char* buffer, int size, Destructor const& destructor)
|
||||||
|
{
|
||||||
|
m_send_buffer.append_buffer(buffer, size, size, destructor);
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
m_ses.m_buffer_usage_logger << log_time() << " append_send_buffer: " << size << std::endl;
|
||||||
|
m_ses.log_buffer_usage();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
void setup_send();
|
void setup_send();
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||||
|
@ -376,6 +387,12 @@ namespace libtorrent
|
||||||
bool has_country() const { return m_country[0] != 0; }
|
bool has_country() const { return m_country[0] != 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int send_buffer_size() const
|
||||||
|
{ return m_send_buffer.size(); }
|
||||||
|
|
||||||
|
int send_buffer_capacity() const
|
||||||
|
{ return m_send_buffer.capacity(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void get_specific_peer_info(peer_info& p) const = 0;
|
virtual void get_specific_peer_info(peer_info& p) const = 0;
|
||||||
|
@ -388,7 +405,7 @@ namespace libtorrent
|
||||||
virtual void write_cancel(peer_request const& r) = 0;
|
virtual void write_cancel(peer_request const& r) = 0;
|
||||||
virtual void write_have(int index) = 0;
|
virtual void write_have(int index) = 0;
|
||||||
virtual void write_keepalive() = 0;
|
virtual void write_keepalive() = 0;
|
||||||
virtual void write_piece(peer_request const& r, char const* buffer) = 0;
|
virtual void write_piece(peer_request const& r, char* buffer) = 0;
|
||||||
|
|
||||||
virtual void write_reject_request(peer_request const& r) = 0;
|
virtual void write_reject_request(peer_request const& r) = 0;
|
||||||
virtual void write_allow_fast(int piece) = 0;
|
virtual void write_allow_fast(int piece) = 0;
|
||||||
|
@ -401,13 +418,6 @@ namespace libtorrent
|
||||||
virtual void on_sent(asio::error_code const& error
|
virtual void on_sent(asio::error_code const& error
|
||||||
, std::size_t bytes_transferred) = 0;
|
, std::size_t bytes_transferred) = 0;
|
||||||
|
|
||||||
int send_buffer_size() const
|
|
||||||
{
|
|
||||||
return (int)m_send_buffer[0].size()
|
|
||||||
+ (int)m_send_buffer[1].size()
|
|
||||||
- m_write_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
buffer::interval wr_recv_buffer()
|
buffer::interval wr_recv_buffer()
|
||||||
{
|
{
|
||||||
|
@ -512,31 +522,13 @@ namespace libtorrent
|
||||||
int m_recv_pos;
|
int m_recv_pos;
|
||||||
buffer m_recv_buffer;
|
buffer m_recv_buffer;
|
||||||
|
|
||||||
// this is the buffer where data that is
|
chained_buffer m_send_buffer;
|
||||||
// to be sent is stored until it gets
|
|
||||||
// consumed by send(). Since asio requires
|
|
||||||
// the memory buffer that is given to async.
|
|
||||||
// operations to remain valid until the operation
|
|
||||||
// finishes, there has to be two buffers. While
|
|
||||||
// waiting for a async_write operation on one
|
|
||||||
// buffer, the other is used to write data to
|
|
||||||
// be queued up.
|
|
||||||
buffer m_send_buffer[2];
|
|
||||||
// the current send buffer is the one to write to.
|
|
||||||
// (m_current_send_buffer + 1) % 2 is the
|
|
||||||
// buffer we're currently waiting for.
|
|
||||||
int m_current_send_buffer;
|
|
||||||
|
|
||||||
// the number of bytes we are currently reading
|
// the number of bytes we are currently reading
|
||||||
// from disk, that will be added to the send
|
// from disk, that will be added to the send
|
||||||
// buffer as soon as they complete
|
// buffer as soon as they complete
|
||||||
int m_reading_bytes;
|
int m_reading_bytes;
|
||||||
|
|
||||||
// if the sending buffer doesn't finish in one send
|
|
||||||
// operation, this is the position within that buffer
|
|
||||||
// where the next operation should continue
|
|
||||||
int m_write_pos;
|
|
||||||
|
|
||||||
// timeouts
|
// timeouts
|
||||||
ptime m_last_receive;
|
ptime m_last_receive;
|
||||||
ptime m_last_sent;
|
ptime m_last_sent;
|
||||||
|
|
|
@ -184,6 +184,9 @@ namespace libtorrent
|
||||||
std::pair<bool, float> check_files(std::vector<bool>& pieces
|
std::pair<bool, float> check_files(std::vector<bool>& pieces
|
||||||
, int& num_pieces, boost::recursive_mutex& mutex);
|
, int& num_pieces, boost::recursive_mutex& mutex);
|
||||||
|
|
||||||
|
// frees a buffer that was returned from a read operation
|
||||||
|
void free_buffer(char* buf);
|
||||||
|
|
||||||
void write_resume_data(entry& rd) const;
|
void write_resume_data(entry& rd) const;
|
||||||
bool verify_resume_data(entry& rd, std::string& error);
|
bool verify_resume_data(entry& rd, std::string& error);
|
||||||
|
|
||||||
|
|
|
@ -389,5 +389,18 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
inline std::string log_time()
|
||||||
|
{
|
||||||
|
static ptime start = time_now();
|
||||||
|
char ret[200];
|
||||||
|
std::sprintf(ret, "%d", total_milliseconds(time_now() - start));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ namespace libtorrent
|
||||||
void write_request(peer_request const& r);
|
void write_request(peer_request const& r);
|
||||||
void write_cancel(peer_request const& r) {}
|
void write_cancel(peer_request const& r) {}
|
||||||
void write_have(int index) {}
|
void write_have(int index) {}
|
||||||
void write_piece(peer_request const& r, char const* buffer) { assert(false); }
|
void write_piece(peer_request const& r, char* buffer) { assert(false); }
|
||||||
void write_keepalive() {}
|
void write_keepalive() {}
|
||||||
void on_connected();
|
void on_connected();
|
||||||
void write_reject_request(peer_request const&) {}
|
void write_reject_request(peer_request const&) {}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
import os, sys, time
|
||||||
|
|
||||||
|
lines = open(sys.argv[1], 'rb').readlines()
|
||||||
|
|
||||||
|
#keys = ['send_buffer_utilization']
|
||||||
|
keys = ['send_buffer_size', 'used_send_buffer', 'protocol_buffer']
|
||||||
|
#keys = ['send_buffer_alloc', 'send_buffer', 'allocate_buffer_alloc', 'allocate_buffer', 'protocol_buffer']
|
||||||
|
#keys = ['send_buffer_alloc', 'send_buffer', 'allocate_buffer_alloc', 'allocate_buffer', 'protocol_buffer', 'append_send_buffer']
|
||||||
|
|
||||||
|
average = ['send_buffer_utilization', 'send_buffer_size', 'used_send_buffer']
|
||||||
|
average_interval = 120000
|
||||||
|
render = 'lines'
|
||||||
|
|
||||||
|
time_limit = -1
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
time_limit = long(sys.argv[2])
|
||||||
|
|
||||||
|
|
||||||
|
# logfile format:
|
||||||
|
# <time(ms)> <key> <value>
|
||||||
|
# example:
|
||||||
|
# 16434 allocate_buffer: 17
|
||||||
|
for k in keys:
|
||||||
|
|
||||||
|
last_sample = 0
|
||||||
|
average_accumulator = 0
|
||||||
|
average_samples = 0
|
||||||
|
peak = 0
|
||||||
|
|
||||||
|
out = open(k + '.dat', 'wb')
|
||||||
|
eval_average = False
|
||||||
|
if k in average:
|
||||||
|
eval_average = True
|
||||||
|
peak_out = open(k + '_peak.dat', 'wb')
|
||||||
|
|
||||||
|
for l in lines:
|
||||||
|
l = l.split(' ')
|
||||||
|
if len(l) != 3:
|
||||||
|
print l
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
if l[1] == k + ':':
|
||||||
|
if time_limit != -1 and long(l[0]) > time_limit: break
|
||||||
|
time = l[0]
|
||||||
|
value = l[2]
|
||||||
|
if eval_average:
|
||||||
|
while long(time) > last_sample + average_interval:
|
||||||
|
last_sample = last_sample + average_interval
|
||||||
|
if average_samples < 1: average_samples = 1
|
||||||
|
print >>out, '%d %f' % (last_sample, average_accumulator / average_samples)
|
||||||
|
print >>peak_out, '%d %f' % (last_sample, peak)
|
||||||
|
average_accumulator = 0
|
||||||
|
average_samples = 0
|
||||||
|
peak = 0
|
||||||
|
average_accumulator = average_accumulator + float(value)
|
||||||
|
average_samples = average_samples + 1
|
||||||
|
if float(value) > peak: peak = float(value)
|
||||||
|
else:
|
||||||
|
print >>out, time + ' ' + value,
|
||||||
|
except:
|
||||||
|
print l
|
||||||
|
|
||||||
|
|
||||||
|
out = open('send_buffer.gnuplot', 'wb')
|
||||||
|
print >>out, "set term png size 1200,700"
|
||||||
|
print >>out, 'set output "send_buffer.png"'
|
||||||
|
print >>out, 'set xrange [0:*]'
|
||||||
|
print >>out, 'set xlabel "time (ms)"'
|
||||||
|
print >>out, 'set ylabel "bytes (B)"'
|
||||||
|
print >>out, "set style data lines"
|
||||||
|
print >>out, "set key box"
|
||||||
|
print >>out, 'plot',
|
||||||
|
for k in keys:
|
||||||
|
if k in average:
|
||||||
|
print >>out, ' "%s.dat" using 1:2 title "%s %d seconds average" with %s,' % (k, k, average_interval / 1000., render),
|
||||||
|
print >>out, ' "%s_peak.dat" using 1:2 title "%s %d seconds peak" with %s,' % (k, k, average_interval / 1000., render),
|
||||||
|
else:
|
||||||
|
print >>out, ' "%s.dat" using 1:2 title "%s" with %s,' % (k, k, render),
|
||||||
|
print >>out, 'x=0'
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
os.system('gnuplot send_buffer.gnuplot');
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import os, sys, time
|
||||||
|
|
||||||
|
keys = ['upload rate', 'download rate', 'downloading torrents', \
|
||||||
|
'seeding torrents', 'peers', 'connecting peers', 'disk block buffers']
|
||||||
|
|
||||||
|
axes = ['x1y2', 'x1y2', 'x1y1', 'x1y1', 'x1y1', 'x1y1', 'x1y1']
|
||||||
|
|
||||||
|
out = open('session_stats.gnuplot', 'wb')
|
||||||
|
print >>out, "set term png size 1200,700"
|
||||||
|
print >>out, 'set output "session_stats.png"'
|
||||||
|
print >>out, 'set xrange [0:*]'
|
||||||
|
print >>out, 'set xlabel "time (s)"'
|
||||||
|
print >>out, 'set ylabel "number"'
|
||||||
|
print >>out, 'set y2label "Rate (B/s)"'
|
||||||
|
print >>out, 'set y2range [0:*]'
|
||||||
|
print >>out, 'set y2tics 20000'
|
||||||
|
print >>out, "set style data lines"
|
||||||
|
print >>out, "set key box"
|
||||||
|
print >>out, 'plot',
|
||||||
|
column = 2
|
||||||
|
for k in keys:
|
||||||
|
print >>out, ' "%s" using 1:%d title "%s" axes %s with lines,' % (sys.argv[1], column, k, axes[column-2]),
|
||||||
|
column = column + 1
|
||||||
|
print >>out, 'x=0'
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
os.system('gnuplot session_stats.gnuplot');
|
||||||
|
|
|
@ -251,12 +251,10 @@ namespace libtorrent
|
||||||
(*m_logger) << time_now_string()
|
(*m_logger) << time_now_string()
|
||||||
<< " ==> DHT_PORT [ " << listen_port << " ]\n";
|
<< " ==> DHT_PORT [ " << listen_port << " ]\n";
|
||||||
#endif
|
#endif
|
||||||
buffer::interval packet = allocate_send_buffer(7);
|
char msg[] = {0,0,0,3, msg_dht_port, 0, 0};
|
||||||
detail::write_uint32(3, packet.begin);
|
char* ptr = msg + 5;
|
||||||
detail::write_uint8(msg_dht_port, packet.begin);
|
detail::write_uint16(listen_port, ptr);
|
||||||
detail::write_uint16(listen_port, packet.begin);
|
send_buffer(msg, sizeof(msg));
|
||||||
assert(packet.begin == packet.end);
|
|
||||||
setup_send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_have_all()
|
void bt_peer_connection::write_have_all()
|
||||||
|
@ -270,8 +268,8 @@ namespace libtorrent
|
||||||
(*m_logger) << time_now_string()
|
(*m_logger) << time_now_string()
|
||||||
<< " ==> HAVE_ALL\n";
|
<< " ==> HAVE_ALL\n";
|
||||||
#endif
|
#endif
|
||||||
char buf[] = {0,0,0,1, msg_have_all};
|
char msg[] = {0,0,0,1, msg_have_all};
|
||||||
send_buffer(buf, buf + sizeof(buf));
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_have_none()
|
void bt_peer_connection::write_have_none()
|
||||||
|
@ -285,8 +283,8 @@ namespace libtorrent
|
||||||
(*m_logger) << time_now_string()
|
(*m_logger) << time_now_string()
|
||||||
<< " ==> HAVE_NONE\n";
|
<< " ==> HAVE_NONE\n";
|
||||||
#endif
|
#endif
|
||||||
char buf[] = {0,0,0,1, msg_have_none};
|
char msg[] = {0,0,0,1, msg_have_none};
|
||||||
send_buffer(buf, buf + sizeof(buf));
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_reject_request(peer_request const& r)
|
void bt_peer_connection::write_reject_request(peer_request const& r)
|
||||||
|
@ -296,22 +294,12 @@ namespace libtorrent
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
assert(associated_torrent().lock()->valid_metadata());
|
assert(associated_torrent().lock()->valid_metadata());
|
||||||
|
|
||||||
char buf[] = {0,0,0,13, msg_reject_request};
|
char msg[] = {0,0,0,13, msg_reject_request,0,0,0,0, 0,0,0,0, 0,0,0,0};
|
||||||
|
char* ptr = msg + 5;
|
||||||
buffer::interval i = allocate_send_buffer(17);
|
detail::write_int32(r.piece, ptr); // index
|
||||||
|
detail::write_int32(r.start, ptr); // begin
|
||||||
std::copy(buf, buf + 5, i.begin);
|
detail::write_int32(r.length, ptr); // length
|
||||||
i.begin += 5;
|
send_buffer(msg, sizeof(msg));
|
||||||
|
|
||||||
// index
|
|
||||||
detail::write_int32(r.piece, i.begin);
|
|
||||||
// begin
|
|
||||||
detail::write_int32(r.start, i.begin);
|
|
||||||
// length
|
|
||||||
detail::write_int32(r.length, i.begin);
|
|
||||||
assert(i.begin == i.end);
|
|
||||||
|
|
||||||
setup_send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_allow_fast(int piece)
|
void bt_peer_connection::write_allow_fast(int piece)
|
||||||
|
@ -321,11 +309,10 @@ namespace libtorrent
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
assert(associated_torrent().lock()->valid_metadata());
|
assert(associated_torrent().lock()->valid_metadata());
|
||||||
|
|
||||||
char buf[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0};
|
char msg[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0};
|
||||||
|
char* ptr = msg + 5;
|
||||||
char* ptr = buf + 5;
|
|
||||||
detail::write_int32(piece, ptr);
|
detail::write_int32(piece, ptr);
|
||||||
send_buffer(buf, buf + sizeof(buf));
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::get_specific_peer_info(peer_info& p) const
|
void bt_peer_connection::get_specific_peer_info(peer_info& p) const
|
||||||
|
@ -556,8 +543,8 @@ namespace libtorrent
|
||||||
assert(secret);
|
assert(secret);
|
||||||
|
|
||||||
hasher h;
|
hasher h;
|
||||||
const char keyA[] = "keyA";
|
static const char keyA[] = "keyA";
|
||||||
const char keyB[] = "keyB";
|
static const char keyB[] = "keyB";
|
||||||
|
|
||||||
// encryption rc4 longkeys
|
// encryption rc4 longkeys
|
||||||
// outgoing connection : hash ('keyA',S,SKEY)
|
// outgoing connection : hash ('keyA',S,SKEY)
|
||||||
|
@ -587,17 +574,16 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::send_buffer(char* begin, char* end)
|
void bt_peer_connection::send_buffer(char* buf, int size)
|
||||||
{
|
{
|
||||||
assert (begin);
|
assert(buf);
|
||||||
assert (end);
|
assert(size > 0);
|
||||||
assert (end > begin);
|
assert(!m_rc4_encrypted || m_encrypted);
|
||||||
assert (!m_rc4_encrypted || m_encrypted);
|
|
||||||
|
|
||||||
if (m_rc4_encrypted)
|
if (m_rc4_encrypted)
|
||||||
m_RC4_handler->encrypt(begin, end - begin);
|
m_RC4_handler->encrypt(buf, size);
|
||||||
|
|
||||||
peer_connection::send_buffer(begin, end);
|
peer_connection::send_buffer(buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer::interval bt_peer_connection::allocate_send_buffer(int size)
|
buffer::interval bt_peer_connection::allocate_send_buffer(int size)
|
||||||
|
@ -606,6 +592,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_rc4_encrypted)
|
if (m_rc4_encrypted)
|
||||||
{
|
{
|
||||||
|
assert(m_enc_send_buffer.left() == 0);
|
||||||
m_enc_send_buffer = peer_connection::allocate_send_buffer(size);
|
m_enc_send_buffer = peer_connection::allocate_send_buffer(size);
|
||||||
return m_enc_send_buffer;
|
return m_enc_send_buffer;
|
||||||
}
|
}
|
||||||
|
@ -620,24 +607,24 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
assert(!m_rc4_encrypted || m_encrypted);
|
assert(!m_rc4_encrypted || m_encrypted);
|
||||||
|
|
||||||
if (m_rc4_encrypted)
|
if (m_rc4_encrypted && m_enc_send_buffer.left())
|
||||||
{
|
{
|
||||||
assert (m_enc_send_buffer.begin);
|
assert(m_enc_send_buffer.begin);
|
||||||
assert (m_enc_send_buffer.end);
|
assert(m_enc_send_buffer.end);
|
||||||
assert (m_enc_send_buffer.left() > 0);
|
|
||||||
|
|
||||||
m_RC4_handler->encrypt (m_enc_send_buffer.begin, m_enc_send_buffer.left());
|
m_RC4_handler->encrypt(m_enc_send_buffer.begin, m_enc_send_buffer.left());
|
||||||
|
m_enc_send_buffer.end = m_enc_send_buffer.begin;
|
||||||
}
|
}
|
||||||
peer_connection::setup_send();
|
peer_connection::setup_send();
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_peer_connection::get_syncoffset(char const* src, int src_size,
|
int bt_peer_connection::get_syncoffset(char const* src, int src_size,
|
||||||
char const* target, int target_size) const
|
char const* target, int target_size) const
|
||||||
{
|
{
|
||||||
assert (target_size >= src_size);
|
assert(target_size >= src_size);
|
||||||
assert (src_size > 0);
|
assert(src_size > 0);
|
||||||
assert (src);
|
assert(src);
|
||||||
assert (target);
|
assert(target);
|
||||||
|
|
||||||
int traverse_limit = target_size - src_size;
|
int traverse_limit = target_size - src_size;
|
||||||
|
|
||||||
|
@ -1288,8 +1275,8 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
char buf[] = {0,0,0,0};
|
char msg[] = {0,0,0,0};
|
||||||
send_buffer(buf, buf + sizeof(buf));
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_cancel(peer_request const& r)
|
void bt_peer_connection::write_cancel(peer_request const& r)
|
||||||
|
@ -1299,22 +1286,12 @@ namespace libtorrent
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
assert(associated_torrent().lock()->valid_metadata());
|
assert(associated_torrent().lock()->valid_metadata());
|
||||||
|
|
||||||
char buf[] = {0,0,0,13, msg_cancel};
|
char msg[17] = {0,0,0,13, msg_cancel};
|
||||||
|
char* ptr = msg + 5;
|
||||||
buffer::interval i = allocate_send_buffer(17);
|
detail::write_int32(r.piece, ptr); // index
|
||||||
|
detail::write_int32(r.start, ptr); // begin
|
||||||
std::copy(buf, buf + 5, i.begin);
|
detail::write_int32(r.length, ptr); // length
|
||||||
i.begin += 5;
|
send_buffer(msg, sizeof(msg));
|
||||||
|
|
||||||
// index
|
|
||||||
detail::write_int32(r.piece, i.begin);
|
|
||||||
// begin
|
|
||||||
detail::write_int32(r.start, i.begin);
|
|
||||||
// length
|
|
||||||
detail::write_int32(r.length, i.begin);
|
|
||||||
assert(i.begin == i.end);
|
|
||||||
|
|
||||||
setup_send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_request(peer_request const& r)
|
void bt_peer_connection::write_request(peer_request const& r)
|
||||||
|
@ -1324,22 +1301,13 @@ namespace libtorrent
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
assert(associated_torrent().lock()->valid_metadata());
|
assert(associated_torrent().lock()->valid_metadata());
|
||||||
|
|
||||||
char buf[] = {0,0,0,13, msg_request};
|
char msg[17] = {0,0,0,13, msg_request};
|
||||||
|
char* ptr = msg + 5;
|
||||||
|
|
||||||
buffer::interval i = allocate_send_buffer(17);
|
detail::write_int32(r.piece, ptr); // index
|
||||||
|
detail::write_int32(r.start, ptr); // begin
|
||||||
std::copy(buf, buf + 5, i.begin);
|
detail::write_int32(r.length, ptr); // length
|
||||||
i.begin += 5;
|
send_buffer(msg, sizeof(msg));
|
||||||
|
|
||||||
// index
|
|
||||||
detail::write_int32(r.piece, i.begin);
|
|
||||||
// begin
|
|
||||||
detail::write_int32(r.start, i.begin);
|
|
||||||
// length
|
|
||||||
detail::write_int32(r.length, i.begin);
|
|
||||||
assert(i.begin == i.end);
|
|
||||||
|
|
||||||
setup_send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_bitfield(std::vector<bool> const& bitfield)
|
void bt_peer_connection::write_bitfield(std::vector<bool> const& bitfield)
|
||||||
|
@ -1526,7 +1494,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (is_choked()) return;
|
if (is_choked()) return;
|
||||||
char msg[] = {0,0,0,1,msg_choke};
|
char msg[] = {0,0,0,1,msg_choke};
|
||||||
send_buffer(msg, msg + sizeof(msg));
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_unchoke()
|
void bt_peer_connection::write_unchoke()
|
||||||
|
@ -1536,7 +1504,7 @@ namespace libtorrent
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
char msg[] = {0,0,0,1,msg_unchoke};
|
char msg[] = {0,0,0,1,msg_unchoke};
|
||||||
send_buffer(msg, msg + sizeof(msg));
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_interested()
|
void bt_peer_connection::write_interested()
|
||||||
|
@ -1546,7 +1514,7 @@ namespace libtorrent
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
char msg[] = {0,0,0,1,msg_interested};
|
char msg[] = {0,0,0,1,msg_interested};
|
||||||
send_buffer(msg, msg + sizeof(msg));
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_not_interested()
|
void bt_peer_connection::write_not_interested()
|
||||||
|
@ -1556,7 +1524,7 @@ namespace libtorrent
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
char msg[] = {0,0,0,1,msg_not_interested};
|
char msg[] = {0,0,0,1,msg_not_interested};
|
||||||
send_buffer(msg, msg + sizeof(msg));
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_have(int index)
|
void bt_peer_connection::write_have(int index)
|
||||||
|
@ -1567,34 +1535,39 @@ namespace libtorrent
|
||||||
assert(index < associated_torrent().lock()->torrent_file().num_pieces());
|
assert(index < associated_torrent().lock()->torrent_file().num_pieces());
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
const int packet_size = 9;
|
char msg[] = {0,0,0,5,msg_have,0,0,0,0};
|
||||||
char msg[packet_size] = {0,0,0,5,msg_have};
|
|
||||||
char* ptr = msg + 5;
|
char* ptr = msg + 5;
|
||||||
detail::write_int32(index, ptr);
|
detail::write_int32(index, ptr);
|
||||||
send_buffer(msg, msg + packet_size);
|
send_buffer(msg, sizeof(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_piece(peer_request const& r, char const* buffer)
|
void bt_peer_connection::write_piece(peer_request const& r, char* buffer)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
assert(m_sent_handshake && m_sent_bitfield);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
const int packet_size = 4 + 5 + 4 + r.length;
|
|
||||||
|
|
||||||
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
assert(t);
|
assert(t);
|
||||||
|
|
||||||
buffer::interval i = allocate_send_buffer(packet_size);
|
char msg[4 + 1 + 4 + 4];
|
||||||
|
char* ptr = msg;
|
||||||
detail::write_int32(packet_size-4, i.begin);
|
assert(r.length <= 16 * 1024);
|
||||||
detail::write_uint8(msg_piece, i.begin);
|
detail::write_int32(r.length + 1 + 4 + 4, ptr);
|
||||||
detail::write_int32(r.piece, i.begin);
|
detail::write_uint8(msg_piece, ptr);
|
||||||
detail::write_int32(r.start, i.begin);
|
detail::write_int32(r.piece, ptr);
|
||||||
|
detail::write_int32(r.start, ptr);
|
||||||
|
send_buffer(msg, sizeof(msg));
|
||||||
|
|
||||||
|
append_send_buffer(buffer, r.length
|
||||||
|
, boost::bind(&session_impl::free_disk_buffer
|
||||||
|
, boost::ref(m_ses), _1));
|
||||||
|
|
||||||
|
/*
|
||||||
|
buffer::interval i = allocate_send_buffer(r.length);
|
||||||
std::memcpy(i.begin, buffer, r.length);
|
std::memcpy(i.begin, buffer, r.length);
|
||||||
|
t->filesystem().free_buffer(buffer);
|
||||||
assert(i.begin + r.length == i.end);
|
*/
|
||||||
|
|
||||||
m_payloads.push_back(range(send_buffer_size() - r.length, r.length));
|
m_payloads.push_back(range(send_buffer_size() - r.length, r.length));
|
||||||
setup_send();
|
setup_send();
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,18 +37,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifdef TORRENT_DISK_STATS
|
#ifdef TORRENT_DISK_STATS
|
||||||
|
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
std::string log_time()
|
|
||||||
{
|
|
||||||
using namespace libtorrent;
|
|
||||||
static ptime start = time_now();
|
|
||||||
return boost::lexical_cast<std::string>(
|
|
||||||
total_milliseconds(time_now() - start));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -64,7 +52,9 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
, m_disk_io_thread(boost::ref(*this))
|
, m_disk_io_thread(boost::ref(*this))
|
||||||
{
|
{
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
m_allocations = 0;
|
||||||
|
#endif
|
||||||
#ifdef TORRENT_DISK_STATS
|
#ifdef TORRENT_DISK_STATS
|
||||||
m_log.open("disk_io_thread.log", std::ios::trunc);
|
m_log.open("disk_io_thread.log", std::ios::trunc);
|
||||||
#endif
|
#endif
|
||||||
|
@ -188,9 +178,21 @@ namespace libtorrent
|
||||||
char* disk_io_thread::allocate_buffer()
|
char* disk_io_thread::allocate_buffer()
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
boost::mutex::scoped_lock l(m_mutex);
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
++m_allocations;
|
||||||
|
#endif
|
||||||
return (char*)m_pool.ordered_malloc();
|
return (char*)m_pool.ordered_malloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void disk_io_thread::free_buffer(char* buf)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock l(m_mutex);
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
--m_allocations;
|
||||||
|
#endif
|
||||||
|
m_pool.ordered_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
void disk_io_thread::operator()()
|
void disk_io_thread::operator()()
|
||||||
{
|
{
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -225,10 +227,14 @@ namespace libtorrent
|
||||||
#ifdef TORRENT_DISK_STATS
|
#ifdef TORRENT_DISK_STATS
|
||||||
m_log << log_time() << " read " << j.buffer_size << std::endl;
|
m_log << log_time() << " read " << j.buffer_size << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
free_buffer = false;
|
||||||
if (j.buffer == 0)
|
if (j.buffer == 0)
|
||||||
{
|
{
|
||||||
l.lock();
|
l.lock();
|
||||||
j.buffer = (char*)m_pool.ordered_malloc();
|
j.buffer = (char*)m_pool.ordered_malloc();
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
++m_allocations;
|
||||||
|
#endif
|
||||||
l.unlock();
|
l.unlock();
|
||||||
assert(j.buffer_size <= m_block_size);
|
assert(j.buffer_size <= m_block_size);
|
||||||
if (j.buffer == 0)
|
if (j.buffer == 0)
|
||||||
|
@ -238,10 +244,6 @@ namespace libtorrent
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
free_buffer = false;
|
|
||||||
}
|
|
||||||
ret = j.storage->read_impl(j.buffer, j.piece, j.offset
|
ret = j.storage->read_impl(j.buffer, j.piece, j.offset
|
||||||
, j.buffer_size);
|
, j.buffer_size);
|
||||||
|
|
||||||
|
@ -301,6 +303,9 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
l.lock();
|
l.lock();
|
||||||
m_pool.ordered_free(j.buffer);
|
m_pool.ordered_free(j.buffer);
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
--m_allocations;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,9 +81,7 @@ namespace libtorrent
|
||||||
, m_last_unchoke(min_time())
|
, m_last_unchoke(min_time())
|
||||||
, m_packet_size(0)
|
, m_packet_size(0)
|
||||||
, m_recv_pos(0)
|
, m_recv_pos(0)
|
||||||
, m_current_send_buffer(0)
|
|
||||||
, m_reading_bytes(0)
|
, m_reading_bytes(0)
|
||||||
, m_write_pos(0)
|
|
||||||
, m_last_receive(time_now())
|
, m_last_receive(time_now())
|
||||||
, m_last_sent(time_now())
|
, m_last_sent(time_now())
|
||||||
, m_socket(s)
|
, m_socket(s)
|
||||||
|
@ -161,9 +159,7 @@ namespace libtorrent
|
||||||
, m_last_unchoke(min_time())
|
, m_last_unchoke(min_time())
|
||||||
, m_packet_size(0)
|
, m_packet_size(0)
|
||||||
, m_recv_pos(0)
|
, m_recv_pos(0)
|
||||||
, m_current_send_buffer(0)
|
|
||||||
, m_reading_bytes(0)
|
, m_reading_bytes(0)
|
||||||
, m_write_pos(0)
|
|
||||||
, m_last_receive(time_now())
|
, m_last_receive(time_now())
|
||||||
, m_last_sent(time_now())
|
, m_last_sent(time_now())
|
||||||
, m_socket(s)
|
, m_socket(s)
|
||||||
|
@ -2082,8 +2078,7 @@ namespace libtorrent
|
||||||
p.remote_dl_rate = 0;
|
p.remote_dl_rate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.send_buffer_size = int(m_send_buffer[0].capacity()
|
p.send_buffer_size = m_send_buffer.capacity();
|
||||||
+ m_send_buffer[1].capacity());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void peer_connection::cut_receive_buffer(int size, int packet_size)
|
void peer_connection::cut_receive_buffer(int size, int packet_size)
|
||||||
|
@ -2386,8 +2381,7 @@ namespace libtorrent
|
||||||
shared_ptr<torrent> t = m_torrent.lock();
|
shared_ptr<torrent> t = m_torrent.lock();
|
||||||
|
|
||||||
if (m_bandwidth_limit[upload_channel].quota_left() == 0
|
if (m_bandwidth_limit[upload_channel].quota_left() == 0
|
||||||
&& (!m_send_buffer[m_current_send_buffer].empty()
|
&& !m_send_buffer.empty()
|
||||||
|| !m_send_buffer[(m_current_send_buffer + 1) & 1].empty())
|
|
||||||
&& !m_connecting
|
&& !m_connecting
|
||||||
&& t
|
&& t
|
||||||
&& !m_ignore_bandwidth_limits)
|
&& !m_ignore_bandwidth_limits)
|
||||||
|
@ -2415,32 +2409,21 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(!m_writing);
|
assert(!m_writing);
|
||||||
|
|
||||||
int sending_buffer = (m_current_send_buffer + 1) & 1;
|
|
||||||
if (m_send_buffer[sending_buffer].empty())
|
|
||||||
{
|
|
||||||
// this means we have to swap buffer, because there's no
|
|
||||||
// previous buffer we're still waiting for.
|
|
||||||
std::swap(m_current_send_buffer, sending_buffer);
|
|
||||||
m_write_pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send the actual buffer
|
// send the actual buffer
|
||||||
if (!m_send_buffer[sending_buffer].empty())
|
if (!m_send_buffer.empty())
|
||||||
{
|
{
|
||||||
int amount_to_send = (int)m_send_buffer[sending_buffer].size() - m_write_pos;
|
int amount_to_send = m_send_buffer.size();
|
||||||
int quota_left = m_bandwidth_limit[upload_channel].quota_left();
|
int quota_left = m_bandwidth_limit[upload_channel].quota_left();
|
||||||
if (!m_ignore_bandwidth_limits && amount_to_send > quota_left)
|
if (!m_ignore_bandwidth_limits && amount_to_send > quota_left)
|
||||||
amount_to_send = quota_left;
|
amount_to_send = quota_left;
|
||||||
|
|
||||||
assert(amount_to_send > 0);
|
assert(amount_to_send > 0);
|
||||||
|
|
||||||
assert(m_write_pos < (int)m_send_buffer[sending_buffer].size());
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << "async_write " << amount_to_send << " bytes\n";
|
(*m_logger) << "async_write " << amount_to_send << " bytes\n";
|
||||||
#endif
|
#endif
|
||||||
m_socket->async_write_some(asio::buffer(
|
std::list<asio::const_buffer> const& vec = m_send_buffer.build_iovec(amount_to_send);
|
||||||
&m_send_buffer[sending_buffer][m_write_pos], amount_to_send)
|
m_socket->async_write_some(vec, bind(&peer_connection::on_send_data, self(), _1, _2));
|
||||||
, bind(&peer_connection::on_send_data, self(), _1, _2));
|
|
||||||
|
|
||||||
m_writing = true;
|
m_writing = true;
|
||||||
}
|
}
|
||||||
|
@ -2511,10 +2494,32 @@ namespace libtorrent
|
||||||
m_recv_buffer.resize(m_packet_size);
|
m_recv_buffer.resize(m_packet_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void peer_connection::send_buffer(char const* begin, char const* end)
|
void peer_connection::send_buffer(char const* buf, int size)
|
||||||
{
|
{
|
||||||
buffer& buf = m_send_buffer[m_current_send_buffer];
|
int free_space = m_send_buffer.space_in_last_buffer();
|
||||||
buf.insert(buf.end(), begin, end);
|
if (free_space > size) free_space = size;
|
||||||
|
if (free_space > 0)
|
||||||
|
{
|
||||||
|
m_send_buffer.append(buf, free_space);
|
||||||
|
size -= free_space;
|
||||||
|
buf += free_space;
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
m_ses.m_buffer_usage_logger << log_time() << " send_buffer: "
|
||||||
|
<< free_space << std::endl;
|
||||||
|
m_ses.log_buffer_usage();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (size <= 0) return;
|
||||||
|
|
||||||
|
std::pair<char*, int> buffer = m_ses.allocate_buffer(size);
|
||||||
|
assert(buffer.second >= size);
|
||||||
|
std::memcpy(buffer.first, buf, size);
|
||||||
|
m_send_buffer.append_buffer(buffer.first, buffer.second, size
|
||||||
|
, bind(&session_impl::free_buffer, boost::ref(m_ses), _1, buffer.second));
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
m_ses.m_buffer_usage_logger << log_time() << " send_buffer_alloc: " << size << std::endl;
|
||||||
|
m_ses.log_buffer_usage();
|
||||||
|
#endif
|
||||||
setup_send();
|
setup_send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2522,10 +2527,29 @@ namespace libtorrent
|
||||||
// return value is destructed
|
// return value is destructed
|
||||||
buffer::interval peer_connection::allocate_send_buffer(int size)
|
buffer::interval peer_connection::allocate_send_buffer(int size)
|
||||||
{
|
{
|
||||||
buffer& buf = m_send_buffer[m_current_send_buffer];
|
char* insert = m_send_buffer.allocate_appendix(size);
|
||||||
buf.resize(buf.size() + size);
|
if (insert == 0)
|
||||||
buffer::interval ret(&buf[0] + buf.size() - size, &buf[0] + buf.size());
|
{
|
||||||
return ret;
|
std::pair<char*, int> buffer = m_ses.allocate_buffer(size);
|
||||||
|
assert(buffer.second >= size);
|
||||||
|
m_send_buffer.append_buffer(buffer.first, buffer.second, size
|
||||||
|
, bind(&session_impl::free_buffer, boost::ref(m_ses), _1, buffer.second));
|
||||||
|
buffer::interval ret(buffer.first, buffer.first + size);
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
m_ses.m_buffer_usage_logger << log_time() << " allocate_buffer_alloc: " << size << std::endl;
|
||||||
|
m_ses.log_buffer_usage();
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
m_ses.m_buffer_usage_logger << log_time() << " allocate_buffer: " << size << std::endl;
|
||||||
|
m_ses.log_buffer_usage();
|
||||||
|
#endif
|
||||||
|
buffer::interval ret(insert, insert + size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
@ -2647,8 +2671,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// if we have requests or pending data to be sent or announcements to be made
|
// if we have requests or pending data to be sent or announcements to be made
|
||||||
// we want to send data
|
// we want to send data
|
||||||
return (!m_send_buffer[m_current_send_buffer].empty()
|
return !m_send_buffer.empty()
|
||||||
|| !m_send_buffer[(m_current_send_buffer + 1) & 1].empty())
|
|
||||||
&& (m_bandwidth_limit[upload_channel].quota_left() > 0
|
&& (m_bandwidth_limit[upload_channel].quota_left() > 0
|
||||||
|| m_ignore_bandwidth_limits)
|
|| m_ignore_bandwidth_limits)
|
||||||
&& !m_connecting;
|
&& !m_connecting;
|
||||||
|
@ -2763,6 +2786,9 @@ namespace libtorrent
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
assert(m_writing);
|
assert(m_writing);
|
||||||
|
|
||||||
|
m_send_buffer.pop_front(bytes_transferred);
|
||||||
|
|
||||||
m_writing = false;
|
m_writing = false;
|
||||||
|
|
||||||
if (!m_ignore_bandwidth_limits)
|
if (!m_ignore_bandwidth_limits)
|
||||||
|
@ -2772,9 +2798,6 @@ namespace libtorrent
|
||||||
(*m_logger) << "wrote " << bytes_transferred << " bytes\n";
|
(*m_logger) << "wrote " << bytes_transferred << " bytes\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_write_pos += bytes_transferred;
|
|
||||||
|
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
@ -2787,34 +2810,11 @@ namespace libtorrent
|
||||||
assert(!m_connecting);
|
assert(!m_connecting);
|
||||||
assert(bytes_transferred > 0);
|
assert(bytes_transferred > 0);
|
||||||
|
|
||||||
int sending_buffer = (m_current_send_buffer + 1) & 1;
|
|
||||||
|
|
||||||
assert(int(m_send_buffer[sending_buffer].size()) >= m_write_pos);
|
|
||||||
if (int(m_send_buffer[sending_buffer].size()) == m_write_pos)
|
|
||||||
{
|
|
||||||
m_send_buffer[sending_buffer].clear();
|
|
||||||
m_write_pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_last_sent = time_now();
|
m_last_sent = time_now();
|
||||||
|
|
||||||
on_sent(error, bytes_transferred);
|
on_sent(error, bytes_transferred);
|
||||||
fill_send_buffer();
|
fill_send_buffer();
|
||||||
|
|
||||||
if (m_choked)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 2; ++i)
|
|
||||||
{
|
|
||||||
if (int(m_send_buffer[i].size()) < 64
|
|
||||||
&& int(m_send_buffer[i].capacity()) > 128)
|
|
||||||
{
|
|
||||||
buffer tmp(m_send_buffer[i]);
|
|
||||||
tmp.swap(m_send_buffer[i]);
|
|
||||||
assert(m_send_buffer[i].capacity() == m_send_buffer[i].size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_send();
|
setup_send();
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
@ -2876,8 +2876,6 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
assert(m_write_pos <= int(m_send_buffer[
|
|
||||||
(m_current_send_buffer + 1) & 1].size()));
|
|
||||||
|
|
||||||
// extremely expensive invariant check
|
// extremely expensive invariant check
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1426,16 +1426,16 @@ namespace libtorrent
|
||||||
int nonempty_connections = 0;
|
int nonempty_connections = 0;
|
||||||
|
|
||||||
std::set<address> unique_test;
|
std::set<address> unique_test;
|
||||||
std::set<tcp::endpoint> unique_test2;
|
// std::set<tcp::endpoint> unique_test2;
|
||||||
for (const_iterator i = m_peers.begin();
|
for (const_iterator i = m_peers.begin();
|
||||||
i != m_peers.end(); ++i)
|
i != m_peers.end(); ++i)
|
||||||
{
|
{
|
||||||
peer const& p = *i;
|
peer const& p = *i;
|
||||||
if (!m_torrent->settings().allow_multiple_connections_per_ip)
|
// if (!m_torrent->settings().allow_multiple_connections_per_ip)
|
||||||
assert(unique_test.find(p.ip.address()) == unique_test.end());
|
// assert(unique_test.find(p.ip.address()) == unique_test.end());
|
||||||
assert(unique_test2.find(p.ip) == unique_test2.end());
|
// assert(unique_test2.find(p.ip) == unique_test2.end());
|
||||||
unique_test.insert(p.ip.address());
|
// unique_test.insert(p.ip.address());
|
||||||
unique_test2.insert(p.ip);
|
// unique_test2.insert(p.ip);
|
||||||
++total_connections;
|
++total_connections;
|
||||||
if (!p.connection)
|
if (!p.connection)
|
||||||
{
|
{
|
||||||
|
|
|
@ -507,7 +507,8 @@ namespace detail
|
||||||
std::pair<int, int> listen_port_range
|
std::pair<int, int> listen_port_range
|
||||||
, fingerprint const& cl_fprint
|
, fingerprint const& cl_fprint
|
||||||
, char const* listen_interface)
|
, char const* listen_interface)
|
||||||
: m_strand(m_io_service)
|
: m_send_buffers(send_buffer_size)
|
||||||
|
, m_strand(m_io_service)
|
||||||
, m_files(40)
|
, m_files(40)
|
||||||
, m_half_open(m_io_service)
|
, m_half_open(m_io_service)
|
||||||
, m_download_channel(m_io_service, peer_connection::download_channel)
|
, m_download_channel(m_io_service, peer_connection::download_channel)
|
||||||
|
@ -546,7 +547,7 @@ namespace detail
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TORRENT_STATS
|
#ifdef TORRENT_STATS
|
||||||
m_stats_logger.open("session_stats.log");
|
m_stats_logger.open("session_stats.log", std::ios::trunc);
|
||||||
m_stats_logger <<
|
m_stats_logger <<
|
||||||
"1. second\n"
|
"1. second\n"
|
||||||
"2. upload rate\n"
|
"2. upload rate\n"
|
||||||
|
@ -555,7 +556,9 @@ namespace detail
|
||||||
"5. seeding torrents\n"
|
"5. seeding torrents\n"
|
||||||
"6. peers\n"
|
"6. peers\n"
|
||||||
"7. connecting peers\n"
|
"7. connecting peers\n"
|
||||||
|
"8. disk block buffers\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
m_buffer_usage_logger.open("buffer_stats.log", std::ios::trunc);
|
||||||
m_second_counter = 0;
|
m_second_counter = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -999,7 +1002,8 @@ namespace detail
|
||||||
{
|
{
|
||||||
session_impl::mutex_t::scoped_lock l(m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_mutex);
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
// too expensive
|
||||||
|
// INVARIANT_CHECK;
|
||||||
|
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
|
@ -1031,7 +1035,7 @@ namespace detail
|
||||||
else
|
else
|
||||||
++downloading_torrents;
|
++downloading_torrents;
|
||||||
}
|
}
|
||||||
int num_connections = 0;
|
int num_complete_connections = 0;
|
||||||
int num_half_open = 0;
|
int num_half_open = 0;
|
||||||
for (connection_map::iterator i = m_connections.begin()
|
for (connection_map::iterator i = m_connections.begin()
|
||||||
, end(m_connections.end()); i != end; ++i)
|
, end(m_connections.end()); i != end; ++i)
|
||||||
|
@ -1039,7 +1043,7 @@ namespace detail
|
||||||
if (i->second->is_connecting())
|
if (i->second->is_connecting())
|
||||||
++num_half_open;
|
++num_half_open;
|
||||||
else
|
else
|
||||||
++num_connections;
|
++num_complete_connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_stats_logger
|
m_stats_logger
|
||||||
|
@ -1048,8 +1052,9 @@ namespace detail
|
||||||
<< m_stat.download_rate() << "\t"
|
<< m_stat.download_rate() << "\t"
|
||||||
<< downloading_torrents << "\t"
|
<< downloading_torrents << "\t"
|
||||||
<< seeding_torrents << "\t"
|
<< seeding_torrents << "\t"
|
||||||
<< num_connections << "\t"
|
<< num_complete_connections << "\t"
|
||||||
<< num_half_open << "\t"
|
<< num_half_open << "\t"
|
||||||
|
<< m_disk_thread.disk_allocations() << "\t"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2259,6 +2264,35 @@ namespace detail
|
||||||
m_upnp.reset();
|
m_upnp.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void session_impl::free_disk_buffer(char* buf)
|
||||||
|
{
|
||||||
|
m_disk_thread.free_buffer(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<char*, int> session_impl::allocate_buffer(int size)
|
||||||
|
{
|
||||||
|
int num_buffers = (size + send_buffer_size - 1) / send_buffer_size;
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
m_buffer_allocations += num_buffers;
|
||||||
|
m_buffer_usage_logger << log_time() << " protocol_buffer: "
|
||||||
|
<< (m_buffer_allocations * send_buffer_size) << std::endl;
|
||||||
|
#endif
|
||||||
|
return std::make_pair((char*)m_send_buffers.ordered_malloc(num_buffers)
|
||||||
|
, num_buffers * send_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_impl::free_buffer(char* buf, int size)
|
||||||
|
{
|
||||||
|
assert(size % send_buffer_size == 0);
|
||||||
|
int num_buffers = size / send_buffer_size;
|
||||||
|
#ifdef TORRENT_STATS
|
||||||
|
m_buffer_allocations -= num_buffers;
|
||||||
|
assert(m_buffer_allocations >= 0);
|
||||||
|
m_buffer_usage_logger << log_time() << " protocol_buffer: "
|
||||||
|
<< (m_buffer_allocations * send_buffer_size) << std::endl;
|
||||||
|
#endif
|
||||||
|
m_send_buffers.ordered_free(buf, num_buffers);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
void session_impl::check_invariant() const
|
void session_impl::check_invariant() const
|
||||||
|
|
|
@ -1065,6 +1065,11 @@ namespace libtorrent
|
||||||
return m_storage->verify_resume_data(rd, error);
|
return m_storage->verify_resume_data(rd, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_manager::free_buffer(char* buf)
|
||||||
|
{
|
||||||
|
m_io_thread.free_buffer(buf);
|
||||||
|
}
|
||||||
|
|
||||||
void piece_manager::async_release_files(
|
void piece_manager::async_release_files(
|
||||||
boost::function<void(int, disk_io_job const&)> const& handler)
|
boost::function<void(int, disk_io_job const&)> const& handler)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1464,9 +1464,6 @@ namespace libtorrent
|
||||||
m_policy->connection_closed(*p);
|
m_policy->connection_closed(*p);
|
||||||
p->set_peer_info(0);
|
p->set_peer_info(0);
|
||||||
m_connections.erase(i);
|
m_connections.erase(i);
|
||||||
#ifndef NDEBUG
|
|
||||||
m_policy->check_invariant();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -297,7 +297,7 @@ namespace libtorrent
|
||||||
(*m_logger) << request << "\n";
|
(*m_logger) << request << "\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
send_buffer(request.c_str(), request.c_str() + request.size());
|
send_buffer(request.c_str(), request.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------
|
// --------------------------
|
||||||
|
|
|
@ -34,12 +34,16 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include "libtorrent/buffer.hpp"
|
#include "libtorrent/buffer.hpp"
|
||||||
|
#include "libtorrent/chained_buffer.hpp"
|
||||||
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
|
|
||||||
using libtorrent::buffer;
|
using libtorrent::buffer;
|
||||||
|
using libtorrent::chained_buffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
template<class T>
|
template<class T>
|
||||||
T const& min_(T const& x, T const& y)
|
T const& min_(T const& x, T const& y)
|
||||||
|
@ -113,7 +117,9 @@ void test_speed()
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int test_main()
|
// -- test buffer --
|
||||||
|
|
||||||
|
void test_buffer()
|
||||||
{
|
{
|
||||||
char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||||
|
|
||||||
|
@ -157,6 +163,160 @@ int test_main()
|
||||||
buffer().swap(b);
|
buffer().swap(b);
|
||||||
TEST_CHECK(b.capacity() == 0);
|
TEST_CHECK(b.capacity() == 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- test chained buffer --
|
||||||
|
|
||||||
|
std::set<char*> buffer_list;
|
||||||
|
|
||||||
|
void free_buffer(char* m)
|
||||||
|
{
|
||||||
|
std::set<char*>::iterator i = buffer_list.find(m);
|
||||||
|
TEST_CHECK(i != buffer_list.end());
|
||||||
|
|
||||||
|
buffer_list.erase(i);
|
||||||
|
std::free(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* allocate_buffer(int size)
|
||||||
|
{
|
||||||
|
char* mem = (char*)std::malloc(size);
|
||||||
|
buffer_list.insert(mem);
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
int copy_buffers(T const& b, char* target)
|
||||||
|
{
|
||||||
|
int copied = 0;
|
||||||
|
for (typename T::const_iterator i = b.begin()
|
||||||
|
, end(b.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
memcpy(target, asio::buffer_cast<char const*>(*i), asio::buffer_size(*i));
|
||||||
|
target += asio::buffer_size(*i);
|
||||||
|
copied += asio::buffer_size(*i);
|
||||||
|
}
|
||||||
|
return copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare_chained_buffer(chained_buffer& b, char const* mem, int size)
|
||||||
|
{
|
||||||
|
std::vector<char> flat(size);
|
||||||
|
std::list<asio::const_buffer> const& iovec2 = b.build_iovec(size);
|
||||||
|
int copied = copy_buffers(iovec2, &flat[0]);
|
||||||
|
TEST_CHECK(copied == size);
|
||||||
|
return std::memcmp(&flat[0], mem, size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_chained_buffer()
|
||||||
|
{
|
||||||
|
char data[] = "foobar";
|
||||||
|
{
|
||||||
|
chained_buffer b;
|
||||||
|
|
||||||
|
TEST_CHECK(b.empty());
|
||||||
|
TEST_CHECK(b.capacity() == 0);
|
||||||
|
TEST_CHECK(b.size() == 0);
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 0);
|
||||||
|
TEST_CHECK(buffer_list.empty());
|
||||||
|
|
||||||
|
char* b1 = allocate_buffer(512);
|
||||||
|
std::memcpy(b1, data, 6);
|
||||||
|
b.append_buffer(b1, 512, 6, (void(*)(char*))&free_buffer);
|
||||||
|
TEST_CHECK(buffer_list.size() == 1);
|
||||||
|
|
||||||
|
TEST_CHECK(b.capacity() == 512);
|
||||||
|
TEST_CHECK(b.size() == 6);
|
||||||
|
TEST_CHECK(!b.empty());
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 512 - 6);
|
||||||
|
|
||||||
|
b.pop_front(3);
|
||||||
|
|
||||||
|
TEST_CHECK(b.capacity() == 512);
|
||||||
|
TEST_CHECK(b.size() == 3);
|
||||||
|
TEST_CHECK(!b.empty());
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 512 - 6);
|
||||||
|
|
||||||
|
bool ret = b.append(data, 6);
|
||||||
|
|
||||||
|
TEST_CHECK(ret == true);
|
||||||
|
TEST_CHECK(b.capacity() == 512);
|
||||||
|
TEST_CHECK(b.size() == 9);
|
||||||
|
TEST_CHECK(!b.empty());
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 512 - 12);
|
||||||
|
|
||||||
|
ret = b.append(data, 1024);
|
||||||
|
|
||||||
|
TEST_CHECK(ret == false);
|
||||||
|
|
||||||
|
char* b2 = allocate_buffer(512);
|
||||||
|
std::memcpy(b2, data, 6);
|
||||||
|
b.append_buffer(b2, 512, 6, (void(*)(char*))&free_buffer);
|
||||||
|
TEST_CHECK(buffer_list.size() == 2);
|
||||||
|
|
||||||
|
char* b3 = allocate_buffer(512);
|
||||||
|
std::memcpy(b3, data, 6);
|
||||||
|
b.append_buffer(b3, 512, 6, (void(*)(char*))&free_buffer);
|
||||||
|
TEST_CHECK(buffer_list.size() == 3);
|
||||||
|
|
||||||
|
TEST_CHECK(b.capacity() == 512 * 3);
|
||||||
|
TEST_CHECK(b.size() == 21);
|
||||||
|
TEST_CHECK(!b.empty());
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 512 - 6);
|
||||||
|
|
||||||
|
TEST_CHECK(compare_chained_buffer(b, "barfoobar", 9));
|
||||||
|
|
||||||
|
for (int i = 1; i < 21; ++i)
|
||||||
|
TEST_CHECK(compare_chained_buffer(b, "barfoobarfoobarfoobar", i));
|
||||||
|
|
||||||
|
b.pop_front(5 + 6);
|
||||||
|
|
||||||
|
TEST_CHECK(buffer_list.size() == 2);
|
||||||
|
TEST_CHECK(b.capacity() == 512 * 2);
|
||||||
|
TEST_CHECK(b.size() == 10);
|
||||||
|
TEST_CHECK(!b.empty());
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 512 - 6);
|
||||||
|
|
||||||
|
char const* str = "obarfooba";
|
||||||
|
TEST_CHECK(compare_chained_buffer(b, str, 9));
|
||||||
|
|
||||||
|
for (int i = 0; i < 9; ++i)
|
||||||
|
{
|
||||||
|
b.pop_front(1);
|
||||||
|
++str;
|
||||||
|
TEST_CHECK(compare_chained_buffer(b, str, 8 - i));
|
||||||
|
TEST_CHECK(b.size() == 9 - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* b4 = allocate_buffer(20);
|
||||||
|
std::memcpy(b4, data, 6);
|
||||||
|
std::memcpy(b4 + 6, data, 6);
|
||||||
|
b.append_buffer(b4, 20, 12, (void(*)(char*))&free_buffer);
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 8);
|
||||||
|
|
||||||
|
ret = b.append(data, 6);
|
||||||
|
TEST_CHECK(ret == true);
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 2);
|
||||||
|
std::cout << b.space_in_last_buffer() << std::endl;
|
||||||
|
ret = b.append(data, 2);
|
||||||
|
TEST_CHECK(ret == true);
|
||||||
|
TEST_CHECK(b.space_in_last_buffer() == 0);
|
||||||
|
std::cout << b.space_in_last_buffer() << std::endl;
|
||||||
|
|
||||||
|
char* b5 = allocate_buffer(20);
|
||||||
|
std::memcpy(b4, data, 6);
|
||||||
|
b.append_buffer(b5, 20, 6, (void(*)(char*))&free_buffer);
|
||||||
|
|
||||||
|
b.pop_front(22);
|
||||||
|
TEST_CHECK(b.size() == 5);
|
||||||
|
}
|
||||||
|
TEST_CHECK(buffer_list.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_main()
|
||||||
|
{
|
||||||
|
test_buffer();
|
||||||
|
test_chained_buffer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue