• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020-2021 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "backend/kernel_compiler/akg/akg_kernel_json_generator.h"
18 
19 #ifdef ENABLE_GPU
20 #include <cuda.h>
21 #endif
22 #include "backend/kernel_compiler/akg/akg_kernel_attrs_process.h"
23 #include "backend/kernel_compiler/common_utils.h"
24 #include "backend/kernel_compiler/oplib/oplib.h"
25 #include "backend/session/anf_runtime_algorithm.h"
26 
27 namespace mindspore {
28 namespace kernel {
29 namespace {
GetDynInputSize(const AnfNodePtr & anf_node)30 std::vector<int> GetDynInputSize(const AnfNodePtr &anf_node) {
31   std::vector<int> dyn_input_sizes;
32   auto primitive = AnfAlgo::GetCNodePrimitive(anf_node);
33   MS_EXCEPTION_IF_NULL(primitive);
34   if (primitive->HasAttr(kAttrDynInputSizes)) {
35     std::vector<int64_t> dyn_input_sizes_me =
36       GetValue<const std::vector<int64_t>>(primitive->GetAttr(kAttrDynInputSizes));
37     (void)std::transform(dyn_input_sizes_me.begin(), dyn_input_sizes_me.end(), std::back_inserter(dyn_input_sizes),
38                          [](const int64_t &value) { return static_cast<int>(value); });
39   }
40   return dyn_input_sizes;
41 }
42 
43 class OpInfoExtractor {
44  public:
45   OpInfoExtractor() = default;
46   ~OpInfoExtractor() = default;
Run(const AnfNodePtr & anf_node)47   OpInfoPtr Run(const AnfNodePtr &anf_node) {
48     MS_EXCEPTION_IF_NULL(anf_node);
49     cnode_ = anf_node->cast<CNodePtr>();
50     MS_EXCEPTION_IF_NULL(cnode_);
51     auto op_info = std::make_shared<OpInfo>();
52     op_info->set_op_name(AnfAlgo::GetCNodeName(cnode_));
53     op_info->set_imply_type(OpImplyType::kAKG);
54     ExtractInputs(op_info);
55     ExtractOutputs(op_info);
56     ExtractAttrs(op_info);
57     return op_info;
58   }
59 
60  private:
ExtractInputs(const OpInfoPtr & op_info) const61   void ExtractInputs(const OpInfoPtr &op_info) const {
62     auto dyn_input_sizes = GetDynInputSize(cnode_);
63     if (dyn_input_sizes.empty()) {
64       for (size_t i = 1; i < cnode_->size(); i++) {
65         auto io_info = std::make_shared<OpIOInfo>();
66         io_info->set_name("input_" + std::to_string(i - 1));
67         op_info->add_inputs_ptr(io_info);
68       }
69     } else {
70       for (size_t i = 0; i < dyn_input_sizes.size(); i++) {
71         auto io_info = std::make_shared<OpIOInfo>();
72         io_info->set_name("input_" + std::to_string(i));
73         io_info->set_param_type("dynamic");
74         op_info->add_inputs_ptr(io_info);
75       }
76     }
77   }
78 
ExtractOutputs(const OpInfoPtr & op_info) const79   void ExtractOutputs(const OpInfoPtr &op_info) const {
80     size_t output_tensor_num = AnfAlgo::GetOutputTensorNum(cnode_);
81     for (size_t i = 0; i < output_tensor_num; i++) {
82       auto io_info = std::make_shared<OpIOInfo>();
83       io_info->set_name("output_" + std::to_string(i));
84       op_info->add_outputs_ptr(io_info);
85     }
86   }
87 
ExcludeAttr(const std::string & name) const88   bool ExcludeAttr(const std::string &name) const {
89     const std::set<std::string> black_list = {"IsFeatureMapInputList", "IsFeatureMapOutput", kAttrOutputNames,
90                                               kAttrInputNames};
91     return black_list.count(name) != 0;
92   }
93 
ExtractAttrs(const OpInfoPtr & op_info)94   void ExtractAttrs(const OpInfoPtr &op_info) {
95     auto prim = GetCNodePrimitive(cnode_);
96     if (prim == nullptr) return;
97     for (const auto &[name, v] : prim->attrs()) {
98       if (ExcludeAttr(name)) continue;
99       auto op_attr = std::make_shared<OpAttr>();
100       op_attr->set_name(name);
101       op_attr->set_param_type("required");
102       // Only support the following types in op json.
103       if (v->isa<Int32Imm>() || v->isa<Int64Imm>()) {
104         op_attr->set_type("int");
105       } else if (v->isa<FP32Imm>() || v->isa<FP64Imm>()) {
106         op_attr->set_type("float");
107       } else if (v->isa<BoolImm>()) {
108         op_attr->set_type("bool");
109       } else if (v->isa<StringImm>()) {
110         op_attr->set_type("str");
111       } else if (v->isa<ValueSequeue>()) {
112         const auto &vec = v->cast<ValueSequeuePtr>()->value();
113         if (vec.empty()) {
114           op_attr->set_type("listInt");
115         } else if (vec[0]->isa<Int32Imm>() || vec[0]->isa<Int64Imm>()) {
116           op_attr->set_type("listInt");
117         } else if (vec[0]->isa<StringImm>()) {
118           op_attr->set_type("listStr");
119         }
120       }
121       if (op_attr->type().empty()) {
122         MS_LOG(DEBUG) << "Unknown type, ignore attr " << name;
123         continue;
124       }
125       op_info->add_attrs_ptr(op_attr);
126     }
127   }
128 
129   CNodePtr cnode_;
130 };
131 }  // namespace
132 
133 int AkgKernelJsonGenerator::op_cnt_ = 0;
134 std::mutex AkgKernelJsonGenerator::op_cnt_mtx_;
135 
GetOpCntInc()136 int AkgKernelJsonGenerator::GetOpCntInc() {
137   op_cnt_mtx_.lock();
138   int cnt = op_cnt_++;
139   op_cnt_mtx_.unlock();
140   return cnt;
141 }
142 
GetInputDataType(const AnfNodePtr & anf_node,size_t real_index) const143 TypeId AkgKernelJsonGenerator::GetInputDataType(const AnfNodePtr &anf_node, size_t real_index) const {
144   return dump_option_.is_before_select_kernel ? AnfAlgo::GetPrevNodeOutputInferDataType(anf_node, real_index)
145                                               : AnfAlgo::GetInputDeviceDataType(anf_node, real_index);
146 }
147 
GetInputShape(const AnfNodePtr & anf_node,size_t real_index) const148 std::vector<size_t> AkgKernelJsonGenerator::GetInputShape(const AnfNodePtr &anf_node, size_t real_index) const {
149   return dump_option_.is_before_select_kernel ? AnfAlgo::GetPrevNodeOutputInferShape(anf_node, real_index)
150                                               : AnfAlgo::GetInputDeviceShape(anf_node, real_index);
151 }
152 
GetInputFormat(const AnfNodePtr & anf_node,size_t real_index) const153 std::string AkgKernelJsonGenerator::GetInputFormat(const AnfNodePtr &anf_node, size_t real_index) const {
154   return dump_option_.is_before_select_kernel ? kOpFormat_DEFAULT : AnfAlgo::GetInputFormat(anf_node, real_index);
155 }
156 
GetOutputDataType(const AnfNodePtr & anf_node,size_t index) const157 TypeId AkgKernelJsonGenerator::GetOutputDataType(const AnfNodePtr &anf_node, size_t index) const {
158   return dump_option_.is_before_select_kernel ? AnfAlgo::GetOutputInferDataType(anf_node, index)
159                                               : AnfAlgo::GetOutputDeviceDataType(anf_node, index);
160 }
161 
GetOutputShape(const AnfNodePtr & anf_node,size_t index) const162 std::vector<size_t> AkgKernelJsonGenerator::GetOutputShape(const AnfNodePtr &anf_node, size_t index) const {
163   return dump_option_.is_before_select_kernel ? AnfAlgo::GetOutputInferShape(anf_node, index)
164                                               : AnfAlgo::GetOutputDeviceShape(anf_node, index);
165 }
166 
GetOutputFormat(const AnfNodePtr & anf_node,size_t index) const167 std::string AkgKernelJsonGenerator::GetOutputFormat(const AnfNodePtr &anf_node, size_t index) const {
168   return dump_option_.is_before_select_kernel ? kOpFormat_DEFAULT : AnfAlgo::GetOutputFormat(anf_node, index);
169 }
170 
CreateInputDescJson(const AnfNodePtr & anf_node,const OpInfoPtr & op_info,nlohmann::json * inputs_json)171 bool AkgKernelJsonGenerator::CreateInputDescJson(const AnfNodePtr &anf_node, const OpInfoPtr &op_info,
172                                                  nlohmann::json *inputs_json) {
173   // for dynamic input number, dyn_input_sizes has the info of dynamic input num for each input.
174   auto inputs_ptr = op_info->inputs_ptr();
175   if (inputs_ptr.empty()) {
176     MS_LOG(ERROR) << "Kernel [" << anf_node->fullname_with_scope() << "] info has no input info";
177     return false;
178   }
179 
180   // for dynamic input number, dyn_input_sizes has the info of dynamic input num for each input.
181   auto dyn_input_sizes = GetDynInputSize(anf_node);
182   size_t real_input_index = 0;
183   for (size_t i = 0; i < inputs_ptr.size(); i++) {
184     auto input_ptr = inputs_ptr[i];
185     if (input_ptr == nullptr) {
186       MS_LOG(ERROR) << "Kernel [" << anf_node->fullname_with_scope() << "] input[" << i << "] is nullptr";
187       return false;
188     }
189 
190     size_t input_tensor_num = dyn_input_sizes.empty() ? 1 : IntToSize(dyn_input_sizes[i]);
191     std::vector<nlohmann::json> input_list;
192     for (size_t input_i = 0; input_i < input_tensor_num; input_i++) {
193       auto type_id = this->GetInputDataType(anf_node, real_input_index);
194       std::string dtype = TypeId2String(type_id, dump_option_.is_before_select_kernel);
195       if (dtype.empty()) {
196         MS_LOG(ERROR) << "Op [" << anf_node->fullname_with_scope() << "] input [" << real_input_index
197                       << "] data type is null. ";
198         return false;
199       }
200       nlohmann::json input_desc_json;
201       input_desc_json[kJsonKeyDataType] = dtype;
202       input_desc_json[kJsonKeyFormat] = this->GetInputFormat(anf_node, real_input_index);
203       input_desc_json[kJsonKeyName] = input_ptr->name();
204       input_desc_json[kJsonKeyTensorName] = "input_" + std::to_string(GetInputTensorIdxInc(anf_node, real_input_index));
205       auto input_shape = this->GetInputShape(anf_node, real_input_index);
206       if (!is_basic_op_ && GetInputTensorValue(anf_node, real_input_index, &input_desc_json)) {
207         MS_LOG(DEBUG) << "Take input[" << real_input_index << "] of [" << anf_node->DebugString(2)
208                       << "] as const tensor, shape: [" << Vector2Str(input_shape)
209                       << "], value: " << input_desc_json[kJsonKeyValue];
210         input_shape.clear();
211       }
212       if (input_shape.empty()) {
213         input_shape.push_back(1);
214       }
215       input_desc_json[kJsonKeyShape] = input_shape;
216       input_list.emplace_back(input_desc_json);
217       real_input_index++;
218     }
219     inputs_json->emplace_back(input_list);
220   }
221   return true;
222 }
223 
CreateOutputDescJson(const AnfNodePtr & anf_node,const OpInfoPtr & op_info,nlohmann::json * outputs_json)224 bool AkgKernelJsonGenerator::CreateOutputDescJson(const AnfNodePtr &anf_node, const OpInfoPtr &op_info,
225                                                   nlohmann::json *outputs_json) {
226   MS_EXCEPTION_IF_NULL(anf_node);
227   MS_EXCEPTION_IF_NULL(op_info);
228   MS_EXCEPTION_IF_NULL(outputs_json);
229   size_t output_tensor_num = AnfAlgo::GetOutputTensorNum(anf_node);
230 
231   auto outputs = op_info->outputs_ptr();
232   for (size_t i = 0; i < output_tensor_num; i++) {
233     nlohmann::json output_json;
234     auto type_id = this->GetOutputDataType(anf_node, i);
235     std::string dtype = TypeId2String(type_id, dump_option_.is_before_select_kernel);
236     if (dtype.empty()) {
237       MS_LOG(ERROR) << "Op [" << anf_node->fullname_with_scope() << "] output [" << i << "] data type is null. ";
238       return false;
239     }
240 
241     std::string output_name = outputs[i]->name();
242     output_json[kJsonKeyDataType] = dtype;
243     output_json[kJsonKeyFormat] = this->GetOutputFormat(anf_node, i);
244     output_json[kJsonKeyName] = output_name;
245     output_json[kJsonKeyTensorName] = "output_" + std::to_string(i) + "_" + std::to_string(GetOutputTensorIdxInc());
246     auto output_shape = this->GetOutputShape(anf_node, i);
247     if (output_shape.empty()) {
248       output_shape.push_back(1);
249     }
250     output_json[kJsonKeyShape] = output_shape;
251     outputs_json->push_back(output_json);
252   }
253   return true;
254 }
255 
GetAttrJson(const AnfNodePtr & anf_node,const std::vector<int> & dyn_input_sizes,const OpAttrPtr & op_attr,nlohmann::json * attr_json,const ValuePtr & attr_value)256 void AkgKernelJsonGenerator::GetAttrJson(const AnfNodePtr &anf_node, const std::vector<int> &dyn_input_sizes,
257                                          const OpAttrPtr &op_attr, nlohmann::json *attr_json,
258                                          const ValuePtr &attr_value) {
259   MS_EXCEPTION_IF_NULL(anf_node);
260   MS_EXCEPTION_IF_NULL(op_attr);
261   MS_EXCEPTION_IF_NULL(attr_json);
262 
263   auto get_int_value = [](const ValuePtr &value) -> int {
264     return value->isa<Int64Imm>() ? static_cast<int>(GetValue<int64_t>(value)) : GetValue<int>(value);
265   };
266   std::string type = op_attr->type();
267   (*attr_json)[kJsonKeyDataType] = type;
268   if (type == "int") {
269     (*attr_json)[kJsonKeyValue] = get_int_value(attr_value);
270   } else if (type == "str") {
271     (*attr_json)[kJsonKeyValue] = GetValue<std::string>(attr_value);
272   } else if (type == "bool") {
273     (*attr_json)[kJsonKeyValue] = GetValue<bool>(attr_value);
274   } else if (type == "float") {
275     (*attr_json)[kJsonKeyValue] = GetValue<float>(attr_value);
276   } else if (type == "listInt") {
277     std::vector<int> list_int;
278     const auto &vals = attr_value->cast<ValueSequeuePtr>()->value();
279     (void)std::transform(vals.begin(), vals.end(), std::back_inserter(list_int), get_int_value);
280     (*attr_json)[kJsonKeyValue] = list_int;
281   } else if (type == "listStr") {
282     std::vector<std::string> data_format;
283     if (op_attr->name() == kArgDataformat) {
284       size_t tensor_args_num = !dyn_input_sizes.empty() ? dyn_input_sizes.size() : AnfAlgo::GetInputTensorNum(anf_node);
285       for (size_t format_i = 0; format_i < tensor_args_num; format_i++) {
286         auto input_format = this->GetInputFormat(anf_node, format_i);
287         data_format.push_back(input_format);
288       }
289     } else {
290       data_format = GetValue<std::vector<std::string>>(attr_value);
291     }
292     (*attr_json)[kJsonKeyValue] = data_format;
293   } else {
294     MS_LOG(WARNING) << "No valid json value for attr type: " << type;
295   }
296 }
297 
CreateAttrDescJson(const AnfNodePtr & anf_node,const OpInfoPtr & op_info,nlohmann::json * attrs_json)298 bool AkgKernelJsonGenerator::CreateAttrDescJson(const AnfNodePtr &anf_node, const OpInfoPtr &op_info,
299                                                 nlohmann::json *attrs_json) {
300   auto attrs = op_info->attrs_ptr();
301   if (attrs.empty()) {
302     MS_LOG(DEBUG) << "Apply kernel [" << anf_node->fullname_with_scope() << "] op info attrs is empty";
303     return true;
304   }
305   auto dyn_input_sizes = GetDynInputSize(anf_node);
306   auto primitive = AnfAlgo::GetCNodePrimitive(anf_node);
307 
308   // create input name list for "x_shape" in attr with "x" in primitive.
309   auto inputs = op_info->inputs_ptr();
310   std::map<std::string, size_t> op_info_shape_name;
311   for (size_t i = 0; i < inputs.size(); i++) {
312     op_info_shape_name[inputs[i]->name() + "_shape"] = i;
313   }
314 
315   for (const auto &op_attr : attrs) {
316     nlohmann::json attr_json;
317     ValuePtr attr_value = primitive->GetAttr(op_attr->name());
318     if (attr_value == nullptr && op_attr->name() != kArgDataformat) {
319       if (op_attr->param_type() != "required") continue;
320       // match "x_shape" in attr with "x" in primitive.
321       auto find_item = op_info_shape_name.find(op_attr->name());
322       if (find_item != op_info_shape_name.end()) {
323         if (!dyn_input_sizes.empty()) {
324           if (find_item->second >= dyn_input_sizes.size() - 1) {
325             MS_LOG(EXCEPTION) << "dyn_input_sizes list index:" << find_item->second
326                               << " is out of range:" << dyn_input_sizes.size() - 1 << ".";
327             return false;
328           }
329           size_t tensor_idx = IntToSize(std::accumulate(&dyn_input_sizes[0], &dyn_input_sizes[find_item->second], 0));
330           for (int input_i = 0; input_i < dyn_input_sizes[find_item->second]; input_i++) {
331             attr_json[kJsonKeyValue] = AnfAlgo::GetPrevNodeOutputInferShape(anf_node, tensor_idx);
332             attr_json[kJsonKeyName] = op_attr->name();
333             attrs_json->push_back(attr_json);
334             tensor_idx++;
335           }
336         } else {
337           attr_json[kJsonKeyValue] = AnfAlgo::GetPrevNodeOutputInferShape(anf_node, find_item->second);
338           attr_json[kJsonKeyName] = op_attr->name();
339           attrs_json->push_back(attr_json);
340         }
341       } else {
342         MS_LOG(ERROR) << "op [" << anf_node->fullname_with_scope() << "] should have attr :" << op_attr->name();
343         return false;
344       }
345     } else {
346       GetAttrJson(anf_node, dyn_input_sizes, op_attr, &attr_json, attr_value);
347       attr_json[kJsonKeyName] = op_attr->name();
348       attrs_json->push_back(attr_json);
349     }
350   }
351   return true;
352 }
353 
GetInputTensorIdxInc(const AnfNodePtr & anf_node,size_t input_idx)354 size_t AkgKernelJsonGenerator::GetInputTensorIdxInc(const AnfNodePtr &anf_node, size_t input_idx) {
355   MS_EXCEPTION_IF_NULL(anf_node);
356   auto cnode = anf_node->cast<CNodePtr>();
357   MS_EXCEPTION_IF_NULL(cnode);
358   if (input_idx + 1 >= cnode->inputs().size()) {
359     MS_EXCEPTION(ArgumentError) << "input_idx [" << input_idx << "] is out of index of inputs of ["
360                                 << cnode->inputs().size() - 1 << "][" << cnode->DebugString() << "]";
361   }
362 
363   auto input_node = cnode->input(input_idx + 1);
364   if (input_tensor_idx_.find(input_node) == input_tensor_idx_.end()) {
365     size_t index = input_tensor_idx_.size();
366     input_tensor_idx_[input_node] = index;
367   }
368 
369   return input_tensor_idx_[input_node];
370 }
371 
GetOutputTensorIdxInc()372 size_t AkgKernelJsonGenerator::GetOutputTensorIdxInc() {
373   size_t idx = output_tensor_idx_++;
374   return idx;
375 }
376 
GetTensorName(const nlohmann::json & node_json,const std::string & tag,const std::pair<size_t,size_t> & position) const377 std::string AkgKernelJsonGenerator::GetTensorName(const nlohmann::json &node_json, const std::string &tag,
378                                                   const std::pair<size_t, size_t> &position) const {
379   if (node_json.count(tag) == 0) {
380     MS_LOG(ERROR) << "Node [" << node_json.dump() << "] has no key [" << tag << "].";
381     return "";
382   }
383 
384   auto const &tag_desc = node_json[tag];
385   nlohmann::json first_index;
386   if (tag == kJsonKeyOutputDesc) {
387     first_index = tag_desc;
388   } else if (!tag_desc.is_array() || tag_desc.size() <= position.first) {
389     MS_LOG(ERROR) << "Node [" << tag_desc.dump() << "] has no enough value [" << position.first << "].";
390     return "";
391   } else {
392     first_index = tag_desc[position.first];
393   }
394 
395   if (!first_index.is_array() || first_index.size() <= position.second) {
396     MS_LOG(ERROR) << "Node [" << first_index.dump() << "] has no enough value [" << position.second << "].";
397     return "";
398   }
399   auto const &second_index = first_index[position.second];
400   if (second_index.count(kJsonKeyTensorName) == 0) {
401     MS_LOG(ERROR) << "Node [" << second_index.dump() << "] has no key [" << kJsonKeyTensorName << "].";
402     return "";
403   }
404 
405   return second_index[kJsonKeyTensorName];
406 }
407 
SetTensorName(const std::string & tag,const std::string & new_name,const std::pair<size_t,size_t> & position,nlohmann::json * node_json) const408 void AkgKernelJsonGenerator::SetTensorName(const std::string &tag, const std::string &new_name,
409                                            const std::pair<size_t, size_t> &position, nlohmann::json *node_json) const {
410   MS_EXCEPTION_IF_NULL(node_json);
411   if (node_json->count(tag) == 0) {
412     MS_LOG(ERROR) << "Node [" << node_json->dump() << "] has no key [" << tag << "].";
413     return;
414   }
415 
416   nlohmann::json *tag_desc = &((*node_json)[tag]);
417   nlohmann::json *first_index;
418   if (tag == kJsonKeyOutputDesc) {
419     first_index = tag_desc;
420   } else if (!tag_desc->is_array() || tag_desc->size() <= position.first) {
421     MS_LOG(ERROR) << "Node [" << tag_desc->dump() << "] has no enough value [" << position.first << "].";
422     return;
423   } else {
424     first_index = &((*tag_desc)[position.first]);
425   }
426 
427   if (!first_index->is_array() || first_index->size() <= position.second) {
428     MS_LOG(ERROR) << "Node [" << first_index->dump() << "] has no enough value [" << position.second << "].";
429     return;
430   }
431   nlohmann::json *second_index = &((*first_index)[position.second]);
432   if (second_index->count(kJsonKeyTensorName) == 0) {
433     MS_LOG(ERROR) << "Node [" << second_index->dump() << "] has no key [" << kJsonKeyTensorName << "].";
434     return;
435   }
436   (*second_index)[kJsonKeyTensorName] = new_name;
437   return;
438 }
439 
SaveNodeAddress(const AnfNodePtr & anf_node,nlohmann::json * node_json)440 void AkgKernelJsonGenerator::SaveNodeAddress(const AnfNodePtr &anf_node, nlohmann::json *node_json) {
441   if (dump_option_.save_ptr_address) {
442     std::ostringstream get_the_address;
443     get_the_address << anf_node.get();
444     auto address = get_the_address.str();
445     (*node_json)[kJsonKeyPtrAddress] = address;
446     address_node_map_[address] = anf_node;
447   }
448 }
449 
ExtractOpInfo(const AnfNodePtr & anf_node) const450 OpInfoPtr AkgKernelJsonGenerator::ExtractOpInfo(const AnfNodePtr &anf_node) const {
451   if (dump_option_.extract_opinfo_from_anfnode) {
452     return OpInfoExtractor().Run(anf_node);
453   } else {
454     return mindspore::kernel::OpLib::FindOp(AnfAlgo::GetCNodeName(anf_node), OpImplyType::kAKG);
455   }
456 }
457 
GenerateSingleKernelJson(const AnfNodePtr & anf_node,nlohmann::json * node_json)458 bool AkgKernelJsonGenerator::GenerateSingleKernelJson(const AnfNodePtr &anf_node, nlohmann::json *node_json) {
459   MS_EXCEPTION_IF_NULL(anf_node);
460   MS_EXCEPTION_IF_NULL(node_json);
461   OpInfoPtr op_info = ExtractOpInfo(anf_node);
462   MS_EXCEPTION_IF_NULL(op_info);
463 
464   // get basic params from currentNodeOpDesc
465   (*node_json)[kJsonKeyName] = op_info->op_name();
466   (*node_json)[kJsonKeyImplPath] = op_info->impl_path();
467   SaveNodeAddress(anf_node, node_json);
468 
469   // input desc
470   nlohmann::json inputs_json;
471   if (!CreateInputDescJson(anf_node, op_info, &inputs_json)) {
472     MS_LOG(ERROR) << "Create input desc json failed, op[" << anf_node->fullname_with_scope() << "].";
473     return false;
474   }
475   (*node_json)[kJsonKeyInputDesc] = inputs_json;
476   MS_LOG(DEBUG) << "Akg create input desc json success.";
477 
478   // output desc
479   nlohmann::json outputs_json;
480   if (!CreateOutputDescJson(anf_node, op_info, &outputs_json)) {
481     MS_LOG(ERROR) << "Create output desc json failed, op[" << anf_node->fullname_with_scope() << "].";
482     return false;
483   }
484   (*node_json)[kJsonKeyOutputDesc] = outputs_json;
485   MS_LOG(DEBUG) << "Akg create output desc json success.";
486 
487   // attribute desc
488   nlohmann::json attrs_json;
489   if (!CreateAttrDescJson(anf_node, op_info, &attrs_json)) {
490     MS_LOG(ERROR) << "Create attr desc json failed, op[" << anf_node->fullname_with_scope() << "].";
491     return false;
492   }
493   (*node_json)[kJsonKeyAttr] = attrs_json;
494   return true;
495 }
496 
GetIOSize(const nlohmann::json & node_json,std::vector<size_t> * input_size,std::vector<size_t> * output_size) const497 bool AkgKernelJsonGenerator::GetIOSize(const nlohmann::json &node_json, std::vector<size_t> *input_size,
498                                        std::vector<size_t> *output_size) const {
499   if (input_size == nullptr || output_size == nullptr) {
500     MS_LOG(ERROR) << "input size or output size is nullptr";
501     return false;
502   }
503   input_size->clear();
504   output_size->clear();
505 
506   for (size_t i = 0; i < node_json[kJsonKeyInputDesc].size(); i++) {
507     for (size_t m = 0; m < node_json[kJsonKeyInputDesc][i].size(); m++) {
508       std::string dtype = node_json[kJsonKeyInputDesc][i][m][kJsonKeyDataType];
509       size_t nbyte = GetDtypeNbyte(dtype);
510       size_t size_i =
511         std::accumulate(node_json[kJsonKeyInputDesc][i][m][kJsonKeyShape].begin(),
512                         node_json[kJsonKeyInputDesc][i][m][kJsonKeyShape].end(), nbyte, std::multiplies<size_t>());
513       input_size->push_back(size_i);
514     }
515   }
516 
517   for (size_t i = 0; i < node_json[kJsonKeyOutputDesc].size(); i++) {
518     std::string dtype = node_json[kJsonKeyOutputDesc][i][kJsonKeyDataType];
519     size_t nbyte = GetDtypeNbyte(dtype);
520     size_t size_i =
521       std::accumulate(node_json[kJsonKeyOutputDesc][i][kJsonKeyShape].begin(),
522                       node_json[kJsonKeyOutputDesc][i][kJsonKeyShape].end(), nbyte, std::multiplies<size_t>());
523     output_size->push_back(size_i);
524   }
525 
526   return true;
527 }
528 
CollectJson(const AnfNodePtr & anf_node,nlohmann::json * kernel_json)529 bool AkgKernelJsonGenerator::CollectJson(const AnfNodePtr &anf_node, nlohmann::json *kernel_json) {
530   MS_EXCEPTION_IF_NULL(anf_node);
531   MS_EXCEPTION_IF_NULL(kernel_json);
532   std::string op_name = AnfAlgo::GetCNodeName(anf_node);
533   MS_LOG(DEBUG) << "Akg start generate kernel json desc, full scope name is : " << anf_node->fullname_with_scope();
534   SetAkgKernelAttrs(anf_node);
535   is_basic_op_ = true;
536   if (!GenerateSingleKernelJson(anf_node, kernel_json)) {
537     MS_LOG(ERROR) << "Op[" << anf_node->fullname_with_scope() << "] create single kernel json failed.";
538     return false;
539   }
540 
541   size_t hash_id = std::hash<std::string>()(kernel_json->dump());
542   kernel_name_ = op_name + "_";
543   (void)kernel_name_.append(std::to_string(hash_id));
544   (*kernel_json)[kJsonKeyId] = GetOpCntInc();
545   (*kernel_json)[kJsonKeyOp] = kernel_name_;
546   (*kernel_json)[kJsonKeyPlatform] = "AKG";
547   (*kernel_json)[kJsonKeyProcess] = GetStrProcessorFromContext();  // GetProcessorStr(anf_node);
548   (*kernel_json)[kJsonKeyComposite] = false;
549   if (dump_option_.get_compute_capability) {
550     (*kernel_json)[kJsonKeyComputeCapability] = ComputeCapability::Get();
551   }
552 
553   if (!GetIOSize(*kernel_json, &input_size_list_, &output_size_list_)) {
554     MS_LOG(ERROR) << "Cal mem size failed.";
555     return false;
556   }
557 
558   MS_LOG(DEBUG) << "Akg create kernel json desc success, full scope name is : " << anf_node->fullname_with_scope()
559                 << ", json info name is : " << kernel_name_;
560   return true;
561 }
562 
GenStitchJson(const std::vector<AnfNodePtr> & anf_nodes,std::map<AnfNodePtr,nlohmann::json> * node_json_map,nlohmann::json * kernel_json)563 void AkgKernelJsonGenerator::GenStitchJson(const std::vector<AnfNodePtr> &anf_nodes,
564                                            std::map<AnfNodePtr, nlohmann::json> *node_json_map,
565                                            nlohmann::json *kernel_json) {
566   std::vector<std::string> stitchs;
567   for (auto const &anf_node : anf_nodes) {
568     if (AnfAlgo::HasNodeAttr(kAttrStitch, anf_node->cast<CNodePtr>()) &&
569         AnfAlgo::GetNodeAttr<std::string>(anf_node, kAttrStitch) == "common") {
570       auto name = GetTensorName((*node_json_map)[anf_node], kJsonKeyOutputDesc, {0, 0});
571       if (std::find(stitchs.begin(), stitchs.end(), name) == stitchs.end()) {
572         stitchs.emplace_back(name);
573       }
574     }
575   }
576   if (!stitchs.empty()) {
577     std::vector<nlohmann::json> v;
578     for (auto &s : stitchs) {
579       std::vector<std::string> t;
580       t.emplace_back(s);
581       v.emplace_back(t);
582     }
583     nlohmann::json stitch_json;
584     stitch_json[kJsonKeyStitchOp] = v;
585     (*kernel_json)[kJsonKeyBufferStitch] = stitch_json;
586   }
587 }
CollectFusedJson(const std::vector<AnfNodePtr> & anf_nodes,const std::vector<AnfNodePtr> & input_list,const std::vector<AnfNodePtr> & output_list,nlohmann::json * kernel_json)588 bool AkgKernelJsonGenerator::CollectFusedJson(const std::vector<AnfNodePtr> &anf_nodes,
589                                               const std::vector<AnfNodePtr> &input_list,
590                                               const std::vector<AnfNodePtr> &output_list, nlohmann::json *kernel_json) {
591   if (anf_nodes.empty()) {
592     MS_LOG(ERROR) << "Invalid input size, anf_nodes [" << anf_nodes.size() << "], input_list [" << input_list.size()
593                   << "].";
594     return false;
595   }
596   MS_LOG(DEBUG) << "Fusion nodes: [" << output_list.size() << "], input_list: [" << anf_nodes.size()
597                 << "], output_list: [" << input_list.size() << "].";
598   std::map<AnfNodePtr, nlohmann::json> node_json_map;
599   is_basic_op_ = false;
600   dump_option_.extract_opinfo_from_anfnode = true;  // always extract from anfnode for composite ops.
601   if (!GenSingleJsons(anf_nodes, &node_json_map)) return false;
602 
603   UpdateTensorName(anf_nodes, &node_json_map);
604 
605   std::vector<nlohmann::json> node_json_desc;
606   std::transform(anf_nodes.begin(), anf_nodes.end(), std::back_inserter(node_json_desc),
607                  [&node_json_map](const AnfNodePtr &anf_node) { return node_json_map[anf_node]; });
608   (*kernel_json)[kJsonKeyOpDesc] = node_json_desc;
609 
610   auto inputs_json = CreateInputsJson(anf_nodes, input_list, node_json_map);
611   (*kernel_json)[kJsonKeyInputDesc] = inputs_json;
612   (*kernel_json)[kJsonKeyOutputDesc] =
613     CreateOutputsJson(anf_nodes, input_list, output_list, inputs_json, node_json_map);
614 
615   // Add parallel fusion information.
616   GenParallelJson(anf_nodes, input_list, output_list, node_json_map, kernel_json);
617 
618   size_t hash_id = std::hash<std::string>()(kernel_json->dump());
619   kernel_name_ = "Fused_";
620   auto fg = anf_nodes[0]->func_graph();
621   MS_EXCEPTION_IF_NULL(fg);
622   auto attr_val = fg->get_attr(FUNC_GRAPH_ATTR_GRAPH_KERNEL);
623   constexpr size_t name_len_limited = 80;
624   if (attr_val != nullptr) {
625     auto fg_name = GetValue<std::string>(attr_val);
626     if (fg_name.size() > name_len_limited) {
627       (*kernel_json)[kJsonKeyOpFullName] = kernel_name_ + fg_name;
628       auto suffix_pos = fg_name.find_last_of("_");
629       fg_name =
630         fg_name.substr(0, name_len_limited - fg_name.size() + suffix_pos) + "_more" + fg_name.substr(suffix_pos);
631     }
632     static_cast<void>(kernel_name_.append(fg_name).append("_"));
633   }
634   static_cast<void>(kernel_name_.append(std::to_string(hash_id)));
635   (*kernel_json)[kJsonKeyId] = GetOpCntInc();
636   (*kernel_json)[kJsonKeyOp] = kernel_name_;
637   (*kernel_json)[kJsonKeyPlatform] = "AKG";
638   (*kernel_json)[kJsonKeyProcess] = GetStrProcessorFromContext();
639   (*kernel_json)[kJsonKeyComposite] = true;
640   (*kernel_json)[kJsonKeyCompositeGraph] = fg->ToString();
641   if (dump_option_.get_compute_capability) {
642     (*kernel_json)[kJsonKeyComputeCapability] = ComputeCapability::Get();
643   }
644 
645   GenStitchJson(anf_nodes, &node_json_map, kernel_json);
646 
647   if (!GetIOSize(*kernel_json, &input_size_list_, &output_size_list_)) {
648     MS_LOG(ERROR) << "Cal mem size failed.";
649     return false;
650   }
651 
652   return true;
653 }
654 
GenSingleJsons(const std::vector<AnfNodePtr> & anf_nodes,std::map<AnfNodePtr,nlohmann::json> * node_json_map)655 bool AkgKernelJsonGenerator::GenSingleJsons(const std::vector<AnfNodePtr> &anf_nodes,
656                                             std::map<AnfNodePtr, nlohmann::json> *node_json_map) {
657   for (auto const &anf_node : anf_nodes) {
658     MS_EXCEPTION_IF_NULL(anf_node);
659     if (!AnfAlgo::IsRealKernel(anf_node)) {
660       MS_LOG(ERROR) << "Invalid anf node to build [" << anf_node->fullname_with_scope() << "].";
661       return false;
662     }
663     SetAkgKernelAttrs(anf_node);
664 
665     nlohmann::json node_json;
666     if (!GenerateSingleKernelJson(anf_node, &node_json)) {
667       MS_LOG(ERROR) << "Op [" << anf_node->fullname_with_scope() << "] create single kernel json failed.";
668       return false;
669     }
670 
671     auto primitive = AnfAlgo::GetCNodePrimitive(anf_node);
672     MS_EXCEPTION_IF_NULL(primitive);
673 
674     (*node_json_map)[anf_node] = node_json;
675   }
676   return true;
677 }
678 
UpdateTensorName(const std::vector<AnfNodePtr> & anf_nodes,std::map<AnfNodePtr,nlohmann::json> * node_json_map)679 void AkgKernelJsonGenerator::UpdateTensorName(const std::vector<AnfNodePtr> &anf_nodes,
680                                               std::map<AnfNodePtr, nlohmann::json> *node_json_map) {
681   for (auto const &anf_node : anf_nodes) {
682     auto dyn_input_sizes = GetDynInputSize(anf_node);
683     bool is_dynamic_input = !dyn_input_sizes.empty();
684     size_t input_num = is_dynamic_input ? dyn_input_sizes.size() : AnfAlgo::GetInputTensorNum(anf_node);
685     size_t real_input_index = 0;
686     for (size_t i = 0; i < input_num; ++i) {
687       size_t input_tensor_num = is_dynamic_input ? IntToSize(dyn_input_sizes[i]) : 1;
688       for (size_t j = 0; j < input_tensor_num; ++j) {
689         auto tmp_input = GetKernelInput(anf_node, real_input_index);
690         std::string tensor_name = GetTensorName((*node_json_map)[anf_node], kJsonKeyInputDesc, std::make_pair(i, j));
691         if (node_json_map->find(tmp_input.first) != node_json_map->end()) {
692           std::string new_tensor_name =
693             GetTensorName((*node_json_map)[tmp_input.first], kJsonKeyOutputDesc, std::make_pair(0, tmp_input.second));
694           SetTensorName(kJsonKeyInputDesc, new_tensor_name, std::make_pair(i, j), &((*node_json_map)[anf_node]));
695           MS_LOG(DEBUG) << "Update [" << real_input_index << "] input [" << tensor_name << "] of ["
696                         << anf_node->fullname_with_scope() << "] to [" << tmp_input.second << "] output ["
697                         << new_tensor_name << "] of [" << tmp_input.first->fullname_with_scope() << "].";
698         } else {
699           MS_LOG(DEBUG) << "[" << real_input_index << "] input " << tensor_name << "] of ["
700                         << anf_node->fullname_with_scope() << "] is out input.";
701         }
702         real_input_index++;
703       }
704     }
705   }
706 }
707 
CreateInputsJson(const std::vector<AnfNodePtr> & anf_nodes,const std::vector<AnfNodePtr> & input_list,const std::map<AnfNodePtr,nlohmann::json> & node_json_map)708 nlohmann::json AkgKernelJsonGenerator::CreateInputsJson(const std::vector<AnfNodePtr> &anf_nodes,
709                                                         const std::vector<AnfNodePtr> &input_list,
710                                                         const std::map<AnfNodePtr, nlohmann::json> &node_json_map) {
711   nlohmann::json inputs_json;
712   auto input_index = GetInputIndex(anf_nodes, input_list);
713   for (size_t i = 0; i < input_index.size(); ++i) {
714     auto tmp_input = input_index[i];
715     auto type_id = this->GetInputDataType(tmp_input.first, tmp_input.second.first);
716     std::string dtype = TypeId2String(type_id, dump_option_.is_before_select_kernel);
717     nlohmann::json input_desc_json;
718     input_desc_json[kJsonKeyTensorName] =
719       GetTensorName(node_json_map.at(tmp_input.first), kJsonKeyInputDesc, tmp_input.second);
720     input_desc_json[kJsonKeyDataType] = dtype;
721     input_desc_json[kJsonKeyFormat] = this->GetInputFormat(tmp_input.first, tmp_input.second.first);
722     auto input_shape = this->GetInputShape(tmp_input.first, tmp_input.second.first);
723     if (input_shape.empty()) {
724       input_shape.push_back(1);
725     }
726     input_desc_json[kJsonKeyShape] = input_shape;
727     inputs_json.emplace_back(std::vector<nlohmann::json>{input_desc_json});
728   }
729   return inputs_json;
730 }
731 
GenParallelJson(const std::vector<AnfNodePtr> & anf_nodes,const std::vector<AnfNodePtr> & input_list,const std::vector<AnfNodePtr> & output_list,const std::map<AnfNodePtr,nlohmann::json> & node_json_map,nlohmann::json * kernel_json)732 void AkgKernelJsonGenerator::GenParallelJson(const std::vector<AnfNodePtr> &anf_nodes,
733                                              const std::vector<AnfNodePtr> &input_list,
734                                              const std::vector<AnfNodePtr> &output_list,
735                                              const std::map<AnfNodePtr, nlohmann::json> &node_json_map,
736                                              nlohmann::json *kernel_json) {
737   std::map<size_t, std::pair<size_t, std::vector<std::string>>> sub_graphs_info;
738   std::string fusion_type;
739   std::vector<std::vector<int>> type_info;
740 
741   auto output_index = GetOutputIndex(anf_nodes, input_list, output_list);
742   for (size_t i = 0; i < output_index.size(); ++i) {
743     auto [tmp_output, tmp_output_index] = output_index[i];
744     bool found = std::any_of(input_list.cbegin(), input_list.cend(),
745                              [&tmp_output](const AnfNodePtr &in) { return tmp_output == in; });
746     if (!found) {
747       auto tcnode = tmp_output->cast<CNodePtr>();
748       if (tcnode == nullptr) {
749         return;
750       }
751       // Get dim info.
752       if (AnfAlgo::HasNodeAttr(kAttrParallelDimInfo, tcnode)) {
753         auto info = AnfAlgo::GetNodeAttr<std::vector<size_t>>(tcnode, kAttrParallelDimInfo);
754         if (info.size() != 2) {
755           MS_LOG(EXCEPTION) << "Parallel dim info is invalid!";
756         }
757         auto tensor_name =
758           GetTensorName(node_json_map.at(tmp_output), kJsonKeyOutputDesc, std::make_pair(0, tmp_output_index));
759         sub_graphs_info[info[0]].second.push_back(tensor_name);
760         sub_graphs_info[info[0]].first = info[1];
761       }
762       // Get fusion type.
763       if (AnfAlgo::HasNodeAttr(kAttrParallelFusionType, tcnode)) {
764         fusion_type = AnfAlgo::GetNodeAttr<std::string>(tcnode, kAttrParallelFusionType);
765       }
766       // Get fusion type info.
767       if (AnfAlgo::HasNodeAttr(kAttrParallelTypeInfo, tcnode)) {
768         type_info = AnfAlgo::GetNodeAttr<std::vector<std::vector<int>>>(tcnode, kAttrParallelTypeInfo);
769       }
770     }
771   }
772 
773   if (!sub_graphs_info.empty()) {
774     auto processor = GetStrProcessorFromContext();  // GetProcessorStr(anf_nodes[0]);
775     if (processor != kProcessorCuda) {
776       MS_LOG(EXCEPTION) << "Parallel fusion not support " << processor << " now.";
777     }
778 
779     nlohmann::json parallel_fusion_json;
780     parallel_fusion_json[kJsonKeyFusionType] = fusion_type;
781     parallel_fusion_json[kJsonKeyTypeInfo] = type_info;
782     std::vector<std::vector<std::string>> sgraphs;
783     std::vector<size_t> cnums;
784     std::for_each(sub_graphs_info.cbegin(), sub_graphs_info.cend(),
785                   [&sgraphs, &cnums](const std::pair<size_t, std::pair<size_t, std::vector<std::string>>> &sg_info) {
786                     sgraphs.push_back(sg_info.second.second);
787                     cnums.push_back(sg_info.second.first);
788                   });
789     parallel_fusion_json[kJsonKeySubGraph] = sgraphs;
790     parallel_fusion_json[kJsonKeyCoreNum] = cnums;
791 
792     (*kernel_json)[kJsonKeyParallelFusion] = parallel_fusion_json;
793   }
794 }
795 
CreateOutputsJson(const std::vector<AnfNodePtr> & anf_nodes,const std::vector<AnfNodePtr> & input_list,const std::vector<AnfNodePtr> & output_list,const nlohmann::json & inputs_json,const std::map<AnfNodePtr,nlohmann::json> & node_json_map)796 nlohmann::json AkgKernelJsonGenerator::CreateOutputsJson(const std::vector<AnfNodePtr> &anf_nodes,
797                                                          const std::vector<AnfNodePtr> &input_list,
798                                                          const std::vector<AnfNodePtr> &output_list,
799                                                          const nlohmann::json &inputs_json,
800                                                          const std::map<AnfNodePtr, nlohmann::json> &node_json_map) {
801   nlohmann::json outputs_json;
802   auto output_index = GetOutputIndex(anf_nodes, input_list, output_list);
803   for (size_t i = 0; i < output_index.size(); ++i) {
804     auto tmp_output = output_index[i];
805     bool found = false;
806     nlohmann::json output_desc_json;
807     for (size_t input_i = 0; input_i < input_list.size(); ++input_i) {
808       if (tmp_output.first == input_list[input_i]) {
809         output_desc_json = inputs_json[input_i][0];
810         found = true;
811         break;
812       }
813     }
814     if (!found) {
815       auto type_id = this->GetOutputDataType(tmp_output.first, tmp_output.second);
816       std::string dtype = TypeId2String(type_id, dump_option_.is_before_select_kernel);
817       output_desc_json[kJsonKeyTensorName] =
818         GetTensorName(node_json_map.at(tmp_output.first), kJsonKeyOutputDesc, std::make_pair(0, tmp_output.second));
819       output_desc_json[kJsonKeyDataType] = dtype;
820       output_desc_json[kJsonKeyFormat] = this->GetOutputFormat(tmp_output.first, tmp_output.second);
821       auto output_shape = this->GetOutputShape(tmp_output.first, tmp_output.second);
822       if (output_shape.empty()) {
823         output_shape.push_back(1);
824       }
825       output_desc_json[kJsonKeyShape] = output_shape;
826     }
827     outputs_json.emplace_back(output_desc_json);
828   }
829   return outputs_json;
830 }
831 
CollectJson(const AnfNodePtr & anf_node)832 bool AkgKernelJsonGenerator::CollectJson(const AnfNodePtr &anf_node) {
833   kernel_json_ = nlohmann::json();
834   return CollectJson(anf_node, &kernel_json_);
835 }
836 
CollectFusedJson(const std::vector<AnfNodePtr> & anf_nodes,const std::vector<AnfNodePtr> & input_list,const std::vector<AnfNodePtr> & output_list)837 bool AkgKernelJsonGenerator::CollectFusedJson(const std::vector<AnfNodePtr> &anf_nodes,
838                                               const std::vector<AnfNodePtr> &input_list,
839                                               const std::vector<AnfNodePtr> &output_list) {
840   kernel_json_ = nlohmann::json();
841   return CollectFusedJson(anf_nodes, input_list, output_list, &kernel_json_);
842 }
843 
GetComputeCapability()844 void ComputeCapability::GetComputeCapability() {
845 #ifdef ENABLE_GPU
846   int a, b;
847   auto ret = cuDeviceGetAttribute(&a, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, 0);
848   if (ret != CUDA_SUCCESS) {
849     MS_LOG(WARNING) << "Get CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR fail, ret=" << ret;
850     return;
851   }
852   ret = cuDeviceGetAttribute(&b, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, 0);
853   if (ret != CUDA_SUCCESS) {
854     MS_LOG(WARNING) << "Get CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR fail, ret=" << ret;
855     return;
856   }
857   this->compute_capability_ = std::to_string(a) + "." + std::to_string(b);
858 #else
859   this->compute_capability_ = "Unknown";
860 #endif
861   return;
862 }
863 }  // namespace kernel
864 }  // namespace mindspore
865