Median selection in CUDA kernel

2020-05-29 06:10发布

问题:

I need to compute the median of an array of size p inside a CUDA kernel (in my case, p is small e.g. p = 10). I am using an O(p^2) algorithm for its simplicity, but at the cost of time performance.

Is there a "function" to find the median efficiently that I can call inside a CUDA kernel?

I know I could implement a selection algorithm, but I'm looking for a function and/or tested code.

Thanks!

回答1:

Here are a few hints:

  1. Use a better selection algorithm: QuickSelect is a faster version of QuickSort for selecting the kth element in an array. For compile-time-constant mask sizes, sorting networks are even faster, thanks to high TLP and a O(log^2 n) critical path. If you only have 8-bit values, you can use a histogram-based approach. This paper describes an implementation that takes constant time per pixel, independent of mask size, which makes it very fast for very large mask sizes. You can parallelize it by using a minimal launch strategy (only run as many threads as you need to keep all SMs at max capacity), tiling the image, and letting threads of the same block cooperate on each kernel histogram.
  2. Sort in registers. For small mask sizes, you can keep the entire array in registers, making median selection with a sorting network much faster. For larger mask sizes, you can use shared memory.
  3. Copy all pixels used by the block to shared memory first, and then copy to thread-local buffers that are also in shared memory.
  4. If you only have a few masks that need to go really fast (such as 3x3 and 5x5), use templates to make them compile time constants. This can speed things up a lot because the compiler can unroll loops and re-order a lot more instructions, possibly improving load batching and other goodies, leading to large speed-ups.
  5. Make sure, your reads are coalesced and aligned.

There are many other optimizations you can do. Make sure, you read through the CUDA documents, especially the Programming Guide and the Best Practices Guide. When you really want to gun for high performance, don't forget to take a good look at a CUDA profiler, such as the Visual Profiler.



回答2:

Even in a single thread one can sort the array and pick the value in the middle in O(p*log(p)), which makes O(p^2) look excessive. If you have p threads at your disposal it's also possible to sort the array as fast as O(log(p)), although that may not be the fastest solution for small p. See the top answer here:

Which parallel sorting algorithm has the best average case performance?