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

Commit c324a27

Browse files
committed
Faster CopyFromAscii
1 parent 17d282b commit c324a27

File tree

1 file changed

+96
-39
lines changed

1 file changed

+96
-39
lines changed

src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -636,68 +636,125 @@ public unsafe void CopyFrom(byte[] data, int offset, int count)
636636

637637
public unsafe void CopyFromAscii(string data)
638638
{
639-
Debug.Assert(_block != null);
640-
Debug.Assert(_block.Pool != null);
641-
Debug.Assert(_block.Next == null);
642-
Debug.Assert(_block.End == _index);
643-
644-
var pool = _block.Pool;
645639
var block = _block;
646640
var blockIndex = _index;
647-
var length = data.Length;
641+
var count = data.Length;
648642

649-
var bytesLeftInBlock = block.BlockEndOffset - blockIndex;
650-
var bytesLeftInBlockMinusSpan = bytesLeftInBlock - 3;
643+
if (count > int.MaxValue - 12)
644+
{
645+
// protect unrolled loop from using negative values in extremis
646+
throw new ArgumentOutOfRangeException(nameof(data));
647+
}
648+
649+
var blockRemaining = block.BlockEndOffset - blockIndex;
651650

652651
fixed (char* pData = data)
653652
{
654-
var input = pData;
655-
var inputEnd = pData + length;
656-
var inputEndMinusSpan = inputEnd - 3;
653+
if (blockRemaining >= count)
654+
{
655+
_index = blockIndex + count;
656+
657+
fixed (byte* output = block.Array)
658+
{
659+
CopyFromAscii(pData, output + blockIndex, count);
660+
}
657661

658-
while (input < inputEnd)
662+
block.End = _index;
663+
return;
664+
}
665+
666+
var input = pData;
667+
do
659668
{
660-
if (bytesLeftInBlock == 0)
669+
if (blockRemaining == 0)
661670
{
662-
var nextBlock = pool.Lease();
663-
block.End = blockIndex;
671+
var nextBlock = block.Pool.Lease();
672+
blockIndex = nextBlock.Data.Offset;
673+
blockRemaining = nextBlock.Data.Count;
664674
block.Next = nextBlock;
665675
block = nextBlock;
666-
667-
blockIndex = block.Data.Offset;
668-
bytesLeftInBlock = block.Data.Count;
669-
bytesLeftInBlockMinusSpan = bytesLeftInBlock - 3;
670676
}
671677

672-
fixed (byte* pOutput = block.Data.Array)
678+
if (count > blockRemaining)
673679
{
674-
var output = pOutput + block.End;
680+
count -= blockRemaining;
675681

676-
var copied = 0;
677-
for (; input < inputEndMinusSpan && copied < bytesLeftInBlockMinusSpan; copied += 4)
682+
fixed (byte* output = block.Array)
678683
{
679-
*(output) = (byte)*(input);
680-
*(output + 1) = (byte)*(input + 1);
681-
*(output + 2) = (byte)*(input + 2);
682-
*(output + 3) = (byte)*(input + 3);
683-
output += 4;
684-
input += 4;
684+
CopyFromAscii(input, output + blockIndex, blockRemaining);
685685
}
686-
for (; input < inputEnd && copied < bytesLeftInBlock; copied++)
686+
687+
block.End = blockIndex + blockRemaining;
688+
input += blockRemaining;
689+
blockRemaining = 0;
690+
continue;
691+
}
692+
else
693+
{
694+
_index = blockIndex + count;
695+
696+
fixed (byte* output = block.Array)
687697
{
688-
*(output++) = (byte)*(input++);
698+
CopyFromAscii(input, output + blockIndex, count);
689699
}
690700

691-
blockIndex += copied;
692-
bytesLeftInBlockMinusSpan -= copied;
693-
bytesLeftInBlock -= copied;
701+
block.End = _index;
702+
_block = block;
703+
return;
694704
}
695-
}
705+
} while (true);
696706
}
707+
}
697708

698-
block.End = blockIndex;
699-
_block = block;
700-
_index = blockIndex;
709+
private unsafe static void CopyFromAscii(char* input, byte* output, int count)
710+
{
711+
var i = 0;
712+
713+
while (i + 11 < count)
714+
{
715+
i += 12;
716+
*(output) = (byte)*(input);
717+
*(output + 1) = (byte)*(input + 1);
718+
*(output + 2) = (byte)*(input + 2);
719+
*(output + 3) = (byte)*(input + 3);
720+
*(output + 4) = (byte)*(input + 4);
721+
*(output + 5) = (byte)*(input + 5);
722+
*(output + 6) = (byte)*(input + 6);
723+
*(output + 7) = (byte)*(input + 7);
724+
*(output + 8) = (byte)*(input + 8);
725+
*(output + 9) = (byte)*(input + 9);
726+
*(output + 10) = (byte)*(input + 10);
727+
*(output + 11) = (byte)*(input + 11);
728+
output += 12;
729+
input += 12;
730+
}
731+
if (i + 6 < count)
732+
{
733+
i += 6;
734+
*(output) = (byte)*(input);
735+
*(output + 1) = (byte)*(input + 1);
736+
*(output + 2) = (byte)*(input + 2);
737+
*(output + 3) = (byte)*(input + 3);
738+
*(output + 4) = (byte)*(input + 4);
739+
*(output + 5) = (byte)*(input + 5);
740+
output += 6;
741+
input += 6;
742+
}
743+
if (i + 3 < count)
744+
{
745+
i += 4;
746+
*(output) = (byte)*(input);
747+
*(output + 1) = (byte)*(input + 1);
748+
*(output + 2) = (byte)*(input + 2);
749+
*(output + 3) = (byte)*(input + 3);
750+
output += 4;
751+
input += 4;
752+
}
753+
while (i < count)
754+
{
755+
i++;
756+
*(output++) = (byte)*(input++);
757+
}
701758
}
702759
}
703760
}

0 commit comments

Comments
 (0)