1 | /******************************************************************************* |
2 | * Copyright 2019-2021 Intel Corporation |
3 | * Copyright 2021 FUJITSU LIMITED |
4 | * |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | * you may not use this file except in compliance with the License. |
7 | * You may obtain a copy of the License at |
8 | * |
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | * |
11 | * Unless required by applicable law or agreed to in writing, software |
12 | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | * See the License for the specific language governing permissions and |
15 | * limitations under the License. |
16 | *******************************************************************************/ |
17 | |
18 | #include <mutex> |
19 | |
20 | #include "common/utils.hpp" |
21 | |
22 | #include "cpu/platform.hpp" |
23 | |
24 | #ifndef DNNL_ENABLE_JIT_PROFILING |
25 | #define DNNL_ENABLE_JIT_PROFILING 1 |
26 | #endif |
27 | |
28 | #ifndef DNNL_ENABLE_JIT_DUMP |
29 | #define DNNL_ENABLE_JIT_DUMP 1 |
30 | #endif |
31 | |
32 | #if DNNL_ENABLE_JIT_PROFILING |
33 | #include "common/ittnotify/jitprofiling.h" |
34 | #ifdef __linux__ |
35 | #include "cpu/jit_utils/linux_perf/linux_perf.hpp" |
36 | #endif |
37 | #endif |
38 | |
39 | namespace dnnl { |
40 | namespace impl { |
41 | namespace cpu { |
42 | namespace jit_utils { |
43 | |
44 | // WARNING: These functions are not thread safe and must be protected by a |
45 | // mutex |
46 | |
47 | // TODO (rsdubtso): support prefix for code dumps |
48 | |
49 | void dump_jit_code(const void *code, size_t code_size, const char *code_name) { |
50 | #if DNNL_ENABLE_JIT_DUMP |
51 | if (code && get_jit_dump()) { |
52 | static int counter = 0; |
53 | #define MAX_FNAME_LEN 256 |
54 | char fname[MAX_FNAME_LEN + 1]; |
55 | // TODO (Roma): support prefix for code / linux perf dumps |
56 | snprintf(fname, MAX_FNAME_LEN, "dnnl_dump_cpu_%s.%d.bin" , code_name, |
57 | counter); |
58 | counter++; |
59 | |
60 | FILE *fp = fopen(fname, "wb+" ); |
61 | // Failure to dump code is not fatal |
62 | if (fp) { |
63 | size_t unused = fwrite(code, code_size, 1, fp); |
64 | UNUSED(unused); |
65 | fclose(fp); |
66 | } |
67 | } |
68 | #undef MAX_FNAME_LEN |
69 | #else |
70 | UNUSED(code); |
71 | UNUSED(code_size); |
72 | UNUSED(code_name); |
73 | #endif |
74 | } |
75 | |
76 | void register_jit_code_vtune(const void *code, size_t code_size, |
77 | const char *code_name, const char *source_file_name) { |
78 | #if DNNL_ENABLE_JIT_PROFILING |
79 | unsigned flags = get_jit_profiling_flags(); |
80 | #if DNNL_X64 |
81 | if ((flags & DNNL_JIT_PROFILE_VTUNE) |
82 | && iJIT_IsProfilingActive() == iJIT_SAMPLING_ON) { |
83 | auto jmethod = iJIT_Method_Load(); |
84 | jmethod.method_id = iJIT_GetNewMethodID(); // XXX: not thread-safe |
85 | jmethod.method_name = (char *)code_name; // XXX: dropping const |
86 | jmethod.class_file_name = nullptr; |
87 | jmethod.source_file_name |
88 | = (char *)source_file_name; // XXX: dropping const |
89 | jmethod.method_load_address = (void *)code; |
90 | jmethod.method_size = (unsigned int)code_size; |
91 | |
92 | iJIT_NotifyEvent( |
93 | iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void *)&jmethod); |
94 | } |
95 | #else |
96 | if (flags & DNNL_JIT_PROFILE_VTUNE) |
97 | fprintf(stderr, "VTune Amplifier integration is not supported.\n" ); |
98 | #endif |
99 | #else |
100 | UNUSED(code); |
101 | UNUSED(code_size); |
102 | UNUSED(code_name); |
103 | UNUSED(source_file_name); |
104 | #endif |
105 | } |
106 | |
107 | void register_jit_code_linux_perf(const void *code, size_t code_size, |
108 | const char *code_name, const char *source_file_name) { |
109 | #if DNNL_ENABLE_JIT_PROFILING && defined(__linux__) |
110 | unsigned flags = get_jit_profiling_flags(); |
111 | if (flags & DNNL_JIT_PROFILE_LINUX_JITDUMP) |
112 | linux_perf_jitdump_record_code_load(code, code_size, code_name); |
113 | if (flags & DNNL_JIT_PROFILE_LINUX_PERFMAP) |
114 | linux_perf_perfmap_record_code_load(code, code_size, code_name); |
115 | #else |
116 | UNUSED(code); |
117 | UNUSED(code_size); |
118 | UNUSED(code_name); |
119 | #endif |
120 | UNUSED(source_file_name); |
121 | } |
122 | |
123 | void register_jit_code(const void *code, size_t code_size, |
124 | const char *code_name, const char *source_file_name) { |
125 | // The #ifdef guards are required to avoid generating a function that only |
126 | // consists of lock and unlock code |
127 | #if DNNL_ENABLE_JIT_PROFILING || DNNL_ENABLE_JIT_DUMP |
128 | static std::mutex m; |
129 | std::lock_guard<std::mutex> guard(m); |
130 | |
131 | dump_jit_code(code, code_size, code_name); |
132 | register_jit_code_vtune(code, code_size, code_name, source_file_name); |
133 | register_jit_code_linux_perf(code, code_size, code_name, source_file_name); |
134 | #else |
135 | UNUSED(code); |
136 | UNUSED(code_size); |
137 | UNUSED(code_name); |
138 | UNUSED(source_file_name); |
139 | #endif |
140 | } |
141 | |
142 | } // namespace jit_utils |
143 | } // namespace cpu |
144 | } // namespace impl |
145 | } // namespace dnnl |
146 | |