optimized heap allocations in piece_picker. #42

This commit is contained in:
Arvid Norberg 2007-05-09 00:49:13 +00:00
parent 25d38ff1fc
commit 6dcca9250b
5 changed files with 68 additions and 26 deletions

View File

@ -88,8 +88,6 @@ namespace libtorrent
{
public:
enum { max_blocks_per_piece = 256 };
struct block_info
{
block_info(): num_downloads(0), requested(0), finished(0) {}
@ -117,7 +115,9 @@ namespace libtorrent
// the index of the piece
int index;
// info about each block
block_info info[max_blocks_per_piece];
// this is a pointer into the m_block_info
// vector owned by the piece_picker
block_info* info;
boost::uint16_t finished;
boost::uint16_t requested;
};
@ -339,6 +339,9 @@ namespace libtorrent
, int num_blocks, bool prefer_whole_pieces
, tcp::endpoint peer, piece_state_t speed) const;
downloading_piece& add_download_piece();
void erase_download_piece(std::vector<downloading_piece>::iterator i);
// this vector contains all pieces we don't have.
// in the first entry (index 0) is a vector of all pieces
// that no peer have, the vector at index 1 contains
@ -363,6 +366,15 @@ namespace libtorrent
// is being downloaded
std::vector<downloading_piece> m_downloads;
// this holds the information of the
// blocks in partially downloaded pieces.
// the first m_blocks_per_piece entries
// in the vector belongs to the first
// entry in m_downloads, the second
// m_blocks_per_piece entries to the
// second entry in m_downloads and so on.
std::vector<block_info> m_block_info;
int m_blocks_per_piece;
int m_blocks_in_last_piece;

View File

@ -204,7 +204,7 @@ namespace libtorrent
struct TORRENT_EXPORT partial_piece_info
{
enum { max_blocks_per_piece = piece_picker::max_blocks_per_piece };
enum { max_blocks_per_piece = 256 };
int piece_index;
int blocks_in_piece;
std::bitset<max_blocks_per_piece> requested_blocks;

View File

@ -76,9 +76,7 @@ namespace libtorrent
m_blocks_in_last_piece = total_num_blocks % blocks_per_piece;
if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = blocks_per_piece;
assert(m_blocks_per_piece <= max_blocks_per_piece);
assert(m_blocks_in_last_piece <= m_blocks_per_piece);
assert(m_blocks_in_last_piece <= max_blocks_per_piece);
// allocate the piece_map to cover all pieces
// and make them invalid (as if though we already had every piece)
@ -191,6 +189,51 @@ namespace libtorrent
}
}
piece_picker::downloading_piece& piece_picker::add_download_piece()
{
int num_downloads = m_downloads.size();
int block_index = num_downloads * m_blocks_per_piece;
if (int(m_block_info.size()) < block_index + m_blocks_per_piece)
{
m_block_info.resize(block_index + m_blocks_per_piece);
if (!m_downloads.empty() && &m_block_info[0] != m_downloads.front().info)
{
// this means the memory was reallocated, update the pointers
for (int i = 0; i < int(m_downloads.size()); ++i)
m_downloads[i].info = &m_block_info[i * m_blocks_per_piece];
}
}
m_downloads.push_back(downloading_piece());
downloading_piece& ret = m_downloads.back();
ret.info = &m_block_info[block_index];
for (int i = 0; i < m_blocks_per_piece; ++i)
{
ret.info[i].num_downloads = 0;
ret.info[i].requested = 0;
ret.info[i].finished = 0;
ret.info[i].peer = tcp::endpoint();
}
return ret;
}
void piece_picker::erase_download_piece(std::vector<downloading_piece>::iterator i)
{
if (i != m_downloads.end() - 1)
{
int remove_index = i - m_downloads.begin();
int last_index = m_downloads.size() - 1;
assert(remove_index < last_index);
assert(int(m_block_info.size()) >= last_index * m_blocks_per_piece + m_blocks_per_piece);
std::copy(m_block_info.begin() + (last_index * m_blocks_per_piece)
, m_block_info.begin() + (last_index * m_blocks_per_piece + m_blocks_per_piece)
, m_block_info.begin() + (remove_index * m_blocks_per_piece));
m_downloads[remove_index] = m_downloads[last_index];
m_downloads[remove_index].info = &m_block_info[remove_index * m_blocks_per_piece];
}
m_downloads.pop_back();
}
#ifndef NDEBUG
void piece_picker::check_invariant(const torrent* t) const
@ -557,7 +600,7 @@ namespace libtorrent
m_downloads.end(),
has_index(index));
assert(i != m_downloads.end());
m_downloads.erase(i);
erase_download_piece(i);
piece_pos& p = m_piece_map[index];
int prev_priority = p.priority(m_sequenced_download_threshold);
@ -841,7 +884,7 @@ namespace libtorrent
, m_downloads.end()
, has_index(index));
assert(i != m_downloads.end());
m_downloads.erase(i);
erase_download_piece(i);
p.downloading = 0;
assert(std::find_if(m_downloads.begin(), m_downloads.end()
@ -1168,7 +1211,6 @@ namespace libtorrent
assert(block.piece_index >= 0);
assert(block.block_index >= 0);
assert(block.piece_index < (int)m_piece_map.size());
assert(block.block_index < (int)max_blocks_per_piece);
if (m_piece_map[block.piece_index].downloading == 0) return false;
std::vector<downloading_piece>::const_iterator i
@ -1186,7 +1228,6 @@ namespace libtorrent
assert(block.piece_index >= 0);
assert(block.block_index >= 0);
assert(block.piece_index < (int)m_piece_map.size());
assert(block.block_index < (int)max_blocks_per_piece);
if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true;
if (m_piece_map[block.piece_index].downloading == 0) return false;
@ -1214,14 +1255,13 @@ namespace libtorrent
p.downloading = 1;
move(prio, p.index);
downloading_piece dp;
downloading_piece& dp = add_download_piece();
dp.state = state;
dp.index = block.piece_index;
block_info& info = dp.info[block.block_index];
info.requested = 1;
info.peer = peer;
++dp.requested;
m_downloads.push_back(dp);
}
else
{
@ -1255,7 +1295,7 @@ namespace libtorrent
if (prio > 0) move(prio, p.index);
else assert(p.priority(m_sequenced_download_threshold) == 0);
downloading_piece dp;
downloading_piece& dp = add_download_piece();
dp.state = none;
dp.index = block.piece_index;
block_info& info = dp.info[block.block_index];
@ -1264,7 +1304,6 @@ namespace libtorrent
++dp.requested;
++dp.finished;
dp.info[block.block_index].peer = peer;
m_downloads.push_back(dp);
}
else
{
@ -1311,7 +1350,6 @@ namespace libtorrent
if (i == m_downloads.end())
return boost::optional<tcp::endpoint>();
assert(block.block_index < max_blocks_per_piece);
assert(block.block_index >= 0);
if (i->info[block.block_index].requested == false
@ -1344,8 +1382,6 @@ namespace libtorrent
if (i->info[block.block_index].finished)
{
assert(i->info[block.block_index].requested);
assert(std::find_if(m_downloads.begin(), m_downloads.end()
, has_index(block.piece_index)) == m_downloads.end());
return;
}
@ -1363,7 +1399,7 @@ namespace libtorrent
// that's being downloaded, remove it from the list
if (i->requested == 0)
{
m_downloads.erase(i);
erase_download_piece(i);
piece_pos& p = m_piece_map[block.piece_index];
int prio = p.priority(m_sequenced_download_threshold);
p.downloading = 0;

View File

@ -105,12 +105,6 @@ namespace
return static_cast<int>(i.piece_length());
}
// if pieces are too large, adjust the block size
if (i.piece_length() / default_block_size > piece_picker::max_blocks_per_piece)
{
return static_cast<int>(i.piece_length() / piece_picker::max_blocks_per_piece);
}
// otherwise, go with the default
return default_block_size;
}

View File

@ -769,7 +769,8 @@ namespace libtorrent
{
partial_piece_info pi;
pi.piece_state = (partial_piece_info::state_t)i->state;
for (int j = 0; j < partial_piece_info::max_blocks_per_piece; ++j)
pi.blocks_in_piece = p.blocks_in_piece(i->index);
for (int j = 0; j < pi.blocks_in_piece; ++j)
{
pi.peer[j] = i->info[j].peer;
pi.num_downloads[j] = i->info[j].num_downloads;
@ -777,7 +778,6 @@ namespace libtorrent
pi.requested_blocks[j] = i->info[j].requested;
}
pi.piece_index = i->index;
pi.blocks_in_piece = p.blocks_in_piece(i->index);
queue.push_back(pi);
}
}