Random high CPU load using transmission 1.50

Discussion of Transmission that doesn't fit in the other categories
Post Reply
roobin
Posts: 6
Joined: Mon Feb 23, 2009 5:11 pm

Random high CPU load using transmission 1.50

Post by roobin »

This is mostly for the developers of transmission, probably I found what triggers it.
(You are doing a great job, thanks for this fine client!)

I am running transmission 1.50 (7887) on Arch linux, downloading one ~30G torrent with 4M pieces (means around 7000 pieces) and 16k blocks. There are 3-6 seeds and 10-40 leechers. Normal CPU load is 6-8%. Upload is limted. Download is not, because it has its own problems. (I will write another post later about it.)

At random times the CPU load climbs to 50%, 60%, 75% or 99% and stays there near constantly for minutes, sometimes for half an hour or hours. The upload drops to half, the download is hard to measure but I think it is dropping too.

Oprofile pointed to refillPulse and blockIteratorNext procedures in peer-mgr.c. Reviewing the code I found some fairly likely worst case scenario can occur. Let us suppose we have a downloading leecher who has small number of completed pieces and nothing important to us. In refillPulse, most probably this will be the last peer who remains in the peer list. Now we have to find something for it to download. What he has can be the "number 3000 piece" in our list. For every peace blockIteratorNext will build a list, cycling 256 times and refillPulse cycling 256 times again, to find that that piece is not good for this peer. Can be millions of wasted cycles.

As a proof of concept I inserted a line at the end of the refillPulse while cycle.
#
if( !handled ) blockIterator->blockIndex = blockIterator->blockCount;
#
I know that this is not a proper solution, but this skips the refillPulse cycles.

Yesturday the high CPU was triggered almost every time with around 50% load. So I tried the modified refillPulse and the CPU load dropped to 16%.

I hope this helps.
Jordan
Transmission Developer
Posts: 2312
Joined: Sat May 26, 2007 3:39 pm
Location: Titania's Room

Re: Random high CPU load using transmission 1.50

Post by Jordan »

Yes, you've hit the nail on the head. Many users have been hitting this same problem, and I've been reading over that code too.

Yesterday I tried hacking the code that way, and it does lower the CPU load. However that change would also mean that we're making worse use of that incomplete peer, because we exit refillPulse() before filling up its queue of blocks to request.

One tweak I'm thinking of is that when a block isn't handled, then in the block iterator we skip to the next piece immediately. That would still lower the CPU use, but try to make better use of the incomplete peer.

A better solution would be to build block iterators tailored to the individual peer, taking into account what pieces it has. This is a little tricky because building the iterators is expensive too (because of getPreferredPieces()) so that's the piece that I'm currently tinkering with to see if it can be made fast enough for per-peer invocation. Specifically, whether it's possible to use heuristics to make the initial piece list shorter even before we sort it in getPreferredPieces(). :)
Post Reply