Skip to content

Instantly share code, notes, and snippets.

@mpaperno
Last active February 25, 2022 10:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpaperno/58ac6c8bc81ddaa62273f80e15cf3b90 to your computer and use it in GitHub Desktop.
Save mpaperno/58ac6c8bc81ddaa62273f80e15cf3b90 to your computer and use it in GitHub Desktop.

Given an existing long-ish UTF8 string, add a newline char and turn it into a byte array (eg. for sending over a socket).

I added some UTF16 characters, so the string length is 500 but the resulting byte length is 606.

Inspired by https://dotnetcoretutorials.com/2020/02/06/performance-of-string-concatenation-in-c/

Results:

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.1526 (21H2)
Intel Core i7-7820X CPU 3.60GHz (Kaby Lake), 1 CPU, 16 logical and 8 physical cores
.NET SDK=5.0.404
  [Host]     : .NET 5.0.13 (5.0.1321.56516), X64 RyuJIT
  DefaultJob : .NET 5.0.13 (5.0.1321.56516), X64 RyuJIT
Method Mean Error StdDev Gen 0 Gen 1 Allocated
BlockCopyToNewArray 265.7 ns 1.96 ns 1.74 ns 0.2360 0.0005 1 KB
MemcpyToNewArray 277.6 ns 1.43 ns 1.27 ns 0.2360 0.0005 1 KB
PlusAppendToString 304.4 ns 2.62 ns 2.45 ns 0.3042 0.0014 2 KB
StringConcat 303.2 ns 2.13 ns 1.99 ns 0.3042 0.0014 2 KB
StringBulderAppend 461.2 ns 1.67 ns 1.39 ns 0.6771 0.0067 4 KB
StringBulderAppendLine 491.1 ns 5.02 ns 4.69 ns 0.6905 0.0067 4 KB

Code:

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Runtime.InteropServices;
using System.Text;

[MemoryDiagnoser]
public class Bench
{
  public volatile string input = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut " +
     "labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea " +
     "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +
     "Excepteur sint occaecat cupidatat  proident. " +
     "Разнообразный и богатый опыт консультация с широким активом в значительной степени обуславливает создание форм развития.";

  [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
  public static extern IntPtr memcpy(IntPtr dest, IntPtr src, int count);

  [Benchmark]
  public byte[] BlockCopyToNewArray()
  {
    byte[] msgbytes = new UTF8Encoding().GetBytes(input);
    int len = msgbytes.Length;
    byte[] bytes = new byte[len + 1];
    Buffer.BlockCopy(msgbytes, 0, bytes, 0, len);
    bytes[len] = 10;
    return bytes;
  }

  [Benchmark]
  unsafe public byte[] MemcpyToNewArray()
  {
    byte[] msgbytes = new UTF8Encoding().GetBytes(input);
    int len = msgbytes.Length;
    byte[] bytes = new byte[len + 1];
    fixed (byte* pDest = bytes)
    fixed (byte* pSrc = msgbytes) {
      IntPtr ipSrc = (IntPtr)pSrc;
      IntPtr ipDest = (IntPtr)pDest;
      memcpy(ipDest, ipSrc, len);
    }
    bytes[len] = 10;
    return bytes;
  }

  [Benchmark]
  public byte[] PlusAppendToString() =>new UTF8Encoding().GetBytes(input + "\n");

  [Benchmark]
  public byte[] StringConcat() => new UTF8Encoding().GetBytes(string.Concat(input, "\n"));

  [Benchmark]
  public byte[] StringBulderAppend()
  {
    string line = new StringBuilder(input).Append('\n').ToString();
    return new UTF8Encoding().GetBytes(line);
  }

  [Benchmark]
  public byte[] StringBulderAppendLine()
  {
    var line = new StringBuilder().AppendLine(input).ToString();
    return new UTF8Encoding().GetBytes(line);
  }
}

class Program
{
  static void Main(string[] args)
  {
    var summary = BenchmarkRunner.Run<Bench>();

    var encoding = new UTF8Encoding();
    Console.OutputEncoding = encoding;
    Bench bench = new();
    byte[] result = bench.BlockCopyToNewArray();

    Console.WriteLine($"\n\nInput:\n{bench.input}\n");
    Console.WriteLine($"Output:\n{encoding.GetString(result)}\n");
    Console.WriteLine($"String len: {bench.input.Length}; Bytes len: {result.Length}");
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment