1 /******************************************************************************
2 * Copyright (c) Intel Corporation - All rights reserved. *
3 * This file is part of the LIBXSMM library. *
4 * *
5 * For information on the license, see the LICENSE file. *
6 * Further information: https://github.com/hfp/libxsmm/ *
7 * SPDX-License-Identifier: BSD-3-Clause *
8 ******************************************************************************/
9 /* Maciej Debski (Google Inc.)
10 ******************************************************************************/
11 #include "libxsmm_perf.h"
12 #include <libxsmm_sync.h>
13
14 #if defined(LIBXSMM_OFFLOAD_TARGET)
15 # pragma offload_attribute(push,target(LIBXSMM_OFFLOAD_TARGET))
16 #endif
17 #include "perf_jitdump.h"
18 #if defined(LIBXSMM_PERF_JITDUMP) && !defined(_WIN32)
19 # include <sys/mman.h>
20 # include <sys/types.h>
21 # include <sys/types.h>
22 # include <sys/stat.h>
23 # include <fcntl.h>
24 # include <errno.h>
25 # include <time.h>
26 #endif
27 #if defined(__linux__)
28 # include <syscall.h>
29 #endif
30 #if defined(_WIN32)
31 # include <windows.h>
32 # define LIBXSMM_MAX_PATH MAX_PATH
33 #else
34 # if defined(__linux__)
35 # include <linux/limits.h>
36 # define LIBXSMM_MAX_PATH PATH_MAX
37 # elif defined(PATH_MAX)
38 # define LIBXSMM_MAX_PATH PATH_MAX
39 # else /* fallback */
40 # define LIBXSMM_MAX_PATH 1024
41 # endif
42 # include <unistd.h>
43 #endif
44 #if defined(LIBXSMM_OFFLOAD_TARGET)
45 # pragma offload_attribute(pop)
46 #endif
47
48 #if !defined(NDEBUG)
49 # define LIBXSMM_PERF_ERROR(msg) fprintf(stderr, msg)
50 #else
51 # define LIBXSMM_PERF_ERROR(msg)
52 #endif
53
54
55 LIBXSMM_APIVAR_DEFINE(FILE* internal_perf_fp);
56 #if defined(LIBXSMM_PERF_JITDUMP) && !defined(_WIN32)
57 LIBXSMM_APIVAR_DEFINE(void* internal_perf_marker);
58 LIBXSMM_APIVAR_DEFINE(int internal_perf_codeidx);
59 #endif
60
61
libxsmm_perf_init(void)62 LIBXSMM_API_INTERN void libxsmm_perf_init(void)
63 {
64 const uint32_t pid = (uint32_t)libxsmm_get_pid();
65 char file_name[LIBXSMM_MAX_PATH];
66 #if defined(LIBXSMM_PERF_JITDUMP) && !defined(_WIN32)
67 char file_path[LIBXSMM_MAX_PATH];
68 int fd, page_size, res;
69 struct jitdump_file_header header;
70 char * path_base;
71 char date[64];
72 time_t t = time(NULL);
73 struct tm tm = *localtime(&t);
74
75 /* initialize global variables */
76 JITDUMP_MAGIC = 'J' << 24 | 'i' << 16 | 'T' << 8 | 'D';
77 JITDUMP_MAGIC_SWAPPED = 'J' | 'i' << 8 | 'T' << 16 | 'D' << 24;
78 JITDUMP_VERSION = 1;
79 JITDUMP_FLAGS_ARCH_TIMESTAMP = 1ULL /*<< 0*/;
80 JITDUMP_CODE_LOAD = 0;
81 JITDUMP_CODE_MOVE = 1;
82 JITDUMP_CODE_DEBUG_INFO = 2;
83 JITDUMP_CODE_CLOSE = 3;
84
85 path_base = getenv("JITDUMPDIR");
86 if (path_base == NULL) {
87 path_base = getenv("HOME");
88 }
89 if (path_base == NULL) {
90 path_base = getenv(".");
91 }
92
93 LIBXSMM_SNPRINTF(file_path, sizeof(file_path), "%s/.debug/", path_base);
94 res = mkdir(file_path, S_IRWXU);
95 if (res < 0 && errno != EEXIST) {
96 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to create .debug dir\n");
97 goto error;
98 }
99
100 LIBXSMM_SNPRINTF(file_path, sizeof(file_path), "%s/.debug/jit", path_base);
101 res = mkdir(file_path, S_IRWXU);
102 if (res < 0 && errno != EEXIST) {
103 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to create .debug/jit dir\n");
104 goto error;
105 }
106
107 strftime(date, sizeof(date), "%Y%m%d", &tm);
108
109 LIBXSMM_SNPRINTF(file_path, sizeof(file_path),
110 "%s/.debug/jit/libxsmm-jit-%s.XXXXXX", path_base, date);
111 path_base = mkdtemp(file_path);
112 if (path_base == NULL) {
113 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to create temporary dir\n");
114 goto error;
115 }
116
117 LIBXSMM_SNPRINTF(file_name, sizeof(file_name), "%s/jit-%u.dump", path_base, pid);
118
119 fd = open(file_name, O_CREAT|O_TRUNC|O_RDWR, 0600);
120 if (fd < 0) {
121 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to open file\n");
122 goto error;
123 }
124
125 page_size = sysconf(_SC_PAGESIZE);
126 if (page_size < 0) {
127 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to get page size\n");
128 goto error;
129 }
130 internal_perf_marker = mmap(NULL, page_size, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
131 if (internal_perf_marker == MAP_FAILED) {
132 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: mmap failed.\n");
133 goto error;
134 }
135
136 /* initialize code index */
137 internal_perf_codeidx = 0;
138
139 internal_perf_fp = fdopen(fd, "wb+");
140 if (internal_perf_fp == NULL) {
141 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: fdopen failed.\n");
142 goto error;
143 }
144
145 LIBXSMM_MEMZERO127(&header);
146 header.magic = JITDUMP_MAGIC;
147 header.version = JITDUMP_VERSION;
148 header.elf_mach = 62; /* EM_X86_64 */
149 header.total_size = sizeof(header);
150 header.pid = pid;
151 header.timestamp = libxsmm_timer_tick();
152 header.flags = JITDUMP_FLAGS_ARCH_TIMESTAMP;
153
154 res = fwrite(&header, sizeof(header), 1, internal_perf_fp);
155 if (res != 1) {
156 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to write header.\n");
157 goto error;
158 }
159
160 #else
161 LIBXSMM_SNPRINTF(file_name, sizeof(file_name), "/tmp/perf-%u.map", pid);
162 internal_perf_fp = fopen(file_name, "w+");
163 if (internal_perf_fp == NULL) {
164 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to open map file\n");
165 goto error;
166 }
167 #endif
168
169 return;
170
171 error:
172 if (internal_perf_fp != NULL) {
173 fclose(internal_perf_fp);
174 internal_perf_fp = NULL;
175 }
176 assert(0);
177 }
178
179
libxsmm_perf_finalize(void)180 LIBXSMM_API_INTERN void libxsmm_perf_finalize(void)
181 {
182 #if defined(LIBXSMM_PERF_JITDUMP) && !defined(_WIN32)
183 int res, page_size;
184 struct jitdump_record_header hdr;
185
186 if (internal_perf_fp == NULL) {
187 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: jit dump file not opened\n");
188 goto error;
189 }
190
191 LIBXSMM_MEMZERO127(&hdr);
192 hdr.id = JITDUMP_CODE_CLOSE;
193 hdr.total_size = sizeof(hdr);
194 hdr.timestamp = libxsmm_timer_tick();
195 res = fwrite(&hdr, sizeof(hdr), 1, internal_perf_fp);
196
197 if (res != 1) {
198 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to write JIT_CODE_CLOSE record\n");
199 goto error;
200 }
201
202 page_size = sysconf(_SC_PAGESIZE);
203 if (page_size < 0) {
204 LIBXSMM_PERF_ERROR("LIBXSMM ERROR: failed to get page_size\n");
205 goto error;
206 }
207 munmap(internal_perf_marker, page_size);
208 fclose(internal_perf_fp);
209 return;
210
211 error:
212 assert(0);
213 #else
214 fclose(internal_perf_fp);
215 #endif
216 }
217
218
219 #if defined(LIBXSMM_PERF_JITDUMP) && !defined(_WIN32)
220 /** Utility function to receive the OS-specific thread ID. */
internal_perf_get_tid(void)221 LIBXSMM_API_INLINE unsigned int internal_perf_get_tid(void)
222 {
223 #if defined(__linux__)
224 return (unsigned int)syscall(__NR_gettid);
225 #else /* fallback */
226 return libxsmm_get_tid();
227 #endif
228 }
229 #endif
230
231
libxsmm_perf_dump_code(const void * memory,size_t size,const char * name)232 LIBXSMM_API_INTERN void libxsmm_perf_dump_code(const void* memory, size_t size, const char* name)
233 {
234 assert(internal_perf_fp != NULL);
235 assert(name && *name);
236 assert(memory != NULL && size != 0);
237 if (internal_perf_fp != NULL) {
238 #if defined(LIBXSMM_PERF_JITDUMP) && !defined(_WIN32)
239 int res;
240 struct jitdump_record_header hdr;
241 struct jitdump_record_code_load rec;
242 size_t name_len = strlen(name) + 1;
243
244 LIBXSMM_MEMZERO127(&hdr);
245 LIBXSMM_MEMZERO127(&rec);
246
247 hdr.id = JITDUMP_CODE_LOAD;
248 hdr.total_size = sizeof(hdr) + sizeof(rec) + name_len + size;
249 hdr.timestamp = libxsmm_timer_tick();
250
251 rec.code_size = size;
252 rec.vma = (uintptr_t) memory;
253 rec.code_addr = (uintptr_t) memory;
254 rec.pid = (uint32_t) libxsmm_get_pid();
255 rec.tid = (uint32_t) internal_perf_get_tid();
256
257 LIBXSMM_FLOCK(internal_perf_fp);
258
259 /* This will be unique as we hold the file lock. */
260 rec.internal_perf_codeidx = internal_perf_codeidx++;
261
262 /* Count number of written items to check for errors. */
263 res = 0;
264 res += fwrite_unlocked(&hdr, sizeof(hdr), 1, internal_perf_fp);
265 res += fwrite_unlocked(&rec, sizeof(rec), 1, internal_perf_fp);
266 res += fwrite_unlocked(name, name_len, 1, internal_perf_fp);
267 res += fwrite_unlocked((const void*) memory, size, 1, internal_perf_fp);
268
269 LIBXSMM_FUNLOCK(internal_perf_fp);
270 fflush(internal_perf_fp);
271
272 assert(res == 4); /* Expected 4 items written above */
273
274 #else
275 fprintf(internal_perf_fp, "%" PRIxPTR " %lx %s\n", (uintptr_t)memory, (unsigned long)size, name);
276 fflush(internal_perf_fp);
277 #endif
278 }
279 }
280
281