Last active
December 11, 2016 01:30
-
-
Save bojanrajkovic/5a0e87737b3da59120eb2f4cc1f61eb0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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