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