Skip to content

Instantly share code, notes, and snippets.

@larsw
Created January 29, 2013 14:35
Show Gist options
  • Select an option

  • Save larsw/4664681 to your computer and use it in GitHub Desktop.

Select an option

Save larsw/4664681 to your computer and use it in GitHub Desktop.
Kellys SIMD stuff
using System;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using Mono.Simd;
namespace VectorizedQueryTest
{
public class AlignedIntArray : IDisposable
{
private byte[] buffer;
private GCHandle bufferHandle;
private IntPtr bufferPointer;
private readonly int length;
public AlignedIntArray(int length, int byteAlignment)
{
this.length = length;
buffer = new byte[length * sizeof(int) + byteAlignment];
bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
long ptr = bufferHandle.AddrOfPinnedObject().ToInt64();
// round up ptr to nearest 'byteAlignment' boundary
ptr = (ptr + byteAlignment - 1) & ~(byteAlignment - 1);
bufferPointer = new IntPtr(ptr);
}
~AlignedIntArray()
{
Dispose(false);
}
protected void Dispose(bool disposing)
{
if(bufferHandle.IsAllocated)
{
bufferHandle.Free();
buffer = null;
}
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
}
#endregion
public int this[int index]
{
get
{
unsafe
{
return GetPointer()[index];
}
}
set
{
unsafe
{
GetPointer()[index] = value;
}
}
}
public int Length
{
get
{
return length;
}
}
public void Write(int index,int[] src,int srcIndex,int count)
{
if(index<0 || index>=length) throw new IndexOutOfRangeException();
if ((index + count) > length) count = Math.Max(0, length - index);
System.Runtime.InteropServices.Marshal.Copy(
src,
srcIndex,
new IntPtr(bufferPointer.ToInt64() + index*sizeof (int)),
count);
}
public void Read(int index, int[] dest, int dstIndex, int count)
{
if (index < 0 || index >= length) throw new IndexOutOfRangeException();
if ((index + count) > length) count = Math.Max(0, length - index);
System.Runtime.InteropServices.Marshal.Copy(
new IntPtr(bufferPointer.ToInt64() + index*sizeof (int)),
dest,
dstIndex,
count);
}
public int[] GetManagedArray()
{
return GetManagedArray(0, length);
}
public int[] GetManagedArray(int index,int count)
{
int[] result = new int[count];
Read(index, result, 0, count);
return result;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
for(int t=0;t<length;t++)
{
sb.Append(this[t].ToString());
if (t < (length - 1)) sb.Append(',');
}
sb.Append(']');
return sb.ToString();
}
public unsafe int* GetPointer(int index)
{
return GetPointer() + index;
}
public unsafe int* GetPointer()
{
return ((int*) bufferPointer.ToPointer());
}
}
class Program
{
static bool MinimalSimdSupport()
{
return SimdRuntime.IsMethodAccelerated (typeof (Vector4f), "op_Addition") &&
SimdRuntime.IsMethodAccelerated (typeof (Vector4f), "op_Multiply") &&
SimdRuntime.IsMethodAccelerated (typeof (VectorOperations), "Shuffle", typeof (Vector4f), typeof (ShuffleSel));
}
static bool EnhancedSimdSupport()
{
return SimdRuntime.IsMethodAccelerated (typeof (VectorOperations), "HorizontalAdd", typeof (Vector4f), typeof (Vector4f)) &&
SimdRuntime.IsMethodAccelerated (typeof (Vector4f), "op_Multiply");
}
static unsafe void Main(string[] args)
{
// Console.WriteLine("Minimal SIMD Support: " + MinimalSimdSupport());
// Console.WriteLine("Enhanched SIMD Support: " + EnhancedSimdSupport());
// SELECT * FROM Table WHERE ColumnA < ColumnB
int rowCount = 10000000; // 10M
var rand = new Random();
var rowidsAligned = new AlignedIntArray(rowCount, 16);
var rowids = rowidsAligned.GetPointer(); //new int[rowCount];
var columnaAligned = new AlignedIntArray(rowCount, 16);
var columna = columnaAligned.GetPointer(); //new int[rowids.Length];
var columnbAligned = new AlignedIntArray(rowCount, 16);
var columnb = columnbAligned.GetPointer(); //new int[rowids.Length];
var resultAligned = new AlignedIntArray(rowCount + 1, 16);
var result = resultAligned.GetPointer(); //new int[rowids.Length + 1];
var pos = 0;
for (int i = 0; i < rowCount; i++)
{
rowids[i] = i;
columna[i] = rand.Next();
columnb[i] = rand.Next();
}
Vector4i columnbVector;
Vector4i columnaVector;
// Start of performance measuring.
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < rowCount; i += 4)
{
columnaVector = new Vector4i(columna[i], columna[i+1], columna[i+2], columna[i+3]); // columna.GetVector(i);
columnbVector = new Vector4i(columnb[i], columnb[i+1], columnb[i+2], columnb[i+3]); // columnb.GetVector(i);
var mask = columnbVector.CompareGreaterThan(columnaVector);
// To compare greater than or equals, compare equals, compare greater than, and then and the two masks together. Use bitwise OR.
if ((mask.X | mask.Y | mask.Z | mask.W) < 0) // Profiler says 4.8% spent here.
{
var tmp = mask[0] & 1;
result[pos] = rowids[i];
pos += tmp;
tmp = mask[1] & 1;
result[pos] = rowids[i + 1];
pos += tmp;
tmp = mask[2] & 1;
result[pos] = rowids[i + 2];
pos += tmp;
tmp = mask[3] & 1;
result[pos] = rowids[i + 3];
pos += tmp;
}
}
result[pos] = 0;
watch.Stop(); // 114 milliseconds to process 10M rows.
Console.WriteLine(watch.Elapsed);
columnaAligned.Dispose();
columnbAligned.Dispose();
rowidsAligned.Dispose();
resultAligned.Dispose();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment