| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 | #region Copyright notice and license// Protocol Buffers - Google's data interchange format// Copyright 2019 Google Inc.  All rights reserved.// https://github.com/protocolbuffers/protobuf//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met:////     * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.//     * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.//     * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#endregionusing BenchmarkDotNet.Attributes;using System;using System.Buffers.Binary;using System.Collections.Generic;using System.IO;using System.Buffers;using System.Text;namespace Google.Protobuf.Benchmarks{    /// <summary>    /// Benchmarks throughput when writing raw primitives.    /// </summary>    [MemoryDiagnoser]    public class WriteRawPrimitivesBenchmark    {        // key is the encodedSize of varint values        Dictionary<int, uint[]> varint32Values;        Dictionary<int, ulong[]> varint64Values;        double[] doubleValues;        float[] floatValues;        // key is the encodedSize of string values        Dictionary<int, string[]> stringValues;        // key is the encodedSize of string values        Dictionary<int, string[]> nonAsciiStringValues;        // key is the encodedSize of string values        Dictionary<int, ByteString[]> byteStringValues;        // the buffer to which all the data will be written        byte[] outputBuffer;        Random random = new Random(417384220);  // random but deterministic seed        public IEnumerable<int> StringEncodedSizes => new[] { 1, 4, 10, 105, 10080 };        public IEnumerable<int> NonAsciiStringEncodedSizes => new[] { 4, 10, 105, 10080 };        [GlobalSetup]        public void GlobalSetup()        {            outputBuffer = new byte[BytesToWrite];            varint32Values = new Dictionary<int, uint[]>();            varint64Values = new Dictionary<int, ulong[]>();            for (int encodedSize = 1; encodedSize <= 10; encodedSize++)            {                if (encodedSize <= 5)                {                    varint32Values.Add(encodedSize, CreateRandomVarints32(random, BytesToWrite / encodedSize, encodedSize));                }                varint64Values.Add(encodedSize, CreateRandomVarints64(random, BytesToWrite / encodedSize, encodedSize));            }            doubleValues = CreateRandomDoubles(random, BytesToWrite / sizeof(double));            floatValues = CreateRandomFloats(random, BytesToWrite / sizeof(float));            stringValues = new Dictionary<int, string[]>();            byteStringValues = new Dictionary<int, ByteString[]>();            foreach(var encodedSize in StringEncodedSizes)            {                stringValues.Add(encodedSize, CreateStrings(BytesToWrite / encodedSize, encodedSize));                byteStringValues.Add(encodedSize, CreateByteStrings(BytesToWrite / encodedSize, encodedSize));            }            nonAsciiStringValues = new Dictionary<int, string[]>();            foreach(var encodedSize in NonAsciiStringEncodedSizes)            {                nonAsciiStringValues.Add(encodedSize, CreateNonAsciiStrings(BytesToWrite / encodedSize, encodedSize));            }        }        // Total number of bytes that each benchmark will write.        // Measuring the time taken to write buffer of given size makes it easier to compare parsing speed for different        // types and makes it easy to calculate the througput (in MB/s)        // 10800 bytes is chosen because it is divisible by all possible encoded sizes for all primitive types {1..10}        [Params(10080)]        public int BytesToWrite { get; set; }        [Benchmark]        [Arguments(1)]        [Arguments(2)]        [Arguments(3)]        [Arguments(4)]        [Arguments(5)]        public void WriteRawVarint32_CodedOutputStream(int encodedSize)        {            var values = varint32Values[encodedSize];            var cos = new CodedOutputStream(outputBuffer);            foreach (var value in values)            {                cos.WriteRawVarint32(value);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        [Arguments(1)]        [Arguments(2)]        [Arguments(3)]        [Arguments(4)]        [Arguments(5)]        public void WriteRawVarint32_WriteContext(int encodedSize)        {            var values = varint32Values[encodedSize];            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            foreach (var value in values)            {                ctx.WriteUInt32(value);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        [Benchmark]        [Arguments(1)]        [Arguments(2)]        [Arguments(3)]        [Arguments(4)]        [Arguments(5)]        [Arguments(6)]        [Arguments(7)]        [Arguments(8)]        [Arguments(9)]        [Arguments(10)]        public void WriteRawVarint64_CodedOutputStream(int encodedSize)        {            var values = varint64Values[encodedSize];            var cos = new CodedOutputStream(outputBuffer);            foreach (var value in values)            {                cos.WriteRawVarint64(value);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        [Arguments(1)]        [Arguments(2)]        [Arguments(3)]        [Arguments(4)]        [Arguments(5)]        [Arguments(6)]        [Arguments(7)]        [Arguments(8)]        [Arguments(9)]        [Arguments(10)]        public void WriteRawVarint64_WriteContext(int encodedSize)        {            var values = varint64Values[encodedSize];            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            foreach (var value in values)            {                ctx.WriteUInt64(value);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        [Benchmark]        public void WriteFixed32_CodedOutputStream()        {            const int encodedSize = sizeof(uint);            var cos = new CodedOutputStream(outputBuffer);            for(int i = 0; i < BytesToWrite / encodedSize; i++)            {                cos.WriteFixed32(12345);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        public void WriteFixed32_WriteContext()        {            const int encodedSize = sizeof(uint);            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            for (uint i = 0; i < BytesToWrite / encodedSize; i++)            {                ctx.WriteFixed32(12345);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        [Benchmark]        public void WriteFixed64_CodedOutputStream()        {            const int encodedSize = sizeof(ulong);            var cos = new CodedOutputStream(outputBuffer);            for(int i = 0; i < BytesToWrite / encodedSize; i++)            {                cos.WriteFixed64(123456789);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        public void WriteFixed64_WriteContext()        {            const int encodedSize = sizeof(ulong);            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            for (uint i = 0; i < BytesToWrite / encodedSize; i++)            {                ctx.WriteFixed64(123456789);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        [Benchmark]        public void WriteRawFloat_CodedOutputStream()        {            var cos = new CodedOutputStream(outputBuffer);            foreach (var value in floatValues)            {                cos.WriteFloat(value);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        public void WriteRawFloat_WriteContext()        {            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            foreach (var value in floatValues)            {                ctx.WriteFloat(value);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        [Benchmark]        public void WriteRawDouble_CodedOutputStream()        {            var cos = new CodedOutputStream(outputBuffer);            foreach (var value in doubleValues)            {                cos.WriteDouble(value);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        public void WriteRawDouble_WriteContext()        {            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            foreach (var value in doubleValues)            {                ctx.WriteDouble(value);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        [Benchmark]        [ArgumentsSource(nameof(StringEncodedSizes))]        public void WriteString_CodedOutputStream(int encodedSize)        {            var values = stringValues[encodedSize];            var cos = new CodedOutputStream(outputBuffer);            foreach (var value in values)            {                cos.WriteString(value);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        [ArgumentsSource(nameof(StringEncodedSizes))]        public void WriteString_WriteContext(int encodedSize)        {            var values = stringValues[encodedSize];            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            foreach (var value in values)            {                ctx.WriteString(value);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        [Benchmark]        [ArgumentsSource(nameof(NonAsciiStringEncodedSizes))]        public void WriteNonAsciiString_CodedOutputStream(int encodedSize)        {            var values = nonAsciiStringValues[encodedSize];            var cos = new CodedOutputStream(outputBuffer);            foreach (var value in values)            {                cos.WriteString(value);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        [ArgumentsSource(nameof(NonAsciiStringEncodedSizes))]        public void WriteNonAsciiString_WriteContext(int encodedSize)        {            var values = nonAsciiStringValues[encodedSize];            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            foreach (var value in values)            {                ctx.WriteString(value);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        [Benchmark]        [ArgumentsSource(nameof(StringEncodedSizes))]        public void WriteBytes_CodedOutputStream(int encodedSize)        {            var values = byteStringValues[encodedSize];            var cos = new CodedOutputStream(outputBuffer);            foreach (var value in values)            {                cos.WriteBytes(value);            }            cos.Flush();            cos.CheckNoSpaceLeft();        }        [Benchmark]        [ArgumentsSource(nameof(StringEncodedSizes))]        public void WriteBytes_WriteContext(int encodedSize)        {            var values = byteStringValues[encodedSize];            var span = new Span<byte>(outputBuffer);            WriteContext.Initialize(ref span, out WriteContext ctx);            foreach (var value in values)            {                ctx.WriteBytes(value);            }            ctx.Flush();            ctx.CheckNoSpaceLeft();        }        private static uint[] CreateRandomVarints32(Random random, int valueCount, int encodedSize)        {            var result = new uint[valueCount];            for (int i = 0; i < valueCount; i++)            {                result[i] = (uint) ParseRawPrimitivesBenchmark.RandomUnsignedVarint(random, encodedSize, true);            }            return result;        }        private static ulong[] CreateRandomVarints64(Random random, int valueCount, int encodedSize)        {                        var result = new ulong[valueCount];            for (int i = 0; i < valueCount; i++)            {                result[i] = ParseRawPrimitivesBenchmark.RandomUnsignedVarint(random, encodedSize, false);            }            return result;        }        private static float[] CreateRandomFloats(Random random, int valueCount)        {            var result = new float[valueCount];            for (int i = 0; i < valueCount; i++)            {                result[i] = (float)random.NextDouble();            }            return result;        }        private static double[] CreateRandomDoubles(Random random, int valueCount)        {            var result = new double[valueCount];            for (int i = 0; i < valueCount; i++)            {                result[i] = random.NextDouble();            }            return result;        }        private static string[] CreateStrings(int valueCount, int encodedSize)        {            var str = ParseRawPrimitivesBenchmark.CreateStringWithEncodedSize(encodedSize);            var result = new string[valueCount];            for (int i = 0; i < valueCount; i++)            {                result[i] = str;            }            return result;        }        private static string[] CreateNonAsciiStrings(int valueCount, int encodedSize)        {            var str = ParseRawPrimitivesBenchmark.CreateNonAsciiStringWithEncodedSize(encodedSize);            var result = new string[valueCount];            for (int i = 0; i < valueCount; i++)            {                result[i] = str;            }            return result;        }        private static ByteString[] CreateByteStrings(int valueCount, int encodedSize)        {            var str = ParseRawPrimitivesBenchmark.CreateStringWithEncodedSize(encodedSize);            var result = new ByteString[valueCount];            for (int i = 0; i < valueCount; i++)            {                result[i] = ByteString.CopyFrom(Encoding.UTF8.GetBytes(str));            }            return result;        }    }}
 |