From 2772dfe8a1eae7c942bb50d84bda3f45b5d7b683 Mon Sep 17 00:00:00 2001 From: csharptest Date: Wed, 8 Jun 2011 15:50:58 -0500 Subject: Performance fix for float/double write bytes. Performance fix, do not use Array.Copy. --- src/ProtoBench/Program.cs | 5 ++-- src/ProtocolBuffers/ByteString.cs | 6 ++--- src/ProtocolBuffers/Bytes.cs | 32 +++++++++++++++++++++++++ src/ProtocolBuffers/CodedInputStream.cs | 12 +++++----- src/ProtocolBuffers/CodedOutputStream.cs | 33 ++++++++++++++++++++++---- src/ProtocolBuffers/ProtocolBuffers.csproj | 1 + src/ProtocolBuffers/ProtocolBuffersLite.csproj | 1 + 7 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 src/ProtocolBuffers/Bytes.cs (limited to 'src') diff --git a/src/ProtoBench/Program.cs b/src/ProtoBench/Program.cs index 7d91bbed..36f7850d 100644 --- a/src/ProtoBench/Program.cs +++ b/src/ProtoBench/Program.cs @@ -87,6 +87,7 @@ namespace Google.ProtocolBuffers.ProtoBench Console.Error.WriteLine("(You can specify multiple pairs of descriptor type name and input data.)"); return 1; } + bool success = true; for (int i = 0; i < args.Length; i += 2) { @@ -94,7 +95,7 @@ namespace Google.ProtocolBuffers.ProtoBench } return success ? 0 : 1; } - + /// /// Runs a single test. Error messages are displayed to Console.Error, and the return value indicates /// general success/failure. @@ -185,7 +186,7 @@ namespace Google.ProtocolBuffers.ProtoBench double first = (iterations * dataSize) / (elapsed.TotalSeconds * 1024 * 1024); if (Verbose) Console.WriteLine("Round ---: Count = {1,6}, Bps = {2,8:f3}", 0, iterations, first); elapsed = TimeSpan.Zero; - int max = FastTest ? 30 : 100; + int max = FastTest ? 10 : 30; while (runs < max) { diff --git a/src/ProtocolBuffers/ByteString.cs b/src/ProtocolBuffers/ByteString.cs index e645a9f2..06708af7 100644 --- a/src/ProtocolBuffers/ByteString.cs +++ b/src/ProtocolBuffers/ByteString.cs @@ -123,7 +123,7 @@ namespace Google.ProtocolBuffers public static ByteString CopyFrom(byte[] bytes, int offset, int count) { byte[] portion = new byte[count]; - Array.Copy(bytes, offset, portion, 0, count); + Bytes.Copy(bytes, offset, portion, 0, count); return new ByteString(portion); } @@ -259,9 +259,9 @@ namespace Google.ProtocolBuffers /// /// Copies the entire byte array to the destination array provided at the offset specified. /// - public void CopyTo(Array array, int position) + public void CopyTo(byte[] array, int position) { - Array.Copy(bytes, 0, array, position, bytes.Length); + Bytes.Copy(bytes, 0, array, position, bytes.Length); } /// diff --git a/src/ProtocolBuffers/Bytes.cs b/src/ProtocolBuffers/Bytes.cs new file mode 100644 index 00000000..88bc16f8 --- /dev/null +++ b/src/ProtocolBuffers/Bytes.cs @@ -0,0 +1,32 @@ +namespace Google.ProtocolBuffers +{ + /// + /// Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy + /// + static class Bytes + { + /// + /// The threshold above which you should use Buffer.BlockCopy rather than Bytes.Copy + /// + const int CopyThreshold = 12; + /// + /// Determines which copy routine to use based on the number of bytes to be copied. + /// + public static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count) + { + if (count > CopyThreshold) + global::System.Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count); + else + ByteCopy(src, srcOffset, dst, dstOffset, count); + } + /// + /// Copyies the bytes provided with a for loop, faster when there are only a few bytes to copy + /// + public static void ByteCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count) + { + int stop = srcOffset + count; + for (int i = srcOffset; i < stop; i++) + dst[dstOffset++] = src[i]; + } + } +} \ No newline at end of file diff --git a/src/ProtocolBuffers/CodedInputStream.cs b/src/ProtocolBuffers/CodedInputStream.cs index 74fa9475..4f9bdc23 100644 --- a/src/ProtocolBuffers/CodedInputStream.cs +++ b/src/ProtocolBuffers/CodedInputStream.cs @@ -1225,7 +1225,7 @@ namespace Google.ProtocolBuffers { // We have all the bytes we need already. byte[] bytes = new byte[size]; - Array.Copy(buffer, bufferPos, bytes, 0, size); + Bytes.Copy(buffer, bufferPos, bytes, 0, size); bufferPos += size; return bytes; } @@ -1237,7 +1237,7 @@ namespace Google.ProtocolBuffers // First copy what we have. byte[] bytes = new byte[size]; int pos = bufferSize - bufferPos; - Array.Copy(buffer, bufferPos, bytes, 0, pos); + Bytes.Copy(buffer, bufferPos, bytes, 0, pos); bufferPos = bufferSize; // We want to use RefillBuffer() and then copy from the buffer into our @@ -1247,13 +1247,13 @@ namespace Google.ProtocolBuffers while (size - pos > bufferSize) { - Array.Copy(buffer, 0, bytes, pos, bufferSize); + Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize); pos += bufferSize; bufferPos = bufferSize; RefillBuffer(true); } - Array.Copy(buffer, 0, bytes, pos, size - pos); + Bytes.Copy(buffer, 0, bytes, pos, size - pos); bufferPos = size - pos; return bytes; @@ -1305,12 +1305,12 @@ namespace Google.ProtocolBuffers // Start by copying the leftover bytes from this.buffer. int newPos = originalBufferSize - originalBufferPos; - Array.Copy(buffer, originalBufferPos, bytes, 0, newPos); + Bytes.Copy(buffer, originalBufferPos, bytes, 0, newPos); // And now all the chunks. foreach (byte[] chunk in chunks) { - Array.Copy(chunk, 0, bytes, newPos, chunk.Length); + Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length); newPos += chunk.Length; } diff --git a/src/ProtocolBuffers/CodedOutputStream.cs b/src/ProtocolBuffers/CodedOutputStream.cs index 31032058..bd508661 100644 --- a/src/ProtocolBuffers/CodedOutputStream.cs +++ b/src/ProtocolBuffers/CodedOutputStream.cs @@ -38,6 +38,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Runtime.InteropServices; using System.Text; using Google.ProtocolBuffers.Descriptors; @@ -648,7 +649,20 @@ namespace Google.ProtocolBuffers byte[] rawBytes = BitConverter.GetBytes(value); if (!BitConverter.IsLittleEndian) Array.Reverse(rawBytes); - WriteRawBytes(rawBytes, 0, 8); + + if (limit - position >= 8) + { + buffer[position++] = rawBytes[0]; + buffer[position++] = rawBytes[1]; + buffer[position++] = rawBytes[2]; + buffer[position++] = rawBytes[3]; + buffer[position++] = rawBytes[4]; + buffer[position++] = rawBytes[5]; + buffer[position++] = rawBytes[6]; + buffer[position++] = rawBytes[7]; + } + else + WriteRawBytes(rawBytes, 0, 8); #else WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value)); #endif @@ -662,7 +676,16 @@ namespace Google.ProtocolBuffers byte[] rawBytes = BitConverter.GetBytes(value); if (!BitConverter.IsLittleEndian) Array.Reverse(rawBytes); - WriteRawBytes(rawBytes, 0, 4); + + if (limit - position >= 4) + { + buffer[position++] = rawBytes[0]; + buffer[position++] = rawBytes[1]; + buffer[position++] = rawBytes[2]; + buffer[position++] = rawBytes[3]; + } + else + WriteRawBytes(rawBytes, 0, 4); } /// @@ -985,7 +1008,7 @@ namespace Google.ProtocolBuffers { if (limit - position >= length) { - Array.Copy(value, offset, buffer, position, length); + Bytes.Copy(value, offset, buffer, position, length); // We have room in the current buffer. position += length; } @@ -994,7 +1017,7 @@ namespace Google.ProtocolBuffers // Write extends past current buffer. Fill the rest of this buffer and // flush. int bytesWritten = limit - position; - Array.Copy(value, offset, buffer, position, bytesWritten); + Bytes.Copy(value, offset, buffer, position, bytesWritten); offset += bytesWritten; length -= bytesWritten; position = limit; @@ -1006,7 +1029,7 @@ namespace Google.ProtocolBuffers if (length <= limit) { // Fits in new buffer. - Array.Copy(value, offset, buffer, 0, length); + Bytes.Copy(value, offset, buffer, 0, length); position = length; } else diff --git a/src/ProtocolBuffers/ProtocolBuffers.csproj b/src/ProtocolBuffers/ProtocolBuffers.csproj index a059ca39..cf212909 100644 --- a/src/ProtocolBuffers/ProtocolBuffers.csproj +++ b/src/ProtocolBuffers/ProtocolBuffers.csproj @@ -99,6 +99,7 @@ Code + diff --git a/src/ProtocolBuffers/ProtocolBuffersLite.csproj b/src/ProtocolBuffers/ProtocolBuffersLite.csproj index 936a6950..fc1c7f64 100644 --- a/src/ProtocolBuffers/ProtocolBuffersLite.csproj +++ b/src/ProtocolBuffers/ProtocolBuffersLite.csproj @@ -78,6 +78,7 @@ + -- cgit v1.2.3