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
72namespace dnnl {
73namespace impl {
74
75static setting_t<int> verbose {0};
76int 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
123static setting_t<bool> verbose_timestamp {false};
124bool 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
140double 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)
155void pd_info_t::init(
156 dnnl::impl::engine_t *, const dnnl::impl::primitive_desc_t *) {}
157
158#else
159
160std::ostream &operator<<(std::ostream &ss, engine_kind_t eng_kind) {
161 ss << dnnl_engine_kind2str(eng_kind);
162 return ss;
163}
164
165std::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
172const 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
179std::ostream &operator<<(std::ostream &ss, primitive_kind_t prim_kind) {
180 ss << prim_kind2str(prim_kind);
181 return ss;
182}
183
184std::ostream &operator<<(std::ostream &ss, prop_kind_t prop_kind) {
185 ss << dnnl_prop_kind2str(prop_kind);
186 return ss;
187}
188
189std::ostream &operator<<(std::ostream &ss, data_type_t data_type) {
190 ss << dnnl_dt2str(data_type);
191 return ss;
192}
193
194std::ostream &operator<<(std::ostream &ss, alg_kind_t alg) {
195 ss << dnnl_alg_kind2str(alg);
196 return ss;
197}
198
199std::ostream &operator<<(std::ostream &ss, format_kind_t format_kind) {
200 ss << dnnl_fmt_kind2str(format_kind);
201 return ss;
202}
203
204std::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
214std::ostream &operator<<(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
227std::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)
280std::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
307std::ostream &operator<<(std::ostream &ss, const memory_desc_t *md) {
308 ss << md2fmt_str(md);
309 return ss;
310}
311
312template <typename T>
313static 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 `*`.
322std::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.
337std::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
354std::ostream &operator<<(std::ostream &ss, const runtime_scales_t &oscale) {
355 ss << oscale.mask_;
356 return ss;
357}
358
359std::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
369namespace {
370int 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
380std::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
401std::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
408std::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 */
523namespace {
524
525template <typename pd_t>
526static 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
545template <typename pd_t>
546static 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
563template <typename pd_t>
564static 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
588template <typename pd_t>
589static 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
627template <typename pd_t>
628static std::string init_info_deconvolution(const engine_t *e, const pd_t *pd) {
629 return init_info_convolution(e, pd);
630}
631
632template <typename pd_t>
633static 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
652template <typename pd_t>
653static 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
681template <typename pd_t>
682static 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
704template <typename pd_t>
705static 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
724template <typename pd_t>
725static 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
757template <typename pd_t>
758static 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
787template <typename pd_t>
788static 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
809template <typename pd_t>
810static 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
827template <typename pd_t>
828static 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
852template <typename pd_t>
853static 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
874template <typename pd_t>
875static 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
933template <typename pd_t>
934static 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
949template <typename pd_t>
950static 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
971template <typename pd_t>
972static 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
992void 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
1036dnnl_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
1043const 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