/// <summary> /// Creates a kernel to calculate the histogram on a supplied view /// (without overflow checking). /// </summary> /// <typeparam name="T">The input view element type.</typeparam> /// <typeparam name="TStride">The input view stride.</typeparam> /// <typeparam name="TBinType">The histogram bin type.</typeparam> /// <typeparam name="TIncrementor"> /// The operation to increment the value of the bin. /// </typeparam> /// <typeparam name="TLocator"> /// The operation to compute the bin location. /// </typeparam> /// <param name="accelerator">The accelerator.</param> /// <returns>The created histogram handler.</returns> public static HistogramUnchecked <T, TStride, TBinType> CreateHistogramUnchecked < T, TStride, TBinType, TIncrementor, TLocator>( this Accelerator accelerator) where T : unmanaged where TStride : unmanaged, IStride1D where TBinType : unmanaged where TIncrementor : struct, IIncrementOperation <TBinType> where TLocator : struct, IComputeMultiBinOperation <T, TBinType, TIncrementor> { var kernel = accelerator.LoadKernel < HistogramUncheckedDelegate < T, TStride, TBinType, TIncrementor, TLocator> >( HistogramUncheckedKernelMethod.MakeGenericMethod( typeof(T), typeof(TStride), typeof(TBinType), typeof(TIncrementor), typeof(TLocator))); return((stream, view, histogram) => { if (!view.IsValid) { throw new ArgumentNullException(nameof(view)); } if (view.Length < 1) { throw new ArgumentOutOfRangeException(nameof(view)); } if (!histogram.IsValid) { throw new ArgumentNullException(nameof(histogram)); } if (histogram.Length < 1) { throw new ArgumentOutOfRangeException(nameof(histogram)); } if (view.Length > int.MaxValue || histogram.Length > int.MaxValue) { throw new NotSupportedException( ErrorMessages.NotSupportedArrayView64); } int numElements = view.IntExtent; var(gridDim, groupDim) = accelerator.ComputeGridStrideLoopExtent( numElements, out int numIterationsPerGroup); int lengthInformation = XMath.DivRoundUp(numElements, groupDim) * groupDim; kernel( stream, (gridDim, groupDim), view, histogram, lengthInformation); }); }
/// <summary> /// The actual unique kernel implementation. /// </summary> /// <typeparam name="T">The element type.</typeparam> /// <typeparam name="TComparisonOperation">The comparison operation.</typeparam> /// <param name="input">The input view.</param> /// <param name="output">The output view to store the new length.</param> /// <param name="sequentialGroupExecutor"> /// The sequential group executor to use. /// </param> /// <param name="tileSize">The tile size.</param> /// <param name="numIterationsPerGroup"> /// The number of iterations per group. /// </param> internal static void UniqueKernel <T, TComparisonOperation>( ArrayView <T> input, ArrayView <long> output, SequentialGroupExecutor sequentialGroupExecutor, SpecializedValue <int> tileSize, Index1D numIterationsPerGroup) where T : unmanaged where TComparisonOperation : struct, IComparisonOperation <T> { TComparisonOperation comparison = default; var isFirstGrid = Grid.IdxX == 0; var tileInfo = new TileInfo(input.IntLength, numIterationsPerGroup); // Sync groups and wait for the current one to become active sequentialGroupExecutor.Wait(); var temp = SharedMemory.Allocate <bool>(tileSize); var startIdx = Grid.ComputeGlobalIndex(Grid.IdxX, 0); for ( int i = tileInfo.StartIndex; i < tileInfo.MaxLength; i += Group.DimX) { if (Group.IsFirstThread && i == tileInfo.StartIndex && isFirstGrid) { temp[0] = true; } else { var currIdx = i; var prevIdx = Group.IsFirstThread && i == tileInfo.StartIndex ? output[0] - 1 : currIdx - 1; temp[currIdx - startIdx] = comparison.Compare(input[currIdx], input[prevIdx]) != 0; } } Group.Barrier(); if (Group.IsFirstThread) { var offset = isFirstGrid ? 0 : output[0]; var maxLength = XMath.Min(startIdx + temp.IntLength, tileInfo.MaxLength) - startIdx; for (var i = 0; i < maxLength; i++) { if (temp[i]) { input[offset++] = input[startIdx + i]; } } output[0] = offset; } MemoryFence.DeviceLevel(); Group.Barrier(); sequentialGroupExecutor.Release(); }
/// <summary> /// Creates a kernel to calculate the histogram on a supplied view. /// </summary> /// <typeparam name="T">The input view element type.</typeparam> /// <typeparam name="TIndex">The input view index type.</typeparam> /// <typeparam name="TBinType">The histogram bin type.</typeparam> /// <typeparam name="TIncrementor"> /// The operation to increment the value of the bin. /// </typeparam> /// <typeparam name="TLocator"> /// The operation to compute the bin location. /// </typeparam> /// <param name="accelerator">The accelerator.</param> /// <returns>The created histogram handler.</returns> public static Histogram <T, TIndex, TBinType> CreateHistogram < T, TIndex, TBinType, TIncrementor, TLocator>( this Accelerator accelerator) where T : unmanaged where TIndex : unmanaged, IIndex, IGenericIndex <TIndex> where TBinType : unmanaged where TIncrementor : struct, IIncrementOperation <TBinType> where TLocator : struct, IComputeMultiBinOperation <T, TBinType, TIncrementor> { var kernel = accelerator.LoadKernel < HistogramDelegate < T, TBinType, TIncrementor, TLocator> >( HistogramKernelMethod.MakeGenericMethod( typeof(T), typeof(TBinType), typeof(TIncrementor), typeof(TLocator))); return((stream, view, histogram, histogramOverflow) => { if (!view.IsValid) { throw new ArgumentNullException(nameof(view)); } if (view.Length < 1) { throw new ArgumentOutOfRangeException(nameof(view)); } if (!histogram.IsValid) { throw new ArgumentNullException(nameof(histogram)); } if (histogram.Length < 1) { throw new ArgumentOutOfRangeException(nameof(histogram)); } if (!histogramOverflow.IsValid) { throw new ArgumentNullException(nameof(histogramOverflow)); } if (histogramOverflow.Length < 1) { throw new ArgumentOutOfRangeException(nameof(histogramOverflow)); } if (view.Length > int.MaxValue || histogram.Length > int.MaxValue) { throw new NotSupportedException( ErrorMessages.NotSupportedArrayView64); } var input = view.AsLinearView(); var(gridDim, groupDim) = accelerator.ComputeGridStrideLoopExtent( input.Length, out int numIterationsPerGroup); int numVirtualGroups = gridDim * numIterationsPerGroup; int lengthInformation = XMath.DivRoundUp(input.Length, groupDim) * groupDim; kernel( stream, (gridDim, groupDim), input, histogram, histogramOverflow, lengthInformation); }); }