| 221 | template <typename T, typename Index, typename InitialValueF, |
| 222 | typename EmptySegmentValueF, typename ReductionF> |
| 223 | void SegmentReductionFunctor< |
| 224 | T, Index, InitialValueF, EmptySegmentValueF, |
| 225 | ReductionF>::operator()(OpKernelContext* ctx, const GPUDevice& d, |
| 226 | const Index output_rows, |
| 227 | const TensorShape& segment_ids_shape, bool is_mean, |
| 228 | typename TTypes<Index>::ConstFlat segment_ids, |
| 229 | const Index data_size, const T* data, |
| 230 | typename TTypes<T, 2>::Tensor output) { |
| 231 | if (output.size() == 0) { |
| 232 | return; |
| 233 | } |
| 234 | |
| 235 | // Launch kernel(s) to compute sorted segment reduction. |
| 236 | // Notes: |
| 237 | // *) 'input_total_size' is the total number of elements to process. |
| 238 | // *) 'segment_ids.shape' is a prefix of data's shape. |
| 239 | // *) 'input_outer_dim_size' is the total number of segments to process. |
| 240 | const Index input_total_size = data_size; |
| 241 | const Index input_outer_dim_size = segment_ids.dimension(0); |
| 242 | const Index input_inner_dim_size = input_total_size / input_outer_dim_size; |
| 243 | const Index num_segments = output.size() / input_inner_dim_size; |
| 244 | |
| 245 | // Set 'output' to initial value. |
| 246 | GpuLaunchConfig config = GetGpuLaunchConfig(output.size(), d); |
| 247 | const T initial_value = InitialValueF()(); |
| 248 | TF_CHECK_OK(GpuLaunchKernel(SetToValue<T>, config.block_count, |
| 249 | config.thread_per_block, 0, d.stream(), |
| 250 | output.size(), output.data(), initial_value)); |
| 251 | if (data_size == 0 || segment_ids_shape.num_elements() == 0) { |
| 252 | return; |
| 253 | } |
| 254 | |
| 255 | const int OuterDimTileSize = 8; |
| 256 | |
| 257 | const Index input_outer_dim_num_stripe = |
| 258 | Eigen::divup(input_outer_dim_size, Index(OuterDimTileSize)); |
| 259 | |
| 260 | const Index total_stripe_count = |
| 261 | input_inner_dim_size * input_outer_dim_num_stripe; |
| 262 | |
| 263 | config = GetGpuLaunchConfig(total_stripe_count, d); |
| 264 | TF_CHECK_OK(GpuLaunchKernel( |
| 265 | SortedSegmentReductionCustomKernel< |
| 266 | T, Index, OuterDimTileSize, |
| 267 | typename ReduceUpdateOpFor<ReductionF>::nonatomic_op, |
| 268 | typename ReduceUpdateOpFor<ReductionF>::atomic_op>, |
| 269 | config.block_count, config.thread_per_block, 0, d.stream(), |
| 270 | input_outer_dim_size, input_inner_dim_size, output_rows, |
| 271 | segment_ids.data(), data, output.data(), total_stripe_count, |
| 272 | initial_value)); |
| 273 | |
| 274 | const T empty_value = EmptySegmentValueF()(); |
| 275 | if (is_mean || initial_value != empty_value) { |
| 276 | Tensor segment_offsets; |
| 277 | OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum<Index>::value, |
| 278 | TensorShape({num_segments + 1}), |
| 279 | &segment_offsets)); |
| 280 | Index* segment_offsets_ptr = segment_offsets.flat<Index>().data(); |
nothing calls this directly
no test coverage detected