| 32 | |
| 33 | private: |
| 34 | void Compute(user_op::KernelComputeContext* ctx) const override { |
| 35 | const user_op::Tensor* in = ctx->Tensor4ArgNameAndIndex("input", 0); |
| 36 | const int64_t num_axes = in->shape_view().NumAxes(); |
| 37 | const int64_t size = in->shape_view().elem_cnt(); |
| 38 | if (size == 0) return; |
| 39 | const int64_t stride = in->shape_view().At(num_axes - 1); |
| 40 | const int64_t instance_num = size / stride; |
| 41 | user_op::Tensor* values = ctx->Tensor4ArgNameAndIndex("values", 0); |
| 42 | user_op::Tensor* indices = ctx->Tensor4ArgNameAndIndex("indices", 0); |
| 43 | user_op::Tensor* tmp_buffer = ctx->Tensor4ArgNameAndIndex("tmp_buffer", 0); |
| 44 | |
| 45 | auto memcpy = NewMemcpyPrimitive(ctx); |
| 46 | CHECK(memcpy); |
| 47 | memcpy->Launch(ctx->stream(), tmp_buffer->mut_dptr<void>(), in->dptr<void>(), size * sizeof(T)); |
| 48 | const int64_t thread_num = |
| 49 | std::min(instance_num, (int64_t)Singleton<ThreadPool>::Get()->thread_num()); |
| 50 | const BalancedSplitter bs(instance_num, thread_num); |
| 51 | BlockingCounter bc(thread_num); |
| 52 | FOR_RANGE(int64_t, thread_id, 0, thread_num) { |
| 53 | const Range range = bs.At(thread_id); |
| 54 | Singleton<ThreadPool>::Get()->AddWork([=, &bc]() { |
| 55 | FOR_RANGE(int64_t, i, range.begin(), range.end()) { |
| 56 | T* in_ptr = tmp_buffer->mut_dptr<T>() + i * stride; |
| 57 | T* val_ptr = values->mut_dptr<T>() + i; |
| 58 | int64_t* ind_ptr = indices->mut_dptr<int64_t>() + i; |
| 59 | std::vector<std::pair<T, int64_t>> elements(stride); |
| 60 | T mode = 0; |
| 61 | int64_t mode_idx = 0; |
| 62 | int64_t temp_freq = 0; |
| 63 | int64_t max_freq = 0; |
| 64 | FOR_RANGE(int64_t, idx, 0, stride) { |
| 65 | elements[idx] = std::make_pair(*(in_ptr + idx), idx); |
| 66 | } |
| 67 | std::sort(elements.begin(), elements.end(), |
| 68 | [=](const auto& i, const auto& j) { return i.first < j.first; }); |
| 69 | FOR_RANGE(int64_t, idx, 0, stride) { |
| 70 | temp_freq++; |
| 71 | if ((idx == stride - 1) || (elements[idx].first != elements[idx + 1].first)) { |
| 72 | if (temp_freq > max_freq) { |
| 73 | mode = elements[idx].first; |
| 74 | mode_idx = elements[idx].second; |
| 75 | max_freq = temp_freq; |
| 76 | } |
| 77 | temp_freq = 0; |
| 78 | } |
| 79 | } |
| 80 | *val_ptr = mode; |
| 81 | *ind_ptr = mode_idx; |
| 82 | } |
| 83 | bc.Decrease(); |
| 84 | }); |
| 85 | } |
| 86 | bc.WaitForeverUntilCntEqualZero(); |
| 87 | } |
| 88 | bool AlwaysComputeWhenAllOutputsEmpty() const override { return false; } |
| 89 | }; |
| 90 |
nothing calls this directly
no test coverage detected