1 | /******************************************************************************* |
2 | * Copyright 2018-2022 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 | #include <atomic> |
18 | #include <sstream> |
19 | #include <type_traits> |
20 | |
21 | #include <stdlib.h> |
22 | #ifndef _WIN32 |
23 | #include <sys/time.h> |
24 | #else |
25 | #include <windows.h> |
26 | #endif |
27 | |
28 | #include "oneapi/dnnl/dnnl.h" |
29 | #include "oneapi/dnnl/dnnl_debug.h" |
30 | #include "oneapi/dnnl/dnnl_version.h" |
31 | |
32 | #include "c_types_map.hpp" |
33 | #include "verbose.hpp" |
34 | |
35 | #include "batch_normalization_pd.hpp" |
36 | #include "binary_pd.hpp" |
37 | #include "concat_pd.hpp" |
38 | #include "convolution_pd.hpp" |
39 | #include "deconvolution_pd.hpp" |
40 | #include "eltwise_pd.hpp" |
41 | #include "inner_product_pd.hpp" |
42 | #include "layer_normalization_pd.hpp" |
43 | #include "lrn_pd.hpp" |
44 | #include "matmul_pd.hpp" |
45 | #include "pooling_pd.hpp" |
46 | #include "prelu_pd.hpp" |
47 | #include "reduction_pd.hpp" |
48 | #include "reorder_pd.hpp" |
49 | #include "resampling_pd.hpp" |
50 | #include "rnn_pd.hpp" |
51 | #include "shuffle_pd.hpp" |
52 | #include "softmax_pd.hpp" |
53 | #include "sum_pd.hpp" |
54 | |
55 | #if DNNL_CPU_RUNTIME != DNNL_RUNTIME_NONE |
56 | #include "common/dnnl_thread.hpp" |
57 | #include "cpu/platform.hpp" |
58 | #endif |
59 | |
60 | #if DNNL_GPU_RUNTIME == DNNL_RUNTIME_OCL |
61 | #include "gpu/ocl/verbose.hpp" |
62 | #endif |
63 | |
64 | #ifdef DNNL_WITH_SYCL |
65 | #include "sycl/verbose.hpp" |
66 | #endif |
67 | |
68 | #ifdef DNNL_EXPERIMENTAL |
69 | #include "common/experimental.hpp" |
70 | #endif |
71 | |
72 | namespace dnnl { |
73 | namespace impl { |
74 | |
75 | static setting_t<int> verbose {0}; |
76 | int get_verbose() { |
77 | #if defined(DISABLE_VERBOSE) |
78 | return 0; |
79 | #else |
80 | if (!verbose.initialized()) { |
81 | // Assumes that all threads see the same environment |
82 | static int val = getenv_int_user("VERBOSE" , verbose.get()); |
83 | verbose.set(val); |
84 | } |
85 | |
86 | static std::atomic_flag version_printed = ATOMIC_FLAG_INIT; |
87 | if (verbose.get() > 0 && !version_printed.test_and_set()) { |
88 | printf("onednn_verbose,info,oneDNN v%d.%d.%d (commit %s)\n" , |
89 | dnnl_version()->major, dnnl_version()->minor, |
90 | dnnl_version()->patch, dnnl_version()->hash); |
91 | #if DNNL_CPU_RUNTIME != DNNL_RUNTIME_NONE |
92 | printf("onednn_verbose,info,cpu,runtime:%s,nthr:%d\n" , |
93 | dnnl_runtime2str(dnnl_version()->cpu_runtime), |
94 | dnnl_get_max_threads()); |
95 | printf("onednn_verbose,info,cpu,isa:%s\n" , |
96 | cpu::platform::get_isa_info()); |
97 | #endif |
98 | printf("onednn_verbose,info,gpu,runtime:%s\n" , |
99 | dnnl_runtime2str(dnnl_version()->gpu_runtime)); |
100 | #if DNNL_GPU_RUNTIME == DNNL_RUNTIME_OCL |
101 | gpu::ocl::print_verbose_header(); |
102 | #endif |
103 | #ifdef DNNL_WITH_SYCL |
104 | sycl::print_verbose_header(); |
105 | #endif |
106 | #ifdef DNNL_EXPERIMENTAL |
107 | printf("onednn_verbose,info,experimental features are enabled\n" ); |
108 | printf("onednn_verbose,info,use batch_normalization stats one pass is " |
109 | "%s\n" , |
110 | experimental::use_bnorm_stats_one_pass() ? "enabled" |
111 | : "disabled" ); |
112 | #endif |
113 | printf("onednn_verbose,info,prim_template:" ); |
114 | printf("%soperation,engine,primitive,implementation,prop_" |
115 | "kind,memory_descriptors,attributes,auxiliary,problem_desc,exec_" |
116 | "time\n" , |
117 | get_verbose_timestamp() ? "timestamp," : "" ); |
118 | } |
119 | return verbose.get(); |
120 | #endif |
121 | } |
122 | |
123 | static setting_t<bool> verbose_timestamp {false}; |
124 | bool get_verbose_timestamp() { |
125 | #if defined(DISABLE_VERBOSE) |
126 | return false; |
127 | #else |
128 | if (verbose.get() == 0) return false; |
129 | |
130 | if (!verbose_timestamp.initialized()) { |
131 | // Assumes that all threads see the same environment |
132 | static bool val |
133 | = getenv_int_user("VERBOSE_TIMESTAMP" , verbose_timestamp.get()); |
134 | verbose_timestamp.set(val); |
135 | } |
136 | return verbose_timestamp.get(); |
137 | #endif |
138 | } |
139 | |
140 | double get_msec() { |
141 | #ifdef _WIN32 |
142 | static LARGE_INTEGER frequency; |
143 | if (frequency.QuadPart == 0) QueryPerformanceFrequency(&frequency); |
144 | LARGE_INTEGER now; |
145 | QueryPerformanceCounter(&now); |
146 | return 1e+3 * now.QuadPart / frequency.QuadPart; |
147 | #else |
148 | struct timeval time; |
149 | gettimeofday(&time, nullptr); |
150 | return 1e+3 * time.tv_sec + 1e-3 * time.tv_usec; |
151 | #endif |
152 | } |
153 | |
154 | #if defined(DISABLE_VERBOSE) |
155 | void pd_info_t::init( |
156 | dnnl::impl::engine_t *, const dnnl::impl::primitive_desc_t *) {} |
157 | |
158 | #else |
159 | |
160 | std::ostream &operator<<(std::ostream &ss, engine_kind_t eng_kind) { |
161 | ss << dnnl_engine_kind2str(eng_kind); |
162 | return ss; |
163 | } |
164 | |
165 | std::ostream &operator<<(std::ostream &ss, const engine_t *engine) { |
166 | ss << dnnl_engine_kind2str(engine->kind()); |
167 | if (dnnl_engine_get_count(engine->kind()) > 1) |
168 | ss << ":" + std::to_string(engine->index()); |
169 | return ss; |
170 | } |
171 | |
172 | const char *prim_kind2str(primitive_kind_t prim_kind) { |
173 | switch ((int)prim_kind) { |
174 | case primitive_kind::zero_pad: return "zero_pad" ; |
175 | default: return dnnl_prim_kind2str(prim_kind); |
176 | } |
177 | } |
178 | |
179 | std::ostream &operator<<(std::ostream &ss, primitive_kind_t prim_kind) { |
180 | ss << prim_kind2str(prim_kind); |
181 | return ss; |
182 | } |
183 | |
184 | std::ostream &operator<<(std::ostream &ss, prop_kind_t prop_kind) { |
185 | ss << dnnl_prop_kind2str(prop_kind); |
186 | return ss; |
187 | } |
188 | |
189 | std::ostream &operator<<(std::ostream &ss, data_type_t data_type) { |
190 | ss << dnnl_dt2str(data_type); |
191 | return ss; |
192 | } |
193 | |
194 | std::ostream &operator<<(std::ostream &ss, alg_kind_t alg) { |
195 | ss << dnnl_alg_kind2str(alg); |
196 | return ss; |
197 | } |
198 | |
199 | std::ostream &operator<<(std::ostream &ss, format_kind_t format_kind) { |
200 | ss << dnnl_fmt_kind2str(format_kind); |
201 | return ss; |
202 | } |
203 | |
204 | std::string flags2str(unsigned flags) { |
205 | std::string s; |
206 | if (flags & normalization_flags::use_global_stats) s += "G" ; |
207 | if (flags & normalization_flags::use_scale) s += "C" ; |
208 | if (flags & normalization_flags::use_shift) s += "H" ; |
209 | if (flags & normalization_flags::fuse_norm_relu) s += "R" ; |
210 | if (flags & normalization_flags::fuse_norm_add_relu) s += "A" ; |
211 | return s; |
212 | } |
213 | |
214 | std::ostream &(std::ostream &ss, const memory_extra_desc_t &extra) { |
215 | using namespace memory_extra_flags; |
216 | |
217 | ss << ":f" << extra.flags; |
218 | if (extra.flags & compensation_conv_s8s8) |
219 | ss << ":s8m" << extra.compensation_mask; |
220 | if (extra.flags & compensation_conv_asymmetric_src) |
221 | ss << ":zpm" << extra.asymm_compensation_mask; |
222 | if (extra.flags & scale_adjust && extra.scale_adjust != 1.f) |
223 | ss << ":sa" << extra.scale_adjust; |
224 | return ss; |
225 | } |
226 | |
227 | std::string md2fmt_tag_str(const memory_desc_t *md) { |
228 | memory_desc_wrapper mdw(md); |
229 | |
230 | const auto &blk = mdw.blocking_desc(); |
231 | |
232 | dims_t blocks = {0}; |
233 | mdw.compute_blocks(blocks); |
234 | |
235 | char dim_chars[DNNL_MAX_NDIMS + 1]; |
236 | |
237 | dims_t ou_blocks = {0}; |
238 | utils::array_copy(ou_blocks, mdw.padded_dims(), mdw.ndims()); |
239 | |
240 | bool plain = true; |
241 | for (int d = 0; d < mdw.ndims(); ++d) { |
242 | dim_chars[d] = (blocks[d] == 1 ? 'a' : 'A') + (char)d; |
243 | if (blocks[d] != 1) plain = false; |
244 | ou_blocks[d] /= blocks[d]; |
245 | } |
246 | |
247 | // Can't report meaningful tag for runtime dimensions. |
248 | if (mdw.has_runtime_strides()) return "*" ; |
249 | |
250 | dims_t strides; |
251 | utils::array_copy(strides, blk.strides, mdw.ndims()); |
252 | |
253 | utils::simultaneous_sort(strides, ou_blocks, dim_chars, mdw.ndims(), |
254 | [](dim_t a, dim_t b) { return b - a; }); |
255 | |
256 | dim_chars[mdw.ndims()] = '\0'; |
257 | |
258 | std::string s(dim_chars); |
259 | |
260 | if (!plain) { |
261 | for (int iblk = 0; iblk < blk.inner_nblks; ++iblk) { |
262 | char c = ('a' + (char)blk.inner_idxs[iblk]); |
263 | s += (std::to_string(blk.inner_blks[iblk]) + c); |
264 | } |
265 | } |
266 | return s; |
267 | } |
268 | |
269 | // Forms a format string for a given memory descriptor. |
270 | // |
271 | // The format is defined as: 'dt:[p|o|0]:fmt_kind:fmt:extra'. |
272 | // Here: |
273 | // - dt -- data type |
274 | // - p -- indicates there is non-trivial padding |
275 | // - o -- indicates there is non-trivial padding offset |
276 | // - 0 -- indicates there is non-trivial offset0 |
277 | // - fmt_kind -- format kind (blocked, wino, etc...) |
278 | // - fmt -- extended format string (format_kind specific) |
279 | // - extra -- shows extra fields (underspecified) |
280 | std::string md2fmt_str(const memory_desc_t *md) { |
281 | std::stringstream ss; |
282 | if (!md) { |
283 | ss << data_type::undef << "::" << format_kind::undef << "::" ; |
284 | return ss.str(); |
285 | } |
286 | |
287 | memory_desc_wrapper mdw(md); |
288 | ss << mdw.data_type() << ":" ; |
289 | |
290 | bool padded_dims = false, padded_offsets = false; |
291 | for (int d = 0; d < mdw.ndims(); ++d) { |
292 | if (mdw.dims()[d] != mdw.padded_dims()[d]) padded_dims = true; |
293 | if (mdw.padded_offsets()[d] != 0) padded_offsets = true; |
294 | } |
295 | bool offset0 = mdw.offset0(); |
296 | ss << (padded_dims ? "p" : "" ) << (padded_offsets ? "o" : "" ); |
297 | ss << (offset0 ? "0" : "" ) << ":" << mdw.format_kind() << ":" ; |
298 | |
299 | if (mdw.is_blocking_desc()) ss << md2fmt_tag_str(md); |
300 | |
301 | ss << mdw.extra(); |
302 | |
303 | return ss.str(); |
304 | } |
305 | |
306 | // Puts memory_desc information into stream without dimensions |
307 | std::ostream &operator<<(std::ostream &ss, const memory_desc_t *md) { |
308 | ss << md2fmt_str(md); |
309 | return ss; |
310 | } |
311 | |
312 | template <typename T> |
313 | static std::string get_val_str(T val) { |
314 | static_assert( |
315 | std::is_arithmetic<T>::value, "T must be an arithmetic type." ); |
316 | if (is_runtime_value(val)) return std::string("*" ); |
317 | return std::to_string(val); |
318 | } |
319 | |
320 | // Returns string with dimensions from a given memory descriptor. |
321 | // The format is defined as: dim0xdim1x...xdimN, with RT values signed as `*`. |
322 | std::string md2dim_str(const memory_desc_t *md) { |
323 | if (md == nullptr || md->ndims == 0) return "" ; |
324 | |
325 | memory_desc_wrapper mdw(md); |
326 | std::string s; |
327 | |
328 | s += get_val_str(mdw.dims()[0]); |
329 | for (int d = 1; d < mdw.ndims(); ++d) |
330 | s += ("x" + get_val_str(mdw.dims()[d])); |
331 | |
332 | return s; |
333 | } |
334 | |
335 | // Returns string with descriptor style from memory_desc since there's an |
336 | // operator<< for memory_desc. |
337 | std::string md2desc_str(const memory_desc_t *md) { |
338 | const auto dims = md->dims; |
339 | std::string s; |
340 | if (md->ndims >= 6) return md2dim_str(md); |
341 | |
342 | if (md->ndims == 1) { |
343 | s += "x" + std::to_string(dims[0]); |
344 | return s; |
345 | } |
346 | |
347 | s += "mb" + std::to_string(dims[0]) + "ic" + std::to_string(dims[1]); |
348 | if (md->ndims >= 5) s += "id" + std::to_string(dims[md->ndims - 3]); |
349 | if (md->ndims >= 4) s += "ih" + std::to_string(dims[md->ndims - 2]); |
350 | if (md->ndims >= 3) s += "iw" + std::to_string(dims[md->ndims - 1]); |
351 | return s; |
352 | } |
353 | |
354 | std::ostream &operator<<(std::ostream &ss, const runtime_scales_t &oscale) { |
355 | ss << oscale.mask_; |
356 | return ss; |
357 | } |
358 | |
359 | std::ostream &operator<<(std::ostream &ss, const scales_t &oscale) { |
360 | ss << oscale.mask_; |
361 | const float val = oscale.scales_[0]; |
362 | // Can't use scientific flags since it breaks parsing on converter and |
363 | // benchdnn side. |
364 | if (oscale.mask_ == 0 || is_runtime_value(val)) |
365 | ss << ":" << get_val_str(val); |
366 | return ss; |
367 | } |
368 | |
369 | namespace { |
370 | int get_arg_index(int arg) { |
371 | if (arg & DNNL_ARG_MULTIPLE_SRC) return arg - DNNL_ARG_MULTIPLE_SRC; |
372 | switch (arg) { |
373 | case DNNL_ARG_SRC_0: return 0; |
374 | case DNNL_ARG_SRC_1: return 1; |
375 | default: return -1; |
376 | } |
377 | return -1; |
378 | } |
379 | |
380 | std::string get_arg(int arg) { |
381 | if (arg & DNNL_ARG_MULTIPLE_SRC) return "msrc" ; |
382 | |
383 | std::string s; |
384 | switch (arg) { |
385 | case DNNL_ARG_SRC: // DNNL_ARG_SRC_0 |
386 | case DNNL_ARG_SRC_1: s = "src" ; break; |
387 | case DNNL_ARG_DST: s = "dst" ; break; |
388 | case DNNL_ARG_WEIGHTS: s = "wei" ; break; |
389 | case DNNL_ARG_ATTR_POST_OP_DW | DNNL_ARG_DST: |
390 | s = "attr_post_op_dw_dst" ; |
391 | break; |
392 | case DNNL_ARG_ATTR_POST_OP_DW | DNNL_ARG_WEIGHTS: |
393 | s = "attr_post_op_dw_wei" ; |
394 | break; |
395 | default: assert(!"unsupported arg" ); s = "unsupported arg" ; |
396 | } |
397 | return s; |
398 | } |
399 | } // namespace |
400 | |
401 | std::string arg2str(int arg) { |
402 | std::string s = get_arg(arg); |
403 | const int idx = get_arg_index(arg); |
404 | if (idx != -1) s += std::to_string(idx); |
405 | return s; |
406 | } |
407 | |
408 | std::ostream &operator<<(std::ostream &ss, const primitive_attr_t *attr) { |
409 | // scratchpad and fpmath mode are not a part of |
410 | // has_default_values(). Check them first. |
411 | const scratchpad_mode_t &spm = attr->scratchpad_mode_; |
412 | if (spm != scratchpad_mode_t::dnnl_scratchpad_mode_library) { |
413 | ss << "attr-scratchpad:" << dnnl_scratchpad_mode2str(spm) << " " ; |
414 | } |
415 | const fpmath_mode_t &fpm = attr->fpmath_mode_; |
416 | if (fpm != fpmath_mode_t::dnnl_fpmath_mode_strict) { |
417 | ss << "attr-fpmath:" << dnnl_fpmath_mode2str(fpm) << " " ; |
418 | } |
419 | |
420 | if (attr->has_default_values()) return ss; |
421 | |
422 | const runtime_scales_t &os = attr->output_scales_; |
423 | if (!os.has_default_values()) { ss << "attr-oscale:" << os << " " ; } |
424 | |
425 | std::string empty_delim, attr_delim = "+" ; |
426 | |
427 | const arg_scales_t &as = attr->scales_; |
428 | if (!as.has_default_values()) { |
429 | std::string delim = empty_delim; |
430 | ss << "attr-scales:" ; |
431 | for (const auto &map_entry : as.scales_) { |
432 | const auto &val = map_entry.second; |
433 | if (val.has_default_values()) continue; |
434 | |
435 | int arg = map_entry.first; |
436 | ss << delim << arg2str(arg) << ":" << val; |
437 | delim = attr_delim; |
438 | } |
439 | ss << " " ; |
440 | } |
441 | |
442 | const zero_points_t &zp = attr->zero_points_; |
443 | if (!zp.has_default_values()) { |
444 | std::string delim = empty_delim; |
445 | ss << "attr-zero-points:" ; |
446 | for (const auto &arg : {DNNL_ARG_SRC, DNNL_ARG_WEIGHTS, DNNL_ARG_DST}) { |
447 | if (zp.has_default_values(arg)) continue; |
448 | |
449 | int mask = 0; |
450 | zp.get(arg, &mask); |
451 | |
452 | ss << delim << arg2str(arg) << ":" << mask; |
453 | delim = attr_delim; |
454 | } |
455 | ss << " " ; |
456 | } |
457 | |
458 | const post_ops_t &po = attr->post_ops_; |
459 | if (!po.has_default_values()) { |
460 | std::string delim = empty_delim; |
461 | ss << "attr-post-ops:" ; |
462 | for (int i = 0; i < po.len(); ++i) { |
463 | const post_ops_t::entry_t &e = po.entry_[i]; |
464 | switch (e.kind) { |
465 | case primitive_kind::sum: { |
466 | const auto &s = e.sum; |
467 | ss << delim << "sum" ; |
468 | if (s.scale != 1.f || s.zero_point != 0 |
469 | || s.dt != data_type::undef) |
470 | ss << ":" << s.scale; |
471 | if (s.zero_point != 0 || s.dt != data_type::undef) |
472 | ss << ":" << s.zero_point; |
473 | if (s.dt != data_type::undef) ss << ":" << s.dt; |
474 | } break; |
475 | case primitive_kind::convolution: { |
476 | using namespace data_type; |
477 | const auto &c = e.depthwise_conv; |
478 | ss << delim << "dw:k" << c.kernel << "s" << c.stride << "p" |
479 | << c.padding; |
480 | if (c.wei_dt == s8 || c.dst_dt != f32) |
481 | ss << ":" << c.dst_dt; |
482 | } break; |
483 | case primitive_kind::eltwise: { |
484 | const post_ops_t::entry_t::eltwise_t &ew = e.eltwise; |
485 | ss << delim << ew.alg; |
486 | if (ew.alpha != 0.f || ew.beta != 0.f || ew.scale != 1.f) |
487 | ss << ":" << ew.alpha; |
488 | if (ew.beta != 0.f || ew.scale != 1.f) ss << ":" << ew.beta; |
489 | if (ew.scale != 1.f) ss << ":" << ew.scale; |
490 | } break; |
491 | case primitive_kind::binary: { |
492 | const post_ops_t::entry_t::binary_t &eb = e.binary; |
493 | const auto &md = eb.src1_desc; |
494 | int mask = 0; |
495 | for (int d = 0; d < md.ndims; ++d) |
496 | mask += md.dims[d] != 1 ? (1 << d) : 0; |
497 | ss << delim << eb.alg << ":" << md.data_type << ":" << mask; |
498 | if (!memory_desc_wrapper(md).count_non_unit_dims(1)) |
499 | ss << ":" << md2fmt_tag_str(&md); |
500 | } break; |
501 | case primitive_kind::prelu: { |
502 | const auto &ep = e.prelu; |
503 | ss << delim << "prelu" |
504 | << ":" << ep.mask; |
505 | } break; |
506 | default: assert(!"unsupported post op primitive kind!" ); break; |
507 | } |
508 | delim = attr_delim; |
509 | } |
510 | ss << " " ; |
511 | } |
512 | |
513 | const rnn_data_qparams_t &rnn_qp = attr->rnn_data_qparams_; |
514 | if (!rnn_qp.has_default_values()) { |
515 | ss << "rnn_data_qparams:" << rnn_qp.scale_ << ":" << rnn_qp.shift_ |
516 | << ";" ; |
517 | } |
518 | |
519 | return ss; |
520 | } |
521 | |
522 | /* init_info section */ |
523 | namespace { |
524 | |
525 | template <typename pd_t> |
526 | static std::string init_info_batch_normalization( |
527 | const engine_t *e, const pd_t *pd) { |
528 | std::stringstream ss; |
529 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
530 | << pd->desc()->prop_kind << "," ; |
531 | |
532 | auto src_md = pd->src_md(); |
533 | auto diff_src_md = pd->diff_src_md(); |
534 | ss << "data_" << src_md; |
535 | if (diff_src_md) ss << " diff_" << diff_src_md; |
536 | ss << "," ; |
537 | |
538 | ss << pd->attr() << "," ; |
539 | ss << "flags:" << flags2str(pd->desc()->flags) << "," ; |
540 | ss << md2desc_str(src_md); |
541 | |
542 | return ss.str(); |
543 | } |
544 | |
545 | template <typename pd_t> |
546 | static std::string init_info_binary(const engine_t *e, const pd_t *pd) { |
547 | std::stringstream ss; |
548 | ss << e << "," << pd->kind() << "," << pd->name() << "," << prop_kind::undef |
549 | << "," ; |
550 | |
551 | auto src0_md = pd->src_md(0); |
552 | auto src1_md = pd->src_md(1); |
553 | auto dst_md = pd->dst_md(); |
554 | ss << "src_" << src0_md << " src_" << src1_md << " dst_" << dst_md << "," ; |
555 | |
556 | ss << pd->attr() << "," ; |
557 | ss << "alg:" << pd->desc()->alg_kind << "," ; |
558 | ss << md2dim_str(src0_md) << ":" << md2dim_str(src1_md); |
559 | |
560 | return ss.str(); |
561 | } |
562 | |
563 | template <typename pd_t> |
564 | static std::string init_info_concat(const engine_t *e, const pd_t *pd) { |
565 | std::stringstream ss; |
566 | ss << e << "," << pd->kind() << "," << pd->name() << "," << prop_kind::undef |
567 | << "," ; |
568 | |
569 | for (int i = 0; i < pd->n_inputs(); ++i) { |
570 | auto src_i_md = pd->src_md(i); |
571 | ss << "src_" << src_i_md << " " ; |
572 | } |
573 | auto dst_md = pd->dst_md(); |
574 | ss << "dst_" << dst_md << "," ; |
575 | |
576 | ss << pd->attr() << "," ; |
577 | ss << "axis:" << pd->desc()->concat_dimension << "," ; |
578 | |
579 | for (int i = 0; i < pd->n_inputs(); ++i) { |
580 | auto src_i_md = pd->src_md(i); |
581 | ss << md2dim_str(src_i_md); |
582 | if (i < pd->n_inputs() - 1) ss << ":" ; |
583 | } |
584 | |
585 | return ss.str(); |
586 | } |
587 | |
588 | template <typename pd_t> |
589 | static std::string init_info_convolution(const engine_t *e, const pd_t *pd) { |
590 | std::stringstream ss; |
591 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
592 | << pd->desc()->prop_kind << "," ; |
593 | |
594 | auto src_md = pd->desc()->prop_kind == prop_kind::backward_data |
595 | ? pd->diff_src_md() |
596 | : pd->src_md(); |
597 | auto wei_md = pd->desc()->prop_kind == prop_kind::backward_weights |
598 | ? pd->diff_weights_md(0) |
599 | : pd->weights_md(0); |
600 | auto bia_md = pd->desc()->prop_kind == prop_kind::backward_weights |
601 | ? pd->diff_weights_md(1) |
602 | : pd->weights_md(1); |
603 | auto dst_md = !pd->is_fwd() ? pd->diff_dst_md() : pd->dst_md(); |
604 | |
605 | ss << "src_" << src_md << " wei_" << wei_md; |
606 | if (bia_md) ss << " bia_" << bia_md; |
607 | ss << " dst_" << dst_md << "," ; |
608 | |
609 | ss << pd->attr() << "," ; |
610 | ss << "alg:" << pd->desc()->alg_kind << "," ; |
611 | |
612 | if (pd->with_groups()) ss << "g" << pd->G(); |
613 | ss << "mb" << pd->MB() << "_" |
614 | << "ic" << pd->IC() << "oc" << pd->OC() << "_" ; |
615 | if (pd->ndims() >= 5) |
616 | ss << "id" << pd->ID() << "od" << pd->OD() << "kd" << pd->KD() << "sd" |
617 | << pd->KSD() << "dd" << pd->KDD() << "pd" << pd->padFront() << "_" ; |
618 | if (pd->ndims() >= 4) |
619 | ss << "ih" << pd->IH() << "oh" << pd->OH() << "kh" << pd->KH() << "sh" |
620 | << pd->KSH() << "dh" << pd->KDH() << "ph" << pd->padT() << "_" ; |
621 | ss << "iw" << pd->IW() << "ow" << pd->OW() << "kw" << pd->KW() << "sw" |
622 | << pd->KSW() << "dw" << pd->KDW() << "pw" << pd->padL(); |
623 | |
624 | return ss.str(); |
625 | } |
626 | |
627 | template <typename pd_t> |
628 | static std::string init_info_deconvolution(const engine_t *e, const pd_t *pd) { |
629 | return init_info_convolution(e, pd); |
630 | } |
631 | |
632 | template <typename pd_t> |
633 | static std::string init_info_eltwise(const engine_t *e, const pd_t *pd) { |
634 | std::stringstream ss; |
635 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
636 | << pd->desc()->prop_kind << "," ; |
637 | |
638 | auto data_md = pd->use_dst() ? pd->dst_md() : pd->src_md(); |
639 | auto diff_src_md = pd->diff_src_md(); |
640 | ss << "data_" << data_md; |
641 | if (diff_src_md) ss << " diff_" << diff_src_md; |
642 | ss << "," ; |
643 | |
644 | ss << pd->attr() << "," ; |
645 | ss << "alg:" << pd->desc()->alg_kind << " alpha:" << pd->desc()->alpha |
646 | << " beta:" << pd->desc()->beta << "," ; |
647 | ss << md2dim_str(data_md); |
648 | |
649 | return ss.str(); |
650 | } |
651 | |
652 | template <typename pd_t> |
653 | static std::string init_info_inner_product(const engine_t *e, const pd_t *pd) { |
654 | std::stringstream ss; |
655 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
656 | << pd->desc()->prop_kind << "," ; |
657 | |
658 | auto src_md = pd->desc()->prop_kind == prop_kind::backward_data |
659 | ? pd->diff_src_md() |
660 | : pd->src_md(); |
661 | auto wei_md = pd->desc()->prop_kind == prop_kind::backward_weights |
662 | ? pd->diff_weights_md(0) |
663 | : pd->weights_md(0); |
664 | auto bia_md = pd->desc()->prop_kind == prop_kind::backward_weights |
665 | ? pd->diff_weights_md(1) |
666 | : pd->weights_md(1); |
667 | auto dst_md = !pd->is_fwd() ? pd->diff_dst_md() : pd->dst_md(); |
668 | |
669 | ss << "src_" << src_md << " wei_" << wei_md; |
670 | if (bia_md) ss << " bia_" << bia_md; |
671 | ss << " dst_" << dst_md << "," ; |
672 | |
673 | ss << pd->attr() << ",," ; |
674 | |
675 | ss << md2desc_str(src_md); |
676 | ss << "oc" << pd->OC(); |
677 | |
678 | return ss.str(); |
679 | } |
680 | |
681 | template <typename pd_t> |
682 | static std::string init_info_layer_normalization( |
683 | const engine_t *e, const pd_t *pd) { |
684 | std::stringstream ss; |
685 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
686 | << pd->desc()->prop_kind << "," ; |
687 | |
688 | auto src_md = pd->src_md(); |
689 | auto dst_md = pd->is_fwd() ? pd->dst_md() : pd->diff_dst_md(); |
690 | auto stats_md = pd->is_fwd() && !pd->stats_are_src() ? pd->dst_md(1) |
691 | : pd->src_md(1); |
692 | ss << "src_" << src_md << " dst_" << dst_md; |
693 | if (stats_md) ss << " stats_" << stats_md; |
694 | if (pd->is_bwd()) ss << " diff_src_" << pd->diff_src_md(); |
695 | ss << "," ; |
696 | |
697 | ss << pd->attr() << "," ; |
698 | ss << "flags:" << flags2str(pd->desc()->flags) << "," ; |
699 | ss << md2dim_str(src_md); |
700 | |
701 | return ss.str(); |
702 | } |
703 | |
704 | template <typename pd_t> |
705 | static std::string init_info_lrn(const engine_t *e, const pd_t *pd) { |
706 | std::stringstream ss; |
707 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
708 | << pd->desc()->prop_kind << "," ; |
709 | |
710 | auto data_md = pd->src_md(); |
711 | auto diff_src_md = pd->diff_src_md(); |
712 | ss << "data_" << data_md; |
713 | if (diff_src_md) ss << " diff_" << diff_src_md; |
714 | ss << "," ; |
715 | |
716 | ss << pd->attr() << "," ; |
717 | ss << "alg:" << pd->desc()->alg_kind << "," ; |
718 | ss << md2desc_str(data_md); |
719 | ss << "ls" << pd->desc()->local_size << "beta" << pd->desc()->lrn_beta; |
720 | |
721 | return ss.str(); |
722 | } |
723 | |
724 | template <typename pd_t> |
725 | static std::string init_info_matmul(const engine_t *e, const pd_t *pd) { |
726 | std::stringstream ss; |
727 | ss << e << "," << pd->kind() << "," << pd->name() << "," << prop_kind::undef |
728 | << "," ; |
729 | |
730 | auto src_md = pd->src_md(); |
731 | auto wei_md = pd->weights_md(0); |
732 | auto bia_md = pd->weights_md(1); |
733 | auto dst_md = pd->dst_md(); |
734 | |
735 | auto get_bia_mask = [&bia_md]() { |
736 | auto bia_ndims = bia_md->ndims; |
737 | auto bia_dims = bia_md->dims; |
738 | int mask = 0; |
739 | for (int d = bia_ndims - 1; d >= 0; --d) { |
740 | mask += bia_dims[d] != 1 ? 1 << d : 0; |
741 | } |
742 | return mask; |
743 | }; |
744 | |
745 | ss << "src_" << src_md << " wei_" << wei_md; |
746 | if (pd->with_bias()) ss << " bia_" << bia_md << "_mask" << get_bia_mask(); |
747 | ss << " dst_" << dst_md << "," ; |
748 | |
749 | ss << pd->attr() << ",," ; |
750 | |
751 | ss << md2dim_str(src_md) << ":" << md2dim_str(wei_md) << ":" |
752 | << md2dim_str(dst_md); |
753 | |
754 | return ss.str(); |
755 | } |
756 | |
757 | template <typename pd_t> |
758 | static std::string init_info_pooling(const engine_t *e, const pd_t *pd) { |
759 | std::stringstream ss; |
760 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
761 | << pd->desc()->prop_kind << "," ; |
762 | |
763 | auto src_md = pd->is_fwd() ? pd->src_md() : pd->diff_src_md(); |
764 | auto dst_md = pd->is_fwd() ? pd->dst_md() : pd->diff_dst_md(); |
765 | auto ws_md = pd->workspace_md(); |
766 | |
767 | ss << "src_" << src_md << " dst_" << dst_md; |
768 | if (ws_md) ss << " ws_" << ws_md; |
769 | ss << "," ; |
770 | |
771 | ss << pd->attr() << "," ; |
772 | ss << "alg:" << pd->desc()->alg_kind << "," ; |
773 | |
774 | ss << "mb" << pd->MB() << "ic" << pd->IC() << "_" ; |
775 | if (pd->ndims() >= 5) |
776 | ss << "id" << pd->ID() << "od" << pd->OD() << "kd" << pd->KD() << "sd" |
777 | << pd->KSD() << "dd" << pd->KDD() << "pd" << pd->padFront() << "_" ; |
778 | if (pd->ndims() >= 4) |
779 | ss << "ih" << pd->IH() << "oh" << pd->OH() << "kh" << pd->KH() << "sh" |
780 | << pd->KSH() << "dh" << pd->KDH() << "ph" << pd->padT() << "_" ; |
781 | ss << "iw" << pd->IW() << "ow" << pd->OW() << "kw" << pd->KW() << "sw" |
782 | << pd->KSW() << "dw" << pd->KDW() << "pw" << pd->padL(); |
783 | |
784 | return ss.str(); |
785 | } |
786 | |
787 | template <typename pd_t> |
788 | static std::string init_info_prelu(const engine_t *e, const pd_t *pd) { |
789 | std::stringstream ss; |
790 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
791 | << pd->desc()->prop_kind << "," ; |
792 | |
793 | auto data_md = pd->src_md(0); |
794 | auto wei_md = pd->weights_md(0); |
795 | auto diff_data_md = pd->diff_src_md(0); |
796 | auto diff_wei_md = pd->diff_weights_md(0); |
797 | |
798 | ss << "data_" << data_md << " wei_" << wei_md; |
799 | if (diff_data_md) ss << " diff_" << diff_data_md; |
800 | if (diff_wei_md) ss << " diff_wei_" << diff_wei_md; |
801 | ss << "," ; |
802 | |
803 | ss << pd->attr() << ",," ; |
804 | ss << md2dim_str(data_md) << ":" << md2dim_str(wei_md); |
805 | |
806 | return ss.str(); |
807 | } |
808 | |
809 | template <typename pd_t> |
810 | static std::string init_info_reduction(const engine_t *e, const pd_t *pd) { |
811 | std::stringstream ss; |
812 | ss << e << "," << pd->kind() << "," << pd->name() << "," << prop_kind::undef |
813 | << "," ; |
814 | |
815 | auto src_md = pd->src_md(); |
816 | auto dst_md = pd->dst_md(); |
817 | ss << "src_" << src_md << " dst_" << dst_md << "," ; |
818 | |
819 | ss << pd->attr() << "," ; |
820 | ss << "alg:" << pd->desc()->alg_kind << " p:" << pd->desc()->p |
821 | << " eps:" << pd->desc()->eps << "," ; |
822 | ss << md2dim_str(src_md) << ":" << md2dim_str(dst_md); |
823 | |
824 | return ss.str(); |
825 | } |
826 | |
827 | template <typename pd_t> |
828 | static std::string init_info_reorder(const engine_t *e, pd_t *pd) { |
829 | std::stringstream ss; |
830 | |
831 | const auto src_ek = pd->desc()->src_engine_kind; |
832 | const auto dst_ek = pd->desc()->dst_engine_kind; |
833 | |
834 | if (src_ek != dst_ek) |
835 | ss << src_ek << "2" << dst_ek; |
836 | else |
837 | ss << e; |
838 | |
839 | ss << "," << pd->kind() << "," << pd->name() << "," << prop_kind::undef |
840 | << "," ; |
841 | |
842 | auto src_md = pd->src_md(); |
843 | auto dst_md = pd->dst_md(); |
844 | ss << "src_" << src_md << " dst_" << dst_md << "," ; |
845 | |
846 | ss << pd->attr() << ",," ; |
847 | ss << md2dim_str(dst_md); |
848 | |
849 | return ss.str(); |
850 | } |
851 | |
852 | template <typename pd_t> |
853 | static std::string init_info_resampling(const engine_t *e, const pd_t *pd) { |
854 | std::stringstream ss; |
855 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
856 | << pd->desc()->prop_kind << "," ; |
857 | |
858 | auto src_md = pd->is_fwd() ? pd->src_md() : pd->diff_src_md(); |
859 | auto dst_md = pd->is_fwd() ? pd->dst_md() : pd->diff_dst_md(); |
860 | |
861 | ss << "src_" << src_md << " dst_" << dst_md << "," ; |
862 | |
863 | ss << pd->attr() << "," ; |
864 | ss << "alg:" << pd->desc()->alg_kind << "," ; |
865 | |
866 | ss << "mb" << pd->MB() << "ic" << pd->C() << "_" ; |
867 | if (pd->ndims() >= 5) ss << "id" << pd->ID() << "od" << pd->OD() << "_" ; |
868 | if (pd->ndims() >= 4) ss << "ih" << pd->IH() << "oh" << pd->OH() << "_" ; |
869 | ss << "iw" << pd->IW() << "ow" << pd->OW(); |
870 | |
871 | return ss.str(); |
872 | } |
873 | |
874 | template <typename pd_t> |
875 | static std::string init_info_rnn(const engine_t *e, const pd_t *pd) { |
876 | std::stringstream ss; |
877 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
878 | << pd->desc()->prop_kind << "," ; |
879 | |
880 | auto tensor_sep = "" ; |
881 | auto print_tensor = [&](bool cond, int arg_idx, const char *arg_str) { |
882 | if (cond) { |
883 | auto md = pd->arg_md(arg_idx); |
884 | ss << tensor_sep << arg_str << "_" << md; |
885 | } |
886 | tensor_sep = " " ; |
887 | }; |
888 | |
889 | // TODO: shorten the names to consume fewer characters on verbose |
890 | // output |
891 | print_tensor(true, DNNL_ARG_SRC_LAYER, "src_layer" ); |
892 | print_tensor(pd->with_src_iter(), DNNL_ARG_SRC_ITER, "src_iter" ); |
893 | print_tensor(true, DNNL_ARG_WEIGHTS_LAYER, "wei_layer" ); |
894 | print_tensor(true, DNNL_ARG_WEIGHTS_ITER, "wei_iter" ); |
895 | print_tensor( |
896 | pd->is_lstm_peephole(), DNNL_ARG_WEIGHTS_PEEPHOLE, "wei_peephole" ); |
897 | print_tensor( |
898 | pd->is_lstm_projection(), DNNL_ARG_WEIGHTS_PROJECTION, "wei_proj" ); |
899 | print_tensor(pd->with_bias(), DNNL_ARG_BIAS, "bias" ); |
900 | print_tensor(true, DNNL_ARG_DST_LAYER, "dst_layer" ); |
901 | print_tensor(pd->with_dst_iter(), DNNL_ARG_DST_ITER, "dst_iter" ); |
902 | |
903 | if (!pd->is_fwd()) { |
904 | print_tensor(true, DNNL_ARG_DIFF_SRC_LAYER, "diff_src_layer" ); |
905 | print_tensor( |
906 | pd->with_src_iter(), DNNL_ARG_DIFF_SRC_ITER, "diff_src_iter" ); |
907 | print_tensor(true, DNNL_ARG_DIFF_WEIGHTS_LAYER, "diff_wei_layer" ); |
908 | print_tensor(true, DNNL_ARG_DIFF_WEIGHTS_ITER, "diff_wei_iter" ); |
909 | print_tensor(pd->is_lstm_peephole(), DNNL_ARG_DIFF_WEIGHTS_PEEPHOLE, |
910 | "diff_wei_peephole" ); |
911 | print_tensor(pd->is_lstm_projection(), DNNL_ARG_DIFF_WEIGHTS_PROJECTION, |
912 | "diff_wei_proj" ); |
913 | print_tensor(pd->with_bias(), DNNL_ARG_DIFF_BIAS, "diff_bias" ); |
914 | print_tensor(true, DNNL_ARG_DIFF_DST_LAYER, "diff_dst_layer" ); |
915 | print_tensor( |
916 | pd->with_dst_iter(), DNNL_ARG_DIFF_DST_ITER, "diff_dst_iter" ); |
917 | } |
918 | |
919 | ss << "," ; |
920 | |
921 | ss << pd->attr() << "," ; |
922 | ss << "alg:" << pd->cell_kind() |
923 | << " direction:" << dnnl_rnn_direction2str(pd->direction()) |
924 | << " activation:" << pd->activation_kind() << "," ; |
925 | |
926 | ss << "l" << pd->L() << "t" << pd->T() << "mb" << pd->MB() << "sic" |
927 | << pd->SIC() << "slc" << pd->SLC() << "dhc" << pd->DHC() << "dic" |
928 | << pd->DIC(); |
929 | |
930 | return ss.str(); |
931 | } |
932 | |
933 | template <typename pd_t> |
934 | static std::string init_info_shuffle(const engine_t *e, const pd_t *pd) { |
935 | std::stringstream ss; |
936 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
937 | << pd->desc()->prop_kind << "," ; |
938 | |
939 | auto data_md = pd->is_fwd() ? pd->src_md() : pd->diff_src_md(); |
940 | ss << "data_" << data_md << "," ; |
941 | |
942 | ss << pd->attr() << "," ; |
943 | ss << "axis:" << pd->axis() << " group:" << pd->group_size() << "," ; |
944 | ss << md2dim_str(data_md); |
945 | |
946 | return ss.str(); |
947 | } |
948 | |
949 | template <typename pd_t> |
950 | static std::string init_info_softmax(const engine_t *e, const pd_t *pd) { |
951 | std::stringstream ss; |
952 | ss << e << "," << pd->kind() << "," << pd->name() << "," |
953 | << pd->desc()->prop_kind << "," ; |
954 | |
955 | auto src_md = pd->is_fwd() ? pd->src_md() : pd->diff_src_md(); |
956 | auto dst_md = pd->dst_md(); |
957 | ss << "src_" << src_md << " dst_" << dst_md; |
958 | if (!pd->is_fwd()) { |
959 | auto diff_dst_md = pd->diff_dst_md(); |
960 | ss << " diff_dst_" << diff_dst_md; |
961 | } |
962 | ss << "," ; |
963 | |
964 | ss << pd->attr() << "," ; |
965 | ss << "alg:" << pd->alg_kind() << " axis:" << pd->axis() << "," ; |
966 | ss << md2dim_str(src_md); |
967 | |
968 | return ss.str(); |
969 | } |
970 | |
971 | template <typename pd_t> |
972 | static std::string init_info_sum(const engine_t *e, const pd_t *pd) { |
973 | std::stringstream ss; |
974 | ss << e << "," << pd->kind() << "," << pd->name() << "," << prop_kind::undef |
975 | << "," ; |
976 | |
977 | for (int i = 0; i < pd->n_inputs(); ++i) { |
978 | auto src_i_md = pd->src_md(i); |
979 | ss << "src_" << src_i_md << " " ; |
980 | } |
981 | auto dst_md = pd->dst_md(); |
982 | ss << "dst_" << dst_md << "," ; |
983 | |
984 | ss << pd->attr() << ",," ; |
985 | ss << md2dim_str(dst_md); |
986 | |
987 | return ss.str(); |
988 | } |
989 | |
990 | } // namespace |
991 | |
992 | void pd_info_t::init(engine_t *engine, const primitive_desc_t *pd) { |
993 | if (is_initialized_) return; |
994 | |
995 | std::call_once(initialization_flag_, [&] { |
996 | // clang-format off |
997 | #define CASE(kind) \ |
998 | case primitive_kind::kind: \ |
999 | str_ = init_info_##kind(engine, (const kind##_pd_t *)pd); \ |
1000 | break |
1001 | |
1002 | switch ((int)pd->kind()) { |
1003 | CASE(batch_normalization); |
1004 | CASE(binary); |
1005 | CASE(concat); |
1006 | CASE(convolution); |
1007 | CASE(deconvolution); |
1008 | CASE(eltwise); |
1009 | CASE(inner_product); |
1010 | CASE(layer_normalization); |
1011 | CASE(lrn); |
1012 | CASE(matmul); |
1013 | CASE(pooling); |
1014 | CASE(prelu); |
1015 | CASE(reduction); |
1016 | CASE(reorder); |
1017 | CASE(resampling); |
1018 | CASE(rnn); |
1019 | CASE(shuffle); |
1020 | CASE(softmax); |
1021 | CASE(sum); |
1022 | case primitive_kind::zero_pad: break; |
1023 | default: assert(!"unknown primitive kind" ); |
1024 | } |
1025 | #undef CASE |
1026 | // clang-format on |
1027 | |
1028 | is_initialized_ = true; |
1029 | }); |
1030 | } |
1031 | #endif |
1032 | |
1033 | } // namespace impl |
1034 | } // namespace dnnl |
1035 | |
1036 | dnnl_status_t dnnl_set_verbose(int level) { |
1037 | using namespace dnnl::impl::status; |
1038 | if (level < 0 || level > 2) return invalid_arguments; |
1039 | dnnl::impl::verbose.set(level); |
1040 | return success; |
1041 | } |
1042 | |
1043 | const dnnl_version_t *dnnl_version(void) { |
1044 | static const dnnl_version_t ver |
1045 | = {DNNL_VERSION_MAJOR, DNNL_VERSION_MINOR, DNNL_VERSION_PATCH, |
1046 | DNNL_VERSION_HASH, DNNL_CPU_RUNTIME, DNNL_GPU_RUNTIME}; |
1047 | return &ver; |
1048 | } |
1049 | |