Skip to content

Instantly share code, notes, and snippets.

@bojanrajkovic
Last active December 11, 2016 01:30
Show Gist options
  • Save bojanrajkovic/5a0e87737b3da59120eb2f4cc1f61eb0 to your computer and use it in GitHub Desktop.
Save bojanrajkovic/5a0e87737b3da59120eb2f4cc1f61eb0 to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Columns;
using BenchmarkDotNet.Attributes.Jobs;
using BenchmarkDotNet.Mathematics;
using BenchmarkDotNet.Order;
using BenchmarkDotNet.Running;
namespace VectorBenchmark
{
class MainClass
{
public static void Main(string[] args)
{
var pvv = new PointersVsVectors
{
BytesPerPixel = 4,
TotalBytes = 5000
};
pvv.Setup();
var vec = pvv.VectorAndPointer();
var ptr = pvv.PointersOnly();
var equal = vec.SequenceEqual(ptr);
if (!equal)
{
Console.WriteLine("Sequences are not equal from test methods, please check implementation.");
Environment.Exit(1);
}
else {
Console.WriteLine("Sequences are equal, press any key to proceed.");
}
Console.ReadKey();
BenchmarkRunner.Run<PointersVsVectors>();
}
}
[OrderProvider(SummaryOrderPolicy.FastestToSlowest)]
[RankColumn(NumeralSystem.Stars)]
[MonoJob]
public class PointersVsVectors
{
[Params(5000)]
public int TotalBytes { get; set; }
[Params(4)]
public int BytesPerPixel { get; set; }
byte[] data;
static readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
[Setup]
public void Setup()
{
data = new byte[TotalBytes];
rng.GetBytes(data);
}
[Benchmark(Baseline = true)]
public unsafe byte[] PointersOnly()
{
byte[] targetBuffer = new byte[data.Length];
fixed (byte* targetPtr = targetBuffer)
{
fixed (byte* scanlinePtr = data)
{
Buffer.MemoryCopy(scanlinePtr, targetPtr, data.Length, BytesPerPixel);
unchecked
{
// We start immediately after the first pixel--its bytes are unchanged. We only copied
// bytesPerPixel bytes from the scanline, so we need to read over the raw scanline.
for (var x = BytesPerPixel; x < data.Length; x++)
targetPtr[x] = (byte)((scanlinePtr[x] - scanlinePtr[x - BytesPerPixel]) % 256);
}
}
}
return targetBuffer;
}
[Benchmark]
public unsafe byte[] Naive()
{
byte[] targetBuffer = new byte[data.Length];
Buffer.BlockCopy(data, 0, targetBuffer, 0, BytesPerPixel);
unchecked
{
// We start immediately after the first pixel--its bytes are unchanged. We only copied
// bytesPerPixel bytes from the scanline, so we need to read over the raw scanline.
for (var x = BytesPerPixel; x < data.Length; x++)
targetBuffer[x] = (byte)((data[x] - data[x - BytesPerPixel]) % 256);
}
return targetBuffer;
}
[Benchmark]
public unsafe byte[] VectorAndPointer()
{
var vecSize = Vector<byte>.Count;
byte[] result = new byte[data.Length];
var chunks = (int)Math.Floor((float)(data.Length - BytesPerPixel) / vecSize);
fixed (byte* dataPtr = data)
{
fixed (byte* resultPtr = result)
{
Buffer.MemoryCopy(dataPtr, resultPtr, data.Length, BytesPerPixel);
for (int i = 0; i < chunks; i++)
{
int target = BytesPerPixel + i * vecSize;
var vec = new Vector<byte>(data, target) - new Vector<byte>(data, i * vecSize);
vec.CopyTo(result, target);
}
int start = (BytesPerPixel + (vecSize * chunks));
for (int i = start; i < data.Length; i++)
resultPtr[i] = unchecked((byte)(dataPtr[i] - dataPtr[i - BytesPerPixel]));
}
}
return result;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment