Created
January 29, 2013 14:35
-
-
Save larsw/4664681 to your computer and use it in GitHub Desktop.
Kellys SIMD stuff
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.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