Publishing R3
[platform/upstream/dldt.git] / inference-engine / thirdparty / clDNN / src / program_dump_graph.cpp
1 /*
2 // Copyright (c) 2016 Intel Corporation
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 ///////////////////////////////////////////////////////////////////////////////////////////////////
18
19 #include "program_dump_graph.h"
20 #include "to_string_utils.h"
21 #include <algorithm>
22 #include <vector>
23
24 namespace cldnn
25 {
26     namespace
27     {
28         static const std::vector<std::string> colors =
29         {
30             "chartreuse",
31             "aquamarine",
32             "gold",
33             "green",
34             "blue",
35             "cyan",
36             "azure",
37             "beige",
38             "bisque",
39             "blanchedalmond",
40             "blueviolet",
41             "brown",
42             "burlywood",
43             "cadetblue",
44             "chocolate",
45             "coral",
46             "cornflowerblue",
47             "cornsilk",
48             "crimson",
49             "aliceblue",
50             "antiquewhite",
51             "deeppink",
52             "deepskyblue",
53             "dimgray",
54             "dodgerblue",
55             "firebrick",
56             "floralwhite",
57             "forestgreen",
58             "gainsboro",
59             "ghostwhite",
60             "goldenrod",
61             "greenyellow",
62             "honeydew",
63             "hotpink",
64             "indianred",
65             "indigo",
66             "ivory",
67             "khaki",
68             "lavender",
69             "lavenderblush",
70             "lawngreen",
71             "lemonchiffon",
72             "lightblue",
73             "lightcoral",
74             "lightcyan",
75             "lightgoldenrodyellow",
76             "lightgray",
77             "lightgrey",
78             "lightpink",
79             "lightsalmon",
80             "lightseagreen",
81             "lightskyblue",
82             "lightsteelblue",
83             "lightyellow",
84             "lime",
85             "limegreen",
86             "linen",
87             "magenta",
88             "maroon",
89             "mediumaquamarine",
90             "mediumblue",
91             "mediumorchid",
92             "mediumpurple",
93             "mediumseagreen",
94             "mediumslateblue",
95             "mediumspringgreen",
96             "mediumturquoise",
97             "mediumvioletred",
98             "midnightblue",
99             "mintcream",
100             "mistyrose",
101             "moccasin",
102             "navajowhite",
103             "navy",
104             "oldlace",
105             "olive",
106             "olivedrab",
107             "orange",
108             "orangered",
109             "orchid",
110             "palegoldenrod",
111             "palegreen",
112             "paleturquoise",
113             "palevioletred",
114             "papayawhip",
115             "peachpuff",
116             "peru",
117             "pink",
118             "plum",
119             "powderblue",
120             "purple",
121             "red",
122             "rosybrown",
123             "royalblue",
124             "saddlebrown",
125             "salmon",
126             "sandybrown",
127             "seagreen",
128             "seashell",
129             "sienna",
130             "silver",
131             "skyblue",
132             "slateblue",
133             "snow",
134             "springgreen",
135             "steelblue",
136             "tan",
137             "teal",
138             "thistle",
139             "tomato",
140             "turquoise",
141             "violet",
142             "wheat",
143             "white",
144             "yellow",
145             "yellowgreen",
146         };
147
148
149     void close_stream(std::ofstream& graph)
150     {
151         graph.close();
152     }
153
154     std::string get_node_id(program_node* ptr)
155     {
156         return "node_" + std::to_string(reinterpret_cast<uintptr_t>(ptr));
157     }
158
159     void dump_full_node(std::ofstream& out, program_node* node)
160     {
161         out << node->type()->to_string(*node);
162     }
163     }
164
165     std::string get_dir_path(build_options opts)
166     {
167         auto path = opts.get<build_option_type::graph_dumps_dir>()->directory_path;
168         if (path.empty())
169         {
170             return{};
171         }
172
173         if (path.back() != '/' && path.back() != '\\')
174         {
175             path += "/";
176         }
177         return path;
178     }
179
180     /// Returns given name for serialization process.
181     std::string get_serialization_network_name(build_options opts)
182     {
183         return opts.get<build_option_type::serialize_network>()->serialization_network_name;
184     }
185
186     std::string get_load_program_name(build_options opts)
187     {
188         return opts.get<build_option_type::load_program>()->load_program_name;
189     }
190
191     void dump_graph_init(std::ofstream& graph, const program_impl& program, std::function<bool(program_node const&)> const& filter)
192     {
193         const auto extr_oformat = [](program_node* ptr)
194         {
195             std::string out = "";
196             switch (ptr->get_output_layout().format)
197             {
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;
214             default:
215                 out = "unk format";
216                 break;
217             }
218
219             if (!ptr->is_valid_output_layout())
220                 out += " (invalid)";
221
222             return out;
223         };
224
225         const auto extr_data_type = [](program_node* ptr)
226         {
227             std::string out = "";
228             switch (ptr->get_output_layout().data_type)
229             {
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;
234             default:
235                 out = "unknown data_type";
236                 break;
237             }
238             return out;
239         };
240
241         const auto dump_mem_info = [](program_node* ptr)
242         {
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;
247             out += tensor_str;
248             if (!padding)
249             {
250                 out += " (nonpadded)";
251             }
252             else
253             {
254                 out += "\nl: " + padding.lower_size().to_string()
255                     + "\nu: " + padding.upper_size().to_string();
256             }
257             
258             return out;
259         };
260
261         graph << "digraph cldnn_program {\n";
262         for (auto& node : program.get_nodes())
263         {
264             if (filter && !filter(*node))
265             {
266                 continue;
267             }
268             #ifdef __clang__
269                 #pragma clang diagnostic push
270                 #pragma clang diagnostic ignored "-Wpotentially-evaluated-expression"
271             #endif
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()));
280             graph << "\"";
281             #ifdef __clang__
282                 #pragma clang diagnostic pop
283             #endif
284
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())
292             {
293                 graph << ", fillcolor=\"" << colors[node->get_reused_memory_color() % colors.size()] << "\" ";
294                 graph << " style=filled ";
295             }
296             graph << "];\n";
297
298             for (auto& user : node->get_users())
299             {
300                 if (filter && !filter(*user))
301                 {
302                     continue;
303                 }
304                 bool doubled = true;
305                 if (std::find(user->get_dependencies().begin(), user->get_dependencies().end(), node.get()) == user->get_dependencies().end())
306                     doubled = false;
307
308                 graph << "    " << get_node_id(node.get()) << " -> " << get_node_id(user);
309
310                 bool data_flow = node->is_in_data_flow() && user->is_in_data_flow();
311                 if (data_flow)
312                 {
313                     if (doubled)
314                         graph << " [color=red]";
315                     else
316                         graph << " [color=red, style=dashed, label=\"usr\"]";
317                 }
318                 else
319                 {
320                     if (!doubled)
321                         graph << " [style=dashed, label=\"usr\"]";
322                 }
323                 graph << ";\n";
324             }
325
326             for (auto& dep : node->get_dependencies())
327             {
328                 if (filter && !filter(*dep))
329                 {
330                     continue;
331                 }
332
333                 if (std::find(dep->get_users().begin(), dep->get_users().end(), node.get()) != dep->get_users().end())
334                 {
335                     continue;
336                 }
337
338                 graph << "   " << get_node_id(node.get()) << " -> " << get_node_id(dep) << " [style=dashed, label=\"dep\", constraint=false];\n";
339             }
340
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";
345         }
346         graph << "}\n";
347         close_stream(graph);
348     }
349
350
351     void dump_graph_processing_order(std::ofstream& graph, const program_impl& program)
352     { 
353         for (auto node : program.get_processing_order())
354             graph << reinterpret_cast<uintptr_t>(node) << " (" << node->id() << ")\n";
355         graph << '\n';
356         close_stream(graph);
357     }
358
359     void dump_graph_optimized(std::ofstream& graph, const program_impl& program)
360     {
361         for (auto& prim_id : program.get_optimized_out())
362             graph << prim_id << "\n";
363         graph << '\n';
364         close_stream(graph);
365     }
366
367     void dump_graph_info(std::ofstream& graph, const program_impl& program, std::function<bool(program_node const&)> const& filter)
368     {
369         for (auto& node : program.get_nodes())
370         {
371             if (filter && !filter(*node))
372                 continue;
373
374             dump_full_node(graph, node.get());
375             graph << std::endl << std::endl;
376         }
377         close_stream(graph);
378     }
379
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)
382     {
383         xml_composite data_container, node_container, kernels;
384         auto node_number = 1;
385         auto kernels_number = 1;
386         auto postion = 0u;
387         auto offset = 0ull;
388         auto size = offsets.at(0);
389         for (auto& node : program.get_nodes())
390         {
391             if (filter && !filter(*node))
392                 continue;
393
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++)
398             {
399                     if (p != 0)
400                     {
401                         offset = offsets.at(p - 1);
402                         size = offsets.at(p) - offsets.at(p - 1);
403                     }
404                     if (data_names.at(p).find("kernels") != std::string::npos)
405                     {
406                         node_info = kernels;
407                         node_info.add("id", data_names.at(p));
408                         id = "kernels";
409                         package_name = "kernels_" + std::to_string(kernels_number);
410
411                         postion++;
412                         kernels_number++;
413                         node_number--;
414                     }
415                     if (data_names.at(p).find(id) != std::string::npos)
416                     {
417                         node_info.add("data_offset", std::to_string(offset));
418                         node_info.add("data_size", std::to_string(size));
419                         node_number++;
420                         break;
421                     }
422             }
423             node_container.add(package_name, node_info); 
424         }
425         data_container.add("data", node_container);
426         data_container.dump(graph);
427         close_stream(graph);
428     }
429
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)
432     {
433         auto offset_temp = 0ull;
434         for (unsigned int i = 0; i < (unsigned int)program_binaries.size(); i++)
435         {
436             for (unsigned int j = 0; j < (unsigned int)program_binaries.at(i).size(); j++)
437             {
438                 for (unsigned int k = 0; k < (unsigned int)program_binaries.at(i).at(j).size(); k++)
439                 {
440                     char* p = (char*)&program_binaries.at(i).at(j).at(k);
441                     file_stream.write(p, sizeof(char));
442                     offset_temp += sizeof(char);
443                 }
444             }
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);
448         }
449     }
450
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)
453     {
454         auto offset = 0ull;
455         char * ptr = (char*)mem.lock();
456         for (unsigned int x = 0; x < (unsigned int)mem.get_layout().count(); x++)
457         {
458             stream.write(ptr + offset, type);
459             offset += type;
460         }
461         mem.unlock();
462         total_offset += offset;
463     }
464 }
465
466