2 // Copyright (c) 2016 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 ///////////////////////////////////////////////////////////////////////////////////////////////////
19 #include "program_dump_graph.h"
20 #include "to_string_utils.h"
28 static const std::vector<std::string> colors =
75 "lightgoldenrodyellow",
149 void close_stream(std::ofstream& graph)
154 std::string get_node_id(program_node* ptr)
156 return "node_" + std::to_string(reinterpret_cast<uintptr_t>(ptr));
159 void dump_full_node(std::ofstream& out, program_node* node)
161 out << node->type()->to_string(*node);
165 std::string get_dir_path(build_options opts)
167 auto path = opts.get<build_option_type::graph_dumps_dir>()->directory_path;
173 if (path.back() != '/' && path.back() != '\\')
180 /// Returns given name for serialization process.
181 std::string get_serialization_network_name(build_options opts)
183 return opts.get<build_option_type::serialize_network>()->serialization_network_name;
186 std::string get_load_program_name(build_options opts)
188 return opts.get<build_option_type::load_program>()->load_program_name;
191 void dump_graph_init(std::ofstream& graph, const program_impl& program, std::function<bool(program_node const&)> const& filter)
193 const auto extr_oformat = [](program_node* ptr)
195 std::string out = "";
196 switch (ptr->get_output_layout().format)
198 case format::yxfb: out = "yxfb"; break;
199 case format::byxf: out = "byxf"; break;
200 case format::bfyx: out = "bfyx"; break;
201 case format::fyxb: out = "fyxb"; break;
202 case format::os_iyx_osv16: out = "os_iyx_osv16"; break;
203 case format::bs_xs_xsv8_bsv8: out = "bs_xs_xsv8_bsv8"; break;
204 case format::bs_xs_xsv8_bsv16: out = "bs_xs_xsv8_bsv16"; break;
205 case format::bs_x_bsv16: out = "bs_x_bsv16"; break;
206 case format::bf8_xy16: out = "bf8_xy16"; break;
207 case format::image_2d_weights_c1_b_fyx: out = "image_2d_weights_c1_b_fyx"; break;
208 case format::image_2d_weights_c4_fyx_b: out = "image_2d_weights_c4_fyx_b"; break;
209 case format::image_2d_weights_winograd_6x3_s1_fbxyb: out = "image_2d_weights_winograd_6x3_s1_fbxyb"; break;
210 case format::image_2d_weights_winograd_6x3_s1_xfbyb: out = "image_2d_weights_winograd_6x3_s1_xfbyb"; break;
211 case format::os_is_yx_isa8_osv8_isv4: out = "os_is_yx_isa8_osv8_isv4"; break;
212 case format::byxf_af32: out = "byxf_af32"; break;
213 case format::any: out = "any"; break;
219 if (!ptr->is_valid_output_layout())
225 const auto extr_data_type = [](program_node* ptr)
227 std::string out = "";
228 switch (ptr->get_output_layout().data_type)
230 case data_types::i8: out = "i8"; break;
231 case data_types::u8: out = "u8"; break;
232 case data_types::f16: out = "f16"; break;
233 case data_types::f32: out = "f32"; break;
235 out = "unknown data_type";
241 const auto dump_mem_info = [](program_node* ptr)
243 std::string out = "size_info: ";
244 auto out_layout = ptr->get_output_layout();
245 auto tensor_str = out_layout.size.to_string();
246 auto padding = out_layout.data_padding;
250 out += " (nonpadded)";
254 out += "\nl: " + padding.lower_size().to_string()
255 + "\nu: " + padding.upper_size().to_string();
261 graph << "digraph cldnn_program {\n";
262 for (auto& node : program.get_nodes())
264 if (filter && !filter(*node))
269 #pragma clang diagnostic push
270 #pragma clang diagnostic ignored "-Wpotentially-evaluated-expression"
272 std::string node_type = get_extr_type(typeid(*node).name());
273 graph << " " << get_node_id(node.get()) << "[label=\"" << node->id() << ":\n" << node_type << "\n out format: " + extr_oformat(node.get())
274 << "\n out data_type: " + extr_data_type(node.get())
275 << "\\nprocessing number: " << node->get_processing_num() << "\\n color:" << (node->is_reusing_memory() ? std::to_string(node->get_reused_memory_color()) : "none")
276 << (node->can_be_optimized() ? "\\n optimized out" : "");
277 if (node_type != "struct cldnn::data" && node_type != "struct cldnn::input_layout" && !node->can_be_optimized())
278 graph << "\\n Selected kernel: " << (node->get_selected_impl() == nullptr ? "none" : node->get_selected_impl().get()->get_kernel_name()
279 + "\n" + dump_mem_info(node.get()));
282 #pragma clang diagnostic pop
285 if (node->is_type<data>() || node->is_constant())
286 graph << ", shape=box";
287 if (node->is_type<internal_primitive>())
288 graph << ", color=blue";
289 if (node->is_in_data_flow())
290 graph << ", group=data_flow";
291 if (node->is_reusing_memory())
293 graph << ", fillcolor=\"" << colors[node->get_reused_memory_color() % colors.size()] << "\" ";
294 graph << " style=filled ";
298 for (auto& user : node->get_users())
300 if (filter && !filter(*user))
305 if (std::find(user->get_dependencies().begin(), user->get_dependencies().end(), node.get()) == user->get_dependencies().end())
308 graph << " " << get_node_id(node.get()) << " -> " << get_node_id(user);
310 bool data_flow = node->is_in_data_flow() && user->is_in_data_flow();
314 graph << " [color=red]";
316 graph << " [color=red, style=dashed, label=\"usr\"]";
321 graph << " [style=dashed, label=\"usr\"]";
326 for (auto& dep : node->get_dependencies())
328 if (filter && !filter(*dep))
333 if (std::find(dep->get_users().begin(), dep->get_users().end(), node.get()) != dep->get_users().end())
338 graph << " " << get_node_id(node.get()) << " -> " << get_node_id(dep) << " [style=dashed, label=\"dep\", constraint=false];\n";
341 if (node->get_dominator() && (!filter || filter(*node->get_dominator())))
342 graph << " " << get_node_id(node.get()) << " -> " << get_node_id(node->get_dominator()) << " [style=dotted, label=\"dom\", constraint=false];\n";
343 if (node->get_joint() && (!filter || filter(*node->get_joint())))
344 graph << " " << get_node_id(node.get()) << " -> " << get_node_id(node->get_joint()) << " [style=dotted, label=\"p-dom\", constraint=false];\n";
351 void dump_graph_processing_order(std::ofstream& graph, const program_impl& program)
353 for (auto node : program.get_processing_order())
354 graph << reinterpret_cast<uintptr_t>(node) << " (" << node->id() << ")\n";
359 void dump_graph_optimized(std::ofstream& graph, const program_impl& program)
361 for (auto& prim_id : program.get_optimized_out())
362 graph << prim_id << "\n";
367 void dump_graph_info(std::ofstream& graph, const program_impl& program, std::function<bool(program_node const&)> const& filter)
369 for (auto& node : program.get_nodes())
371 if (filter && !filter(*node))
374 dump_full_node(graph, node.get());
375 graph << std::endl << std::endl;
380 //Function used by serialization. Not working yet, in progress.
381 void dump_to_xml(std::ofstream& graph, const program_impl& program, std::function<bool(program_node const&)> const& filter, std::vector<unsigned long long>& offsets, std::vector<std::string>& data_names)
383 xml_composite data_container, node_container, kernels;
384 auto node_number = 1;
385 auto kernels_number = 1;
388 auto size = offsets.at(0);
389 for (auto& node : program.get_nodes())
391 if (filter && !filter(*node))
394 std::string package_name = "node_" + std::to_string(node_number);
395 auto node_info = node.get()->desc_to_xml();
396 auto id = node->id();
397 for (auto p = postion; p < (unsigned int)data_names.size(); p++)
401 offset = offsets.at(p - 1);
402 size = offsets.at(p) - offsets.at(p - 1);
404 if (data_names.at(p).find("kernels") != std::string::npos)
407 node_info.add("id", data_names.at(p));
409 package_name = "kernels_" + std::to_string(kernels_number);
415 if (data_names.at(p).find(id) != std::string::npos)
417 node_info.add("data_offset", std::to_string(offset));
418 node_info.add("data_size", std::to_string(size));
423 node_container.add(package_name, node_info);
425 data_container.add("data", node_container);
426 data_container.dump(graph);
430 //Function used by serialization. Not working yet, in progress.
431 void dump_kernels(kernels_binaries_container program_binaries, std::vector<unsigned long long>& offsets, std::vector<std::string>& data_names, std::ofstream& file_stream)
433 auto offset_temp = 0ull;
434 for (unsigned int i = 0; i < (unsigned int)program_binaries.size(); i++)
436 for (unsigned int j = 0; j < (unsigned int)program_binaries.at(i).size(); j++)
438 for (unsigned int k = 0; k < (unsigned int)program_binaries.at(i).at(j).size(); k++)
440 char* p = (char*)&program_binaries.at(i).at(j).at(k);
441 file_stream.write(p, sizeof(char));
442 offset_temp += sizeof(char);
445 offsets.push_back(offset_temp);
446 std::string offset_name = "kernels_part_" + std::to_string(i+1);
447 data_names.push_back(offset_name);
451 //Function used by serialization. Not working yet, in progress.
452 void dump_data(memory_impl& mem, std::ofstream& stream, unsigned long long& total_offset, unsigned long long type)
455 char * ptr = (char*)mem.lock();
456 for (unsigned int x = 0; x < (unsigned int)mem.get_layout().count(); x++)
458 stream.write(ptr + offset, type);
462 total_offset += offset;