static */
| 181 | } |
| 182 | |
| 183 | /* static */ Maybe<void> CoinFlipOp::InferNdSbp(user_op::InferNdSbpFnContext* ctx) { |
| 184 | const Shape& hierarchy = ctx->parallel_hierarchy(); |
| 185 | NdSbp* output_dist = ctx->NdSbp4ArgNameAndIndex("out", 0); |
| 186 | // the input may be produced by tick which should be broadcast parallel dist |
| 187 | std::vector<NdSbp*> inputs_dist; |
| 188 | for (const auto& arg_pair : ctx->inputs()) { |
| 189 | inputs_dist.emplace_back(ctx->NdSbp4ArgNameAndIndex(arg_pair.first, arg_pair.second)); |
| 190 | } |
| 191 | const auto& dist_conf = ctx->user_op_conf().attr<std::vector<std::string>>("nd_sbp"); |
| 192 | if (dist_conf.size() == 0) { |
| 193 | FOR_RANGE(int, i, 0, hierarchy.NumAxes()) { |
| 194 | output_dist->add_sbp_parallel()->mutable_split_parallel()->set_axis(0); |
| 195 | for (auto* input_dist : inputs_dist) { |
| 196 | input_dist->add_sbp_parallel()->mutable_broadcast_parallel(); |
| 197 | } |
| 198 | } |
| 199 | } else { |
| 200 | CHECK_EQ_OR_RETURN(dist_conf.size(), hierarchy.NumAxes()); |
| 201 | for (const std::string& sbp_str : dist_conf) { |
| 202 | SbpParallel sbp_parallel; |
| 203 | CHECK_OR_RETURN(ParseSbpParallelFromString(sbp_str, &sbp_parallel)); |
| 204 | CHECK_OR_RETURN( |
| 205 | (sbp_parallel.has_split_parallel() && sbp_parallel.split_parallel().axis() == 0) |
| 206 | || sbp_parallel.has_broadcast_parallel()); |
| 207 | *output_dist->add_sbp_parallel() = sbp_parallel; |
| 208 | for (auto* input_dist : inputs_dist) { |
| 209 | input_dist->add_sbp_parallel()->mutable_broadcast_parallel(); |
| 210 | } |
| 211 | } |
| 212 | } |
| 213 | return Maybe<void>::Ok(); |
| 214 | } |
| 215 | |
| 216 | /* static */ Maybe<void> CoinFlipOp::InferDataType(user_op::InferContext* ctx) { |
| 217 | user_op::TensorDesc* out_tensor = ctx->MutOutputTensorDesc("out", 0); |
nothing calls this directly
no test coverage detected