| 27 | |
| 28 | private: |
| 29 | void Compute(user_op::KernelComputeContext* ctx) const override { |
| 30 | const user_op::Tensor* in = ctx->Tensor4ArgNameAndIndex("in", 0); |
| 31 | user_op::Tensor* out = ctx->Tensor4ArgNameAndIndex("out", 0); |
| 32 | |
| 33 | const int32_t elem_cnt = in->shape_view().elem_cnt(); |
| 34 | CHECK_GE(elem_cnt, 0); |
| 35 | if (elem_cnt == 0) { return; } |
| 36 | |
| 37 | const T* in_ptr = in->dptr<T>(); |
| 38 | int64_t* out_ptr = out->mut_dptr<int64_t>(); |
| 39 | |
| 40 | const int64_t instance_size = in->shape_view().At(in->shape_view().NumAxes() - 1); |
| 41 | const int64_t instance_num = elem_cnt / instance_size; |
| 42 | const int64_t num_thread = |
| 43 | std::min(instance_num, (int64_t)Singleton<ThreadPool>::Get()->thread_num()); |
| 44 | const BalancedSplitter bs(instance_num, num_thread); |
| 45 | BlockingCounter bc(num_thread); |
| 46 | FOR_RANGE(int64_t, thread_id, 0, num_thread) { |
| 47 | const Range range = bs.At(thread_id); |
| 48 | Singleton<ThreadPool>::Get()->AddWork([=, &bc]() { |
| 49 | FOR_RANGE(int64_t, i, range.begin(), range.end()) { |
| 50 | const T* in_ptr_i = in_ptr + i * instance_size; |
| 51 | out_ptr[i] = |
| 52 | std::distance(in_ptr_i, std::max_element(in_ptr_i, in_ptr_i + instance_size)); |
| 53 | } |
| 54 | bc.Decrease(); |
| 55 | }); |
| 56 | } |
| 57 | bc.WaitForeverUntilCntEqualZero(); |
| 58 | } |
| 59 | bool AlwaysComputeWhenAllOutputsEmpty() const override { return false; } |
| 60 | }; |
| 61 |
nothing calls this directly
no test coverage detected