Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

add optimized FastByteCopy #853

Closed
wants to merge 1 commit into from
Closed

Conversation

geoffkizer
Copy link
Contributor

Buffer.BlockCopy is not particularly efficient for small blocks.

For blocks < 64 bytes, do the copy ourselves in unsafe code.

This gives something like 4% on TechEmpower plaintext (when combined with other proposed fixes).

@dnfclas
Copy link

dnfclas commented May 20, 2016

Hi @geoffkizer, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!
You've already signed the contribution license agreement. Thanks!

The agreement was validated by .NET Foundation and real humans are currently evaluating your PR.

TTYL, DNFBOT;

@geoffkizer
Copy link
Contributor Author

@benaadams, @nathana1, @halter73

@benaadams
Copy link
Contributor

benaadams commented May 20, 2016

Vectors are better > Vector<byte>.Count with some unrolling; though may be better when the Unsafe library is available. Not sure much in the techempower it that large for the copy? (e.g. Hello World is only 13 bytes)

🚀

@geoffkizer
Copy link
Contributor Author

Yeah, Vectors are better, at least in theory. Unsafe library would be needed to make this work well, I think.

That said, vector size can vary based on hardware, so that would make the code a bit more involved; not sure it's worth it for these scenarios.

BTW, I played around with this a bit, but it's certainly worth looking at more. There may be tweaks we could do to make this better.

Ideally we could have the JIT do smart things here, e.g. do appropriate vector optimization, generate fixed size copies, etc. That's probably a longer term thing.

Largest copy in TechEmpower is 37 bytes, for the Date header.

@benaadams
Copy link
Contributor

Actually do have a change can drop one of the fixed blocks in all cases

@@ -687,7 +790,7 @@ public MemoryPoolIterator CopyTo(byte[] array, int offset, int count, out int ac
actual = count;
if (array != null)
{
Buffer.BlockCopy(block.Array, index, array, offset, remaining);
FastByteCopy(block.Array, (uint)index, array, (uint)offset, (uint)remaining);
Copy link
Contributor

@benaadams benaadams May 20, 2016

Choose a reason for hiding this comment

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

can use block.DataFixedPtr rather than fixed on block.Array

@geoffkizer
Copy link
Contributor Author

I think fixed() here is basically a no-op.


if (byteCount < 64)
{
// Buffer.BlockCopy is expensive for small copies. Do it manually ourselves.
Copy link
Member

Choose a reason for hiding this comment

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

Why doesn't Buffer.BlockCopy do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Buffer.BlockCopy has to do type checks regardless, so it's better to have an unsafe version that doesn't require this.

Perhaps we should have something like Buffer.UnsafeByteCopy, but that's a larger discussion.

Copy link
Member

Choose a reason for hiding this comment

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

I mean, we have other code like this in kestrel but it's not great that we need to do it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, I'm just saying that figuring out a better way is probably a longer discussion. Do you want to have that discussion before we decide whether to take this?

Copy link
Member

Choose a reason for hiding this comment

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

I rather do it in parallel.

Copy link
Contributor

Choose a reason for hiding this comment

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

@benaadams
Copy link
Contributor

benaadams commented May 21, 2016

@geoffkizer this any good? benaadams@201139a?w=1

@benaadams
Copy link
Contributor

Actually this is probably better benaadams@757f7e4?w=1

@halter73
Copy link
Member

I'm going to merge this as is. @davidfowl Sound good to you?

@halter73
Copy link
Member

@geoffkizer For small byte copies do you think the cost of fixed is significant enough to warrant taking advantage of block.DataFixedPtr like @benaadams suggested?

@geoffkizer
Copy link
Contributor Author

I tried using DataFixedPtr and it didn't seem to matter.

@benaadams
Copy link
Contributor

The Debug.Asserts are still testing the wrong things; they are testing against the entire slab array size rather than the individual block size

@geoffkizer
Copy link
Contributor Author

As it stands, FastByteCopy is intentionally ignorant of Blocks, so that it can be a general purpose copy mechanism. That's why the asserts are the way they are.

@benaadams
Copy link
Contributor

Which is why I added the asserts to CopyTo at the block level so it would assert if any of the copies were going outside of the block.

As the block is a small window over a much larger array the asserts in the FastByteCopy are unlikely to ever trigger even if CopyTo is being asked to inadvertently overwrite adjacent blocks; as is far as its concerned its a valid request.

@benaadams
Copy link
Contributor

benaadams commented Jun 1, 2016

Sorry, they are additional asserts that weren't there previously and the behaviour is not changing on BlockCopy, so out of scope will raise other PR.

@benaadams
Copy link
Contributor

Added PR #900 for other asserts

@halter73
Copy link
Member

halter73 commented Jun 2, 2016

@geoffkizer @davidfowl Closing since we want #897 for 1.0.1, and we didn't think this kind of change was worth merging temporarily for 1.0.0.

@halter73 halter73 closed this Jun 2, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants