optimized heap allocations in piece_picker. #42
This commit is contained in:
parent
25d38ff1fc
commit
6dcca9250b
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue