(trunk, libT) #5199 'tr_sessionGetNextQueuedTorrent() can be faster' -- modify session.c's tr_sessionGetNextQueuedTorrents() and peer-mgr.c's getPeerCandidates() functions use the new tr_quickfindFirstK() utility"

This commit is contained in:
Jordan Lee 2012-12-28 20:10:03 +00:00
parent 25b8b60245
commit aa906ced75
3 changed files with 104 additions and 97 deletions

View File

@ -3590,24 +3590,36 @@ pumpAllPeers (tr_peerMgr * mgr)
}
}
static void
queuePulseForeach (void * vtor)
{
tr_torrent * tor = vtor;
tr_torrentStartNow (tor);
if (tor->queue_started_callback != NULL)
(*tor->queue_started_callback)(tor, tor->queue_started_user_data);
}
static void
queuePulse (tr_session * session, tr_direction dir)
{
assert (tr_isSession (session));
assert (tr_isDirection (dir));
assert (tr_isSession (session));
assert (tr_isDirection (dir));
if (tr_sessionGetQueueEnabled (session, dir))
if (tr_sessionGetQueueEnabled (session, dir))
{
int i;
const int n = tr_sessionCountQueueFreeSlots (session, dir);
for (i=0; i<n; i++) {
tr_torrent * tor = tr_sessionGetNextQueuedTorrent (session, dir);
if (tor != NULL) {
tr_torrentStartNow (tor);
if (tor->queue_started_callback != NULL)
(*tor->queue_started_callback)(tor, tor->queue_started_user_data);
}
}
tr_ptrArray torrents = TR_PTR_ARRAY_INIT;
tr_sessionGetNextQueuedTorrents (session,
dir,
tr_sessionCountQueueFreeSlots (session, dir),
&torrents);
tr_ptrArrayForeach (&torrents, queuePulseForeach);
tr_ptrArrayDestruct (&torrents, NULL);
}
}
@ -3877,79 +3889,33 @@ getPeerCandidateScore (const tr_torrent * tor, const struct peer_atom * atom, ui
return score;
}
#ifndef NDEBUG
static int
checkPartition (const struct peer_candidate * candidates, int left, int right, uint64_t pivotScore, int storeIndex)
comparePeerCandidates (const void * va, const void * vb)
{
int i;
int ret;
const struct peer_candidate * a = va;
const struct peer_candidate * b = vb;
assert (storeIndex >= left);
assert (storeIndex <= right);
assert (candidates[storeIndex].score == pivotScore);
if (a->score < b->score)
ret = -1;
else if (a->score > b->score)
ret = 1;
else
ret = 0;
for (i=left; i<storeIndex; ++i)
assert (candidates[i].score < pivotScore);
for (i=storeIndex+1; i<=right; ++i)
assert (candidates[i].score >= pivotScore);
return true;
}
#endif
/* Helper to selectPeerCandidates().
* Adapted from http://en.wikipedia.org/wiki/Selection_algorithm */
static int
partitionPeerCandidates (struct peer_candidate * candidates, int left, int right, int pivotIndex)
{
int i;
int storeIndex;
struct peer_candidate tmp;
const struct peer_candidate pivotValue = candidates[pivotIndex];
/* move pivot to end */
tmp = candidates[right];
candidates[right] = pivotValue;
candidates[pivotIndex] = tmp;
storeIndex = left;
for (i=left; i<=right; ++i)
{
if (candidates[i].score < pivotValue.score)
{
tmp = candidates[storeIndex];
candidates[storeIndex] = candidates[i];
candidates[i] = tmp;
storeIndex++;
}
}
/* move pivot to its final place */
tmp = candidates[right];
candidates[right] = candidates[storeIndex];
candidates[storeIndex] = tmp;
/* sanity check */
assert (checkPartition (candidates, left, right, pivotValue.score, storeIndex));
return storeIndex;
return ret;
}
/* Partial sorting -- selecting the k best candidates
Adapted from http://en.wikipedia.org/wiki/Selection_algorithm */
static void
selectPeerCandidates (struct peer_candidate * candidates, int left, int right, int k)
selectPeerCandidates (struct peer_candidate * candidates, int candidate_count, int select_count)
{
if (right > left)
{
const int pivotIndex = left + (right-left)/2;
int pivotNewIndex = partitionPeerCandidates (candidates, left, right, pivotIndex);
if (pivotNewIndex > left + k) /* new condition */
selectPeerCandidates (candidates, left, pivotNewIndex-1, k);
else if (pivotNewIndex < left + k)
selectPeerCandidates (candidates, pivotNewIndex+1, right, k+left-pivotNewIndex-1);
}
tr_quickfindFirstK (candidates,
candidate_count,
sizeof(struct peer_candidate),
comparePeerCandidates,
select_count);
}
#ifndef NDEBUG
@ -4042,7 +4008,7 @@ getPeerCandidates (tr_session * session, int * candidateCount, int max)
*candidateCount = walk - candidates;
if (walk != candidates)
selectPeerCandidates (candidates, 0, (walk-candidates)-1, max);
selectPeerCandidates (candidates, walk-candidates, max);
assert (checkBestScoresComeFirst (candidates, *candidateCount, max));

View File

@ -2713,33 +2713,74 @@ tr_sessionGetQueueStalledMinutes (const tr_session * session)
return session->queueStalledMinutes;
}
tr_torrent *
tr_sessionGetNextQueuedTorrent (tr_session * session, tr_direction direction)
struct TorrentAndPosition
{
tr_torrent * tor = NULL;
tr_torrent * best_tor = NULL;
int best_position = INT_MAX;
tr_torrent * tor;
int position;
};
assert (tr_isSession (session));
assert (tr_isDirection (direction));
/* higher positions come first */
static int
compareTorrentAndPositions (const void * va, const void * vb)
{
int ret;
const struct TorrentAndPosition * a = va;
const struct TorrentAndPosition * b = vb;
while ((tor = tr_torrentNext (session, tor)))
if (a->position > b->position)
ret = -1;
else if (a->position < b->position)
ret = 1;
else
ret = 0;
return ret;
}
void
tr_sessionGetNextQueuedTorrents (tr_session * session,
tr_direction direction,
size_t num_wanted,
tr_ptrArray * setme)
{
size_t i;
tr_torrent * tor;
struct TorrentAndPosition * candidates;
assert (tr_isSession (session));
assert (tr_isDirection (direction));
/* build an array of the candidates */
candidates = tr_new (struct TorrentAndPosition, session->torrentCount);
tor = NULL;
while ((tor = tr_torrentNext (session, tor)))
{
int position;
if (!tr_torrentIsQueued (tor))
continue;
if (!tr_torrentIsQueued (tor))
continue;
if (direction != tr_torrentGetQueueDirection (tor))
continue;
if (direction != tr_torrentGetQueueDirection (tor))
continue;
position = tr_torrentGetQueuePosition (tor);
if (best_position > position) {
best_position = position;
best_tor = tor;
}
candidates[i].tor = tor;
candidates[i].position = tr_torrentGetQueuePosition (tor);
++i;
}
return best_tor;
/* find the best n candidates */
if (num_wanted > i)
num_wanted = i;
else if (num_wanted < i)
tr_quickfindFirstK (candidates, i,
sizeof(struct TorrentAndPosition),
compareTorrentAndPositions, num_wanted);
/* add them to the return array */
for (i=0; i<num_wanted; ++i)
tr_ptrArrayAppend (setme, candidates[i].tor);
/* cleanup */
tr_free (candidates);
}
int

View File

@ -329,7 +329,7 @@ bool tr_sessionGetActiveSpeedLimit_Bps (const tr_session * session,
unsigned int * setme);
tr_torrent * tr_sessionGetNextQueuedSeed (tr_session * session);
tr_torrent * tr_sessionGetNextQueuedTorrent (tr_session * session, tr_direction);
void tr_sessionGetNextQueuedTorrents (tr_session * session, tr_direction, size_t n, tr_ptrArray * steme);
int tr_sessionCountQueueFreeSlots (tr_session * session, tr_direction);