Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Used thread local buffers to tame GC pressure caused by piece validation #184

Open
wants to merge 98 commits into
base: master
Choose a base branch
from

Conversation

bwzhou
Copy link
Contributor

@bwzhou bwzhou commented Sep 19, 2016

Piece validation allocates 2x memory for each piece received, which could cause frequent young gen GC's and premature old gen promotions. This memory pressure can be alleviated by using pre-allocated thread local buffers as the scratch pad for the validation. A byte array and a ByteBuffer are allocated for each PeerExchange.IncomingThread and released when the thread exits.

Before:
screenshot-heliosshell-0 1 28-snapshot - yourkit java profiler 2014 build 14114 - 64-bit-1

After:
screenshot-heliosshell-0 1 28-snapshot - yourkit java profiler 2014 build 14114 - 64-bit-2

pankdm and others added 30 commits April 10, 2013 12:37
…sage.parse

Order of the parameters to the HTTPAnnounceRequestMessage constructor was incorrect in the parse() method. Thanks to Dan Oxlade for reporting the problem.

Closes mpetazzoni#48.

Signed-off-by: Maxime Petazzoni <[email protected]>
Allow trackerless torrent files mpetazzoni#2

Signed-off-by: Maxime Petazzoni <[email protected]>
…h InboundThread and OutboundThread to a common ExchangeThread superclass.
Add ability to set upload/download rate limits.

Signed-off-by: Maxime Petazzoni <[email protected]>
Fix read when message size wasn't read in one step

Signed-off-by: Maxime Petazzoni <[email protected]>
BDecode support for negative integers

Signed-off-by: Maxime Petazzoni <[email protected]>
Fixes bug with selecting the announce client

A previous change introduced a bug in the selection
of the announce tier and client. Closes mpetazzoni#51.

Signed-off-by: Maxime Petazzoni <[email protected]>
Use maven-shade-plugin to produce executable jar

Signed-off-by: Maxime Petazzoni <[email protected]>
Update pom for compatibility with the maven-release-plugin

Signed-off-by: Maxime Petazzoni <[email protected]>
Clean up javadoc problems

Signed-off-by: Maxime Petazzoni <[email protected]>
Shell script updates for wider platform compatibility

Signed-off-by: Maxime Petazzoni <[email protected]>
Move entry-point main methods to separate package

Signed-off-by: Maxime Petazzoni <[email protected]>
mpetazzoni and others added 18 commits January 18, 2016 11:03
Fixed bitfield payload in bitfield message
Remove dependency on Apache comons-codec
…eerexchange

Allow immedidate shutdown of peerexchange by notifying out-going thread
This change prevents the modification of a storage file in case the
file is already complete and all pieces are available.
…ng-file-only-if-required

Change the length of an existing storage file only if required
In preparation of incoming 1.5 release, with the cli/core split.

Signed-off-by: Maxime Petazzoni <[email protected]>
The old implementation of byteArrayToHexString drops the byte array’s
leading zeros.
…tring

Fix byteArrayToHexString and add tests
Copy link
Owner

@mpetazzoni mpetazzoni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Interesting changes and nice profiling. I've never bothered to do any on this library so this is always helpful. I made a few comments.

@@ -412,6 +412,14 @@ public void save(OutputStream output) throws IOException {
return crypt.digest();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you call the other version of hash() from here instead?

public static byte[] hash(byte[] data) throws NoSuchAlgorithmException {
    return hash(data, 0, data.length);
}

* @throws IOException If the read can't be completed (I/O error, or EOF
* reached, which can happen if the piece is not complete).
*/
private void _read(long offset, ByteBuffer buffer) throws IOException {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't you call this method from the other _read() method with the newly allocated ByteBuffer?

this.length + ") !");
}

// TODO: remove cast to int when large ByteBuffer support is
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not relevant anymore

private static final ThreadLocal<ByteBuffer> validateByteBuffer = new ThreadLocal<ByteBuffer>() {
@Override
protected ByteBuffer initialValue() {
return ByteBuffer.allocate(Torrent.DEFAULT_PIECE_LENGTH);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could even be generous and use 4k here (default piece length is 512 bytes I think). A lot of torrents of large size will usually use larger pieces, so if you don't give a little more room here you'll rarely actually benefit from your optimization.

@bwzhou
Copy link
Contributor Author

bwzhou commented Sep 28, 2016

Thanks for the comments. I updated the PR to address them and also included an optimization for piece recording that follows the similar idea.

Copy link
Owner

@mpetazzoni mpetazzoni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

12MB per peer thread is probably too much when you can potentially have dozens, if not hundreds, of connected peers.

@bwzhou
Copy link
Contributor Author

bwzhou commented Sep 28, 2016

Torrent.DEFAULT_PIECE_LENGTH is 512k, so I thought your previous comment meant 4M instead of 4k. Would you suggest a number for the sizes of the 3 buffers?

@bwzhou
Copy link
Contributor Author

bwzhou commented Sep 28, 2016

Correct me if I am wrong: previously, we allocate 1x the memory of a piece in recording, followed by 2x the memory of a piece in validation; but now, we pre-allocate 3x the memory of a piece in each thread. So on average, we should use 50% more memory than before if the buffer size equals to the piece size.

@zanella
Copy link

zanella commented Nov 14, 2016

"related" -> google/guava#2112

@zanella
Copy link

zanella commented Nov 23, 2016

Also, I think that complete correction of this problem is by having an event loop instead of an unbounded number of threads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.