| 33 | |
| 34 | template<class InputIterator, class OutputIterator, class BinaryFunction> |
| 35 | size_t reduce(InputIterator first, |
| 36 | size_t count, |
| 37 | OutputIterator result, |
| 38 | size_t block_size, |
| 39 | BinaryFunction function, |
| 40 | command_queue &queue) |
| 41 | { |
| 42 | typedef typename |
| 43 | std::iterator_traits<InputIterator>::value_type |
| 44 | input_type; |
| 45 | typedef typename |
| 46 | boost::compute::result_of<BinaryFunction(input_type, input_type)>::type |
| 47 | result_type; |
| 48 | |
| 49 | const context &context = queue.get_context(); |
| 50 | size_t block_count = count / 2 / block_size; |
| 51 | size_t total_block_count = |
| 52 | static_cast<size_t>(std::ceil(float(count) / 2.f / float(block_size))); |
| 53 | |
| 54 | if(block_count != 0){ |
| 55 | meta_kernel k("block_reduce"); |
| 56 | size_t output_arg = k.add_arg<result_type *>(memory_object::global_memory, "output"); |
| 57 | size_t block_arg = k.add_arg<input_type *>(memory_object::local_memory, "block"); |
| 58 | |
| 59 | k << |
| 60 | "const uint gid = get_global_id(0);\n" << |
| 61 | "const uint lid = get_local_id(0);\n" << |
| 62 | |
| 63 | // copy values to local memory |
| 64 | "block[lid] = " << |
| 65 | function(first[k.make_var<uint_>("gid*2+0")], |
| 66 | first[k.make_var<uint_>("gid*2+1")]) << ";\n" << |
| 67 | |
| 68 | // perform reduction |
| 69 | "for(uint i = 1; i < " << uint_(block_size) << "; i <<= 1){\n" << |
| 70 | " barrier(CLK_LOCAL_MEM_FENCE);\n" << |
| 71 | " uint mask = (i << 1) - 1;\n" << |
| 72 | " if((lid & mask) == 0){\n" << |
| 73 | " block[lid] = " << |
| 74 | function(k.expr<input_type>("block[lid]"), |
| 75 | k.expr<input_type>("block[lid+i]")) << ";\n" << |
| 76 | " }\n" << |
| 77 | "}\n" << |
| 78 | |
| 79 | // write block result to global output |
| 80 | "if(lid == 0)\n" << |
| 81 | " output[get_group_id(0)] = block[0];\n"; |
| 82 | |
| 83 | kernel kernel = k.compile(context); |
| 84 | kernel.set_arg(output_arg, result.get_buffer()); |
| 85 | kernel.set_arg(block_arg, local_buffer<input_type>(block_size)); |
| 86 | |
| 87 | queue.enqueue_1d_range_kernel(kernel, |
| 88 | 0, |
| 89 | block_count * block_size, |
| 90 | block_size); |
| 91 | } |
| 92 | |