Skip to content

Instantly share code, notes, and snippets.

@tannergooding
Last active August 6, 2016 04:30
Show Gist options
  • Save tannergooding/bb256733943fc5afecce6a51a640910d to your computer and use it in GitHub Desktop.
Save tannergooding/bb256733943fc5afecce6a51a640910d to your computer and use it in GitHub Desktop.
Simple Benchmark for Buffer.MemoryCopy
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
unsafe class Program
{
const int outerIterations = 10000;
const int innerIterations = 10000;
const int minByteCount = 0;
const int maxByteCount = 1024;
const int sourceOffset = 0;
const int destinationOffset = 0;
const double timeScale = (1000 * 1000);
static void Main(string[] args)
{
for (var byteCount = minByteCount; byteCount < maxByteCount; byteCount++)
{
var minTime = 0.0;
var maxTime = 0.0;
var totalTime = OuterTest(byteCount, out minTime, out maxTime);
Console.WriteLine($"{outerIterations} iterations of copying {byteCount} bytes ({innerIterations} times) took an average of {totalTime} microseconds (Min: {minTime}, Max: {maxTime}).");
}
}
static double OuterTest(int byteCount, out double minTime, out double maxTime)
{
var innerTest = (Func<IntPtr, IntPtr, int, long>)(InnerTest);
minTime = double.MaxValue;
var totalTime = 0l;
maxTime = double.MinValue;
for (var iteration = 0; iteration < outerIterations; iteration++)
{
var source = IntPtr.Zero;
var destination = IntPtr.Zero;
try
{
source = Marshal.AllocHGlobal(byteCount);
RandomizeMemory(source, byteCount);
destination = Marshal.AllocHGlobal(byteCount);
ZeroMemory(destination, byteCount);
var time = innerTest(source, destination, byteCount);
if (time == 0)
{
Debugger.Break();
}
if (time < minTime)
{
minTime = time;
}
totalTime += time;
if (time > maxTime)
{
maxTime = time;
}
}
finally
{
if (source != IntPtr.Zero)
{
Marshal.FreeHGlobal(source);
}
if (destination != IntPtr.Zero)
{
Marshal.FreeHGlobal(destination);
}
}
}
minTime = (minTime / (double)(Stopwatch.Frequency)) * timeScale;
maxTime = (maxTime / (double)(Stopwatch.Frequency)) * timeScale;
return ((totalTime / (double)(Stopwatch.Frequency)) * timeScale) / outerIterations;
}
static long InnerTest(IntPtr source, IntPtr destination, int byteCount)
{
var pSource = (byte*)(source.ToPointer()) + sourceOffset;
var pDestination = (byte*)(destination.ToPointer()) + destinationOffset;
var startTime = Stopwatch.GetTimestamp();
for (var iteration = 0; iteration < innerIterations; iteration++)
{
Buffer.MemoryCopy(pSource, pDestination, byteCount, byteCount);
}
var endTime = Stopwatch.GetTimestamp();
return (endTime - startTime);
}
static void RandomizeMemory(IntPtr destination, int byteCount)
{
var pDestination = (byte*)(destination.ToPointer());
var rng = new Random();
for (var index = 0; index < byteCount; index++)
{
*(pDestination + index) = (byte)(rng.Next(byte.MinValue, byte.MaxValue));
}
}
static void ZeroMemory(IntPtr destination, int byteCount)
{
var pDestination = (byte*)(destination.ToPointer());
for (var index = 0; index < byteCount; index++)
{
*(pDestination + index) = 0;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment